Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (137682 => 137683)
--- trunk/Source/_javascript_Core/ChangeLog 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-12-14 00:32:55 UTC (rev 137683)
@@ -1,3 +1,46 @@
+2012-13-11 Oliver Hunt <[email protected]>
+
+ Support op_typeof in the DFG
+ https://bugs.webkit.org/show_bug.cgi?id=98898
+
+ Reviewed by Filip Pizlo.
+
+ Adds a TypeOf node to the DFG to support op_typeof.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ We try to determine the result early here, and substitute in a constant.
+ Otherwise we leave the node intact, and set the result type to SpecString.
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ Parse op_typeof
+ * dfg/DFGCSEPhase.cpp:
+ (JSC::DFG::CSEPhase::performNodeCSE):
+ TypeOf nodes can be subjected to pure CSE
+ * dfg/DFGCapabilities.h:
+ (JSC::DFG::canCompileOpcode):
+ We can handle typeof.
+ * dfg/DFGNodeType.h:
+ (DFG):
+ Define the node.
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ Add operationTypeOf to support the non-trivial cases.
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ Actual codegen
+ * runtime/Operations.cpp:
+ (JSC::jsTypeStringForValue):
+ (JSC):
+ * runtime/Operations.h:
+ (JSC):
+ Some refactoring to allow us to get the type string for an
+ object without needing a callframe.
+
2012-12-12 Filip Pizlo <[email protected]>
OSR exit compiler should emit code for resetting the execution counter that matches the logic of ExecutionCounter.cpp
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (137682 => 137683)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-12-14 00:32:55 UTC (rev 137683)
@@ -31,6 +31,7 @@
#include "CodeBlock.h"
#include "DFGBasicBlock.h"
#include "GetByIdStatus.h"
+#include "Operations.h"
#include "PutByIdStatus.h"
namespace JSC { namespace DFG {
@@ -707,6 +708,11 @@
case IsString:
constantWasSet = trySetConstant(nodeIndex, jsBoolean(isJSString(child)));
break;
+ case IsObject:
+ if (child.isNull() || !child.isObject()) {
+ constantWasSet = trySetConstant(nodeIndex, jsBoolean(child.isNull()));
+ break;
+ }
default:
constantWasSet = false;
break;
@@ -716,9 +722,64 @@
break;
}
}
+
forNode(nodeIndex).set(SpecBoolean);
break;
}
+
+ case TypeOf: {
+ JSGlobalData* globalData = m_codeBlock->globalData();
+ JSValue child = forNode(node.child1()).value();
+ AbstractValue& abstractChild = forNode(node.child1());
+ if (child) {
+ JSValue typeString = jsTypeStringForValue(*globalData, m_codeBlock->globalObjectFor(node.codeOrigin), child);
+ if (trySetConstant(nodeIndex, typeString)) {
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isNumberSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(nodeIndex, globalData->smallStrings.numberString(globalData))) {
+ forNode(node.child1()).filter(SpecNumber);
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isStringSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(nodeIndex, globalData->smallStrings.stringString(globalData))) {
+ forNode(node.child1()).filter(SpecString);
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isFinalObjectSpeculation(abstractChild.m_type) || isArraySpeculation(abstractChild.m_type) || isArgumentsSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(nodeIndex, globalData->smallStrings.objectString(globalData))) {
+ forNode(node.child1()).filter(SpecFinalObject | SpecArray | SpecArguments);
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isFunctionSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(nodeIndex, globalData->smallStrings.functionString(globalData))) {
+ forNode(node.child1()).filter(SpecFunction);
+ m_foundConstants = true;
+ break;
+ }
+ } else if (isBooleanSpeculation(abstractChild.m_type)) {
+ if (trySetConstant(nodeIndex, globalData->smallStrings.booleanString(globalData))) {
+ forNode(node.child1()).filter(SpecBoolean);
+ m_foundConstants = true;
+ break;
+ }
+ } else {
+ Node& childNode = m_graph[node.child1()];
+ if (isCellSpeculation(childNode.prediction())) {
+ if (isStringSpeculation(childNode.prediction()))
+ forNode(node.child1()).filter(SpecString);
+ else
+ forNode(node.child1()).filter(SpecCell);
+ node.setCanExit(true);
+ }
+ }
+ forNode(nodeIndex).set(SpecString);
+ break;
+ }
case CompareLess:
case CompareLessEq:
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (137682 => 137683)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2012-12-14 00:32:55 UTC (rev 137683)
@@ -3255,6 +3255,12 @@
NEXT_OPCODE(op_new_func_exp);
}
+ case op_typeof: {
+ set(currentInstruction[1].u.operand,
+ addToGraph(TypeOf, get(currentInstruction[2].u.operand)));
+ NEXT_OPCODE(op_typeof);
+ }
+
default:
// Parse failed! This should not happen because the capabilities checker
// should have caught it.
Modified: trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp (137682 => 137683)
--- trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2012-12-14 00:32:55 UTC (rev 137683)
@@ -562,6 +562,7 @@
case CreateThis:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
+ case TypeOf:
return NoNode;
case GetIndexedPropertyStorage:
@@ -1127,6 +1128,7 @@
case SkipTopScope:
case SkipScope:
case GetScopeRegisters:
+ case TypeOf:
setReplacement(pureCSE(node));
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.h (137682 => 137683)
--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.h 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.h 2012-12-14 00:32:55 UTC (rev 137683)
@@ -196,6 +196,7 @@
case op_jneq_ptr:
case op_put_to_base_variable:
case op_put_to_base:
+ case op_typeof:
return CanCompile;
case op_call_varargs:
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (137682 => 137683)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2012-12-14 00:32:55 UTC (rev 137683)
@@ -210,6 +210,7 @@
macro(IsString, NodeResultBoolean) \
macro(IsObject, NodeResultBoolean) \
macro(IsFunction, NodeResultBoolean) \
+ macro(TypeOf, NodeResultJS) \
macro(LogicalNot, NodeResultBoolean) \
macro(ToPrimitive, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
macro(StrCat, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (137682 => 137683)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2012-12-14 00:32:55 UTC (rev 137683)
@@ -1370,6 +1370,11 @@
return jsIsFunctionType(JSValue::decode(value));
}
+JSCell* DFG_OPERATION operationTypeOf(ExecState* exec, JSCell* value)
+{
+ return jsTypeStringForValue(exec, JSValue(value)).asCell();
+}
+
void DFG_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObject* base, Structure* structure, PropertyOffset offset, EncodedJSValue value)
{
JSGlobalData& globalData = exec->globalData();
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (137682 => 137683)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2012-12-14 00:32:55 UTC (rev 137683)
@@ -198,6 +198,7 @@
double DFG_OPERATION operationFModOnInts(int32_t, int32_t) WTF_INTERNAL;
size_t DFG_OPERATION operationIsObject(ExecState*, EncodedJSValue) WTF_INTERNAL;
size_t DFG_OPERATION operationIsFunction(EncodedJSValue) WTF_INTERNAL;
+JSCell* DFG_OPERATION operationTypeOf(ExecState*, JSCell*) WTF_INTERNAL;
void DFG_OPERATION operationReallocateStorageAndFinishPut(ExecState*, JSObject*, Structure*, PropertyOffset, EncodedJSValue) WTF_INTERNAL;
char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState*) WTF_INTERNAL;
char* DFG_OPERATION operationAllocatePropertyStorage(ExecState*, size_t newSize) WTF_INTERNAL;
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (137682 => 137683)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2012-12-14 00:32:55 UTC (rev 137683)
@@ -497,7 +497,13 @@
changed |= mergeDefaultFlags(node);
break;
}
-
+
+ case TypeOf: {
+ changed |= setPrediction(SpecString);
+ changed |= mergeDefaultFlags(node);
+ break;
+ }
+
case GetById: {
changed |= mergePrediction(node.getHeapPrediction());
changed |= mergeDefaultFlags(node);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (137682 => 137683)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2012-12-14 00:32:55 UTC (rev 137683)
@@ -4558,7 +4558,67 @@
booleanResult(result.gpr(), m_compileIndex);
break;
}
+ case TypeOf: {
+ JSValueOperand value(this, node.child1());
+ GPRReg tagGPR = value.tagGPR();
+ GPRReg payloadGPR = value.payloadGPR();
+ GPRTemporary temp(this);
+ GPRReg tempGPR = temp.gpr();
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+ JITCompiler::JumpList doneJumps;
+ flushRegisters();
+
+ JITCompiler::Jump isNotCell = m_jit.branch32(JITCompiler::NotEqual, tagGPR, JITCompiler::TrustedImm32(JSValue::CellTag));
+ Node& child = m_jit.graph()[node.child1()];
+ if (child.shouldSpeculateCell())
+ speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node.child1(), isNotCell);
+
+ if (!child.shouldSpeculateNonStringCell()) {
+ m_jit.loadPtr(JITCompiler::Address(payloadGPR, JSCell::structureOffset()), tempGPR);
+ JITCompiler::Jump notString = m_jit.branch8(JITCompiler::NotEqual, JITCompiler::Address(tempGPR, Structure::typeInfoTypeOffset()), TrustedImm32(StringType));
+ if (child.shouldSpeculateString())
+ speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node.child1(), notString);
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.stringString(m_jit.globalData())), resultGPR);
+ doneJumps.append(m_jit.jump());
+ if (!child.shouldSpeculateString()) {
+ notString.link(&m_jit);
+ callOperation(operationTypeOf, resultGPR, payloadGPR);
+ doneJumps.append(m_jit.jump());
+ }
+ } else {
+ callOperation(operationTypeOf, resultGPR, payloadGPR);
+ doneJumps.append(m_jit.jump());
+ }
+
+ if (!child.shouldSpeculateCell()) {
+ isNotCell.link(&m_jit);
+
+ m_jit.add32(TrustedImm32(1), tagGPR, tempGPR);
+ JITCompiler::Jump notNumber = m_jit.branch32(JITCompiler::AboveOrEqual, tempGPR, JITCompiler::TrustedImm32(JSValue::LowestTag + 1));
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.numberString(m_jit.globalData())), resultGPR);
+ doneJumps.append(m_jit.jump());
+ notNumber.link(&m_jit);
+
+ JITCompiler::Jump notUndefined = m_jit.branch32(JITCompiler::NotEqual, tagGPR, TrustedImm32(JSValue::UndefinedTag));
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.undefinedString(m_jit.globalData())), resultGPR);
+ doneJumps.append(m_jit.jump());
+ notUndefined.link(&m_jit);
+
+ JITCompiler::Jump notNull = m_jit.branch32(JITCompiler::NotEqual, tagGPR, TrustedImm32(JSValue::NullTag));
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.objectString(m_jit.globalData())), resultGPR);
+ doneJumps.append(m_jit.jump());
+ notNull.link(&m_jit);
+
+ // Only boolean left
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.booleanString(m_jit.globalData())), resultGPR);
+ }
+ doneJumps.link(&m_jit);
+ cellResult(resultGPR, m_compileIndex);
+ break;
+ }
+
case Phi:
case Flush:
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (137682 => 137683)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2012-12-14 00:32:55 UTC (rev 137683)
@@ -4069,7 +4069,7 @@
cachedGetById(node.codeOrigin, baseGPR, resultGPR, node.identifierNumber(), notCell, DontSpill);
jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
-
+
break;
}
@@ -4484,6 +4484,64 @@
break;
}
+ case TypeOf: {
+ JSValueOperand value(this, node.child1());
+ GPRReg valueGPR = value.gpr();
+ GPRTemporary temp(this);
+ GPRReg tempGPR = temp.gpr();
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
+ JITCompiler::JumpList doneJumps;
+
+ flushRegisters();
+
+ JITCompiler::Jump isNotCell = m_jit.branchTest64(JITCompiler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
+ Node& child = m_jit.graph()[node.child1()];
+ if (child.shouldSpeculateCell())
+ speculationCheck(BadType, JSValueSource(valueGPR), node.child1(), isNotCell);
+
+ if (!child.shouldSpeculateNonStringCell()) {
+ m_jit.loadPtr(JITCompiler::Address(valueGPR, JSCell::structureOffset()), tempGPR);
+ JITCompiler::Jump notString = m_jit.branch8(JITCompiler::NotEqual, JITCompiler::Address(tempGPR, Structure::typeInfoTypeOffset()), TrustedImm32(StringType));
+ if (child.shouldSpeculateString())
+ speculationCheck(BadType, JSValueSource(valueGPR), node.child1(), notString);
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.stringString(m_jit.globalData())), resultGPR);
+ doneJumps.append(m_jit.jump());
+ if (!child.shouldSpeculateString()) {
+ notString.link(&m_jit);
+ callOperation(operationTypeOf, resultGPR, valueGPR);
+ doneJumps.append(m_jit.jump());
+ }
+ } else {
+ callOperation(operationTypeOf, resultGPR, valueGPR);
+ doneJumps.append(m_jit.jump());
+ }
+
+ if (!child.shouldSpeculateCell()) {
+ isNotCell.link(&m_jit);
+ JITCompiler::Jump notNumber = m_jit.branchTest64(JITCompiler::Zero, valueGPR, GPRInfo::tagTypeNumberRegister);
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.numberString(m_jit.globalData())), resultGPR);
+ doneJumps.append(m_jit.jump());
+ notNumber.link(&m_jit);
+
+ JITCompiler::Jump notUndefined = m_jit.branch64(JITCompiler::NotEqual, valueGPR, JITCompiler::TrustedImm64(ValueUndefined));
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.undefinedString(m_jit.globalData())), resultGPR);
+ doneJumps.append(m_jit.jump());
+ notUndefined.link(&m_jit);
+
+ JITCompiler::Jump notNull = m_jit.branch64(JITCompiler::NotEqual, valueGPR, JITCompiler::TrustedImm64(ValueNull));
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.objectString(m_jit.globalData())), resultGPR);
+ doneJumps.append(m_jit.jump());
+ notNull.link(&m_jit);
+
+ // Only boolean left
+ m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.booleanString(m_jit.globalData())), resultGPR);
+ }
+ doneJumps.link(&m_jit);
+ cellResult(resultGPR, m_compileIndex);
+ break;
+ }
+
case Flush:
case Phi:
break;
Modified: trunk/Source/_javascript_Core/runtime/Operations.cpp (137682 => 137683)
--- trunk/Source/_javascript_Core/runtime/Operations.cpp 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/runtime/Operations.cpp 2012-12-14 00:32:55 UTC (rev 137683)
@@ -56,9 +56,8 @@
return jsNumber(p1.toNumber(callFrame) + p2.toNumber(callFrame));
}
-JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v)
+JSValue jsTypeStringForValue(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue v)
{
- JSGlobalData& globalData = callFrame->globalData();
if (v.isUndefined())
return globalData.smallStrings.undefinedString(&globalData);
if (v.isBoolean())
@@ -70,7 +69,7 @@
if (v.isObject()) {
// Return "undefined" for objects that should be treated
// as null when doing comparisons.
- if (asObject(v)->structure()->masqueradesAsUndefined(callFrame->lexicalGlobalObject()))
+ if (asObject(v)->structure()->masqueradesAsUndefined(globalObject))
return globalData.smallStrings.undefinedString(&globalData);
CallData callData;
JSObject* object = asObject(v);
@@ -80,6 +79,11 @@
return globalData.smallStrings.objectString(&globalData);
}
+JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v)
+{
+ return jsTypeStringForValue(callFrame->globalData(), callFrame->lexicalGlobalObject(), v);
+}
+
bool jsIsObjectType(CallFrame* callFrame, JSValue v)
{
if (!v.isCell())
Modified: trunk/Source/_javascript_Core/runtime/Operations.h (137682 => 137683)
--- trunk/Source/_javascript_Core/runtime/Operations.h 2012-12-14 00:30:25 UTC (rev 137682)
+++ trunk/Source/_javascript_Core/runtime/Operations.h 2012-12-14 00:32:55 UTC (rev 137683)
@@ -32,6 +32,7 @@
NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue);
JSValue jsTypeStringForValue(CallFrame*, JSValue);
+ JSValue jsTypeStringForValue(JSGlobalData&, JSGlobalObject*, JSValue);
bool jsIsObjectType(CallFrame*, JSValue);
bool jsIsFunctionType(JSValue);