TypeOf should be fast
https://bugs.webkit.org/show_bug.cgi?id=144396
Reviewed by Geoffrey Garen.
Adds comprehensive support for fast typeof to the optimizing JITs. Calls into the runtime
are only used for very exotic objects - they must have either the MasqueradesAsUndefined or
TypeOfShouldCallGetCallData type flags set. All other cases are handled inline.
This means optimizing IsObjectOrNull, IsFunction, and TypeOf - all node types that used to
rely heavily on C++ calls to fulfill their function.
Because TypeOf is now so fast, we no longer need to do any speculations on this node.
In the FTL, we take this further by querying AI for each branch in the TypeOf decision tree.
This means that if the TypeOf is dominated by any type checks, we will automatically prune
out cases that are redundant.
This patch anticipates the addition of SwitchTypeOf or something like that. So, the TypeOf
code generation is designed to be reusable.
This is a speed-up on most typeof benchmarks. But, it is a slow-down on benchmarks that take
the exotic call trap hook. That hook is now in a deeper slow path than before.
* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize): TypeOf was pure all along, but we failed to realize this.
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGHeapLocation.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileIsObjectOrNull):
(JSC::DFG::SpeculativeJIT::compileIsFunction):
(JSC::DFG::SpeculativeJIT::compileTypeOf):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::blessedBooleanResult):
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileIsObjectOrNull):
(JSC::FTL::LowerDFGToLLVM::compileIsFunction):
(JSC::FTL::LowerDFGToLLVM::compileTypeOf):
(JSC::FTL::LowerDFGToLLVM::buildTypeOf): Reusable TypeOf building for the FTL.
(JSC::FTL::LowerDFGToLLVM::isExoticForTypeof):
* ftl/FTLSwitchCase.h:
(JSC::FTL::SwitchCase::SwitchCase):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::branchIfNotEqual):
(JSC::AssemblyHelpers::branchIfEqual):
(JSC::AssemblyHelpers::branchIfNumber):
(JSC::AssemblyHelpers::branchIfNotNumber):
(JSC::AssemblyHelpers::branchIfBoolean):
(JSC::AssemblyHelpers::branchIfNotBoolean):
(JSC::AssemblyHelpers::boxBooleanPayload):
(JSC::AssemblyHelpers::boxBoolean):
(JSC::AssemblyHelpers::emitTypeOf): Reusable TypeOf building for assembly JITs.
* jit/JITOperations.h:
* runtime/SmallStrings.h:
(JSC::SmallStrings::typeString):
* runtime/TypeofType.cpp: Added.
(WTF::printInternal):
* runtime/TypeofType.h: Added.
* tests/stress/type-of-functions-and-objects.js: Modified this test to give more comprehensive feedback.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@183724 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index d38579e..e87c38a 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -159,6 +159,7 @@
case ValueToInt32:
case GetExecutable:
case BottomValue:
+ case TypeOf:
def(PureValue(node));
return;
@@ -362,11 +363,6 @@
def(HeapLocation(IsFunctionLoc, MiscFields, node->child1()), node);
return;
- case TypeOf:
- read(MiscFields);
- def(HeapLocation(TypeOfLoc, MiscFields, node->child1()), node);
- return;
-
case GetById:
case GetByIdFlush:
case PutById:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 652cb6a..15dcd41 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -346,14 +346,6 @@
break;
}
- case TypeOf: {
- if (node->child1()->shouldSpeculateString())
- fixEdge<StringUse>(node->child1());
- else if (node->child1()->shouldSpeculateCell())
- fixEdge<CellUse>(node->child1());
- break;
- }
-
case CompareEqConstant: {
break;
}
@@ -1241,6 +1233,7 @@
case MovHint:
case ZombieHint:
case BottomValue:
+ case TypeOf:
break;
#else
default:
diff --git a/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp b/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
index db693d4..2ca344a 100644
--- a/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
+++ b/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
@@ -68,10 +68,6 @@
out.print("IsFunctionLoc");
return;
- case TypeOfLoc:
- out.print("TypeOfLoc");
- return;
-
case GetterLoc:
out.print("GetterLoc");
return;
diff --git a/Source/JavaScriptCore/dfg/DFGHeapLocation.h b/Source/JavaScriptCore/dfg/DFGHeapLocation.h
index f7c119b..ce27ef4 100644
--- a/Source/JavaScriptCore/dfg/DFGHeapLocation.h
+++ b/Source/JavaScriptCore/dfg/DFGHeapLocation.h
@@ -53,7 +53,6 @@
NamedPropertyLoc,
SetterLoc,
StructureLoc,
- TypeOfLoc,
TypedArrayByteOffsetLoc,
VarInjectionWatchpointLoc,
StackLoc,
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 64a4534..8bb2d8d 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -860,21 +860,84 @@
return result;
}
-size_t JIT_OPERATION operationIsObjectOrNull(ExecState* exec, EncodedJSValue value)
-{
- return jsIsObjectTypeOrNull(exec, JSValue::decode(value));
-}
-
-size_t JIT_OPERATION operationIsFunction(EncodedJSValue value)
-{
- return jsIsFunctionType(JSValue::decode(value));
-}
-
-JSCell* JIT_OPERATION operationTypeOf(ExecState* exec, JSCell* value)
+size_t JIT_OPERATION operationObjectIsObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
{
VM& vm = exec->vm();
NativeCallFrameTracer tracer(&vm, exec);
- return jsTypeStringForValue(exec, JSValue(value)).asCell();
+
+ ASSERT(jsDynamicCast<JSObject*>(object));
+
+ if (object->structure(vm)->masqueradesAsUndefined(globalObject))
+ return false;
+ if (object->type() == JSFunctionType)
+ return false;
+ if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
+ CallData callData;
+ if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
+ return false;
+ }
+
+ return true;
+}
+
+size_t JIT_OPERATION operationObjectIsFunction(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ ASSERT(jsDynamicCast<JSObject*>(object));
+
+ if (object->structure(vm)->masqueradesAsUndefined(globalObject))
+ return false;
+ if (object->type() == JSFunctionType)
+ return true;
+ if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
+ CallData callData;
+ if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
+ return true;
+ }
+
+ return false;
+}
+
+JSCell* JIT_OPERATION operationTypeOfObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ ASSERT(jsDynamicCast<JSObject*>(object));
+
+ if (object->structure(vm)->masqueradesAsUndefined(globalObject))
+ return vm.smallStrings.undefinedString();
+ if (object->type() == JSFunctionType)
+ return vm.smallStrings.functionString();
+ if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
+ CallData callData;
+ if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
+ return vm.smallStrings.functionString();
+ }
+
+ return vm.smallStrings.objectString();
+}
+
+int32_t JIT_OPERATION operationTypeOfObjectAsTypeofType(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ ASSERT(jsDynamicCast<JSObject*>(object));
+
+ if (object->structure(vm)->masqueradesAsUndefined(globalObject))
+ return static_cast<int32_t>(TypeofType::Undefined);
+ if (object->type() == JSFunctionType)
+ return static_cast<int32_t>(TypeofType::Function);
+ if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
+ CallData callData;
+ if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
+ return static_cast<int32_t>(TypeofType::Function);
+ }
+
+ return static_cast<int32_t>(TypeofType::Object);
}
char* JIT_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState* exec)
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 6b7441d..b966c8d 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -103,9 +103,10 @@
JSCell* JIT_OPERATION operationCreateClonedArgumentsDuringExit(ExecState*, InlineCallFrame*, JSFunction*, int32_t argumentCount);
JSCell* JIT_OPERATION operationCreateClonedArguments(ExecState*, Structure*, Register* argumentStart, int32_t length, JSFunction* callee);
double JIT_OPERATION operationFModOnInts(int32_t, int32_t) WTF_INTERNAL;
-size_t JIT_OPERATION operationIsObjectOrNull(ExecState*, EncodedJSValue) WTF_INTERNAL;
-size_t JIT_OPERATION operationIsFunction(EncodedJSValue) WTF_INTERNAL;
-JSCell* JIT_OPERATION operationTypeOf(ExecState*, JSCell*) WTF_INTERNAL;
+size_t JIT_OPERATION operationObjectIsObject(ExecState*, JSGlobalObject*, JSCell*) WTF_INTERNAL;
+size_t JIT_OPERATION operationObjectIsFunction(ExecState*, JSGlobalObject*, JSCell*) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationTypeOfObject(ExecState*, JSGlobalObject*, JSCell*) WTF_INTERNAL;
+int32_t JIT_OPERATION operationTypeOfObjectAsTypeofType(ExecState*, JSGlobalObject*, JSCell*) WTF_INTERNAL;
char* JIT_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState*) WTF_INTERNAL;
char* JIT_OPERATION operationAllocatePropertyStorage(ExecState*, size_t newSize) WTF_INTERNAL;
char* JIT_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState*, JSObject*) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 86e3d7c..e2a2369 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -4815,6 +4815,118 @@
return true;
}
+void SpeculativeJIT::compileIsObjectOrNull(Node* node)
+{
+ JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
+
+ JSValueOperand value(this, node->child1());
+ JSValueRegs valueRegs = value.jsValueRegs();
+
+ GPRTemporary result(this);
+ GPRReg resultGPR = result.gpr();
+
+ JITCompiler::Jump isCell = m_jit.branchIfCell(valueRegs);
+
+ JITCompiler::Jump isNull = m_jit.branchIfEqual(valueRegs, jsNull());
+ JITCompiler::Jump isNonNullNonCell = m_jit.jump();
+
+ isCell.link(&m_jit);
+ JITCompiler::Jump isFunction = m_jit.branchIfFunction(valueRegs.payloadGPR());
+ JITCompiler::Jump notObject = m_jit.branchIfNotObject(valueRegs.payloadGPR());
+
+ JITCompiler::Jump slowPath = m_jit.branchTest8(
+ JITCompiler::NonZero,
+ JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()),
+ TrustedImm32(MasqueradesAsUndefined | TypeOfShouldCallGetCallData));
+
+ isNull.link(&m_jit);
+ m_jit.move(TrustedImm32(1), resultGPR);
+ JITCompiler::Jump done = m_jit.jump();
+
+ isNonNullNonCell.link(&m_jit);
+ isFunction.link(&m_jit);
+ notObject.link(&m_jit);
+ m_jit.move(TrustedImm32(0), resultGPR);
+
+ addSlowPathGenerator(
+ slowPathCall(
+ slowPath, this, operationObjectIsObject, resultGPR, globalObject,
+ valueRegs.payloadGPR()));
+
+ done.link(&m_jit);
+
+ unblessedBooleanResult(resultGPR, node);
+}
+
+void SpeculativeJIT::compileIsFunction(Node* node)
+{
+ JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
+
+ JSValueOperand value(this, node->child1());
+ JSValueRegs valueRegs = value.jsValueRegs();
+
+ GPRTemporary result(this);
+ GPRReg resultGPR = result.gpr();
+
+ JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs);
+ JITCompiler::Jump isFunction = m_jit.branchIfFunction(valueRegs.payloadGPR());
+ JITCompiler::Jump notObject = m_jit.branchIfNotObject(valueRegs.payloadGPR());
+
+ JITCompiler::Jump slowPath = m_jit.branchTest8(
+ JITCompiler::NonZero,
+ JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()),
+ TrustedImm32(MasqueradesAsUndefined | TypeOfShouldCallGetCallData));
+
+ notCell.link(&m_jit);
+ notObject.link(&m_jit);
+ m_jit.move(TrustedImm32(0), resultGPR);
+ JITCompiler::Jump done = m_jit.jump();
+
+ isFunction.link(&m_jit);
+ m_jit.move(TrustedImm32(1), resultGPR);
+
+ addSlowPathGenerator(
+ slowPathCall(
+ slowPath, this, operationObjectIsFunction, resultGPR, globalObject,
+ valueRegs.payloadGPR()));
+
+ done.link(&m_jit);
+
+ unblessedBooleanResult(resultGPR, node);
+}
+
+void SpeculativeJIT::compileTypeOf(Node* node)
+{
+ JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
+
+ JSValueOperand value(this, node->child1());
+ JSValueRegs valueRegs = value.jsValueRegs();
+
+ GPRTemporary result(this);
+ GPRReg resultGPR = result.gpr();
+
+ JITCompiler::JumpList done;
+ JITCompiler::Jump slowPath;
+ m_jit.emitTypeOf(
+ valueRegs, resultGPR,
+ [&] (TypeofType type, bool fallsThrough) {
+ m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.typeString(type)), resultGPR);
+ if (!fallsThrough)
+ done.append(m_jit.jump());
+ },
+ [&] (JITCompiler::Jump theSlowPath) {
+ slowPath = theSlowPath;
+ });
+ done.link(&m_jit);
+
+ addSlowPathGenerator(
+ slowPathCall(
+ slowPath, this, operationTypeOfObject, resultGPR, globalObject,
+ valueRegs.payloadGPR()));
+
+ cellResult(resultGPR, node);
+}
+
void SpeculativeJIT::compileAllocatePropertyStorage(Node* node)
{
if (node->transition()->previous->couldHaveIndexingHeader()) {
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 9d72e89..67e673b 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -792,13 +792,7 @@
#if USE(JSVALUE64)
jsValueResult(reg, node, DataFormatJSBoolean, mode);
#else
- if (mode == CallUseChildren)
- useChildren(node);
-
- VirtualRegister virtualRegister = node->virtualRegister();
- m_gprs.retain(reg, virtualRegister, SpillOrderBoolean);
- GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
- info.initBoolean(node, node->refCount(), reg);
+ booleanResult(reg, node, mode);
#endif
}
void unblessedBooleanResult(GPRReg reg, Node* node, UseChildrenMode mode = CallUseChildren)
@@ -1060,6 +1054,18 @@
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(S_JITOperation_EGC operation, GPRReg result, JSGlobalObject* globalObject, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(globalObject), arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
+
+ JITCompiler::Call callOperation(C_JITOperation_EGC operation, GPRReg result, JSGlobalObject* globalObject, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(globalObject), arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
+
JITCompiler::Call callOperation(Jss_JITOperation_EZ operation, GPRReg result, GPRReg arg1)
{
m_jit.setupArgumentsWithExecState(arg1);
@@ -2214,6 +2220,9 @@
void compileCreateClonedArguments(Node*);
void compileNotifyWrite(Node*);
bool compileRegExpExec(Node*);
+ void compileIsObjectOrNull(Node*);
+ void compileIsFunction(Node*);
+ void compileTypeOf(Node*);
void moveTrueTo(GPRReg);
void moveFalseTo(GPRReg);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index fd9f350..f9ca771 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -4107,86 +4107,16 @@
}
case IsObjectOrNull: {
- JSValueOperand value(this, node->child1());
- GPRReg valueTagGPR = value.tagGPR();
- GPRReg valuePayloadGPR = value.payloadGPR();
- GPRFlushedCallResult result(this);
- GPRReg resultGPR = result.gpr();
- flushRegisters();
- callOperation(operationIsObjectOrNull, resultGPR, valueTagGPR, valuePayloadGPR);
- booleanResult(result.gpr(), node);
+ compileIsObjectOrNull(node);
break;
}
case IsFunction: {
- JSValueOperand value(this, node->child1());
- GPRReg valueTagGPR = value.tagGPR();
- GPRReg valuePayloadGPR = value.payloadGPR();
- GPRFlushedCallResult result(this);
- GPRReg resultGPR = result.gpr();
- flushRegisters();
- callOperation(operationIsFunction, resultGPR, valueTagGPR, valuePayloadGPR);
- booleanResult(result.gpr(), node);
+ compileIsFunction(node);
break;
}
case TypeOf: {
- JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
- GPRReg tagGPR = value.tagGPR();
- GPRReg payloadGPR = value.payloadGPR();
- GPRTemporary temp(this);
- GPRReg tempGPR = temp.gpr();
- GPRFlushedCallResult result(this);
- GPRReg resultGPR = result.gpr();
- JITCompiler::JumpList doneJumps;
-
- flushRegisters();
-
- ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == CellUse || node->child1().useKind() == StringUse);
-
- JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(value.jsValueRegs());
- if (node->child1().useKind() != UntypedUse)
- DFG_TYPE_CHECK(JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecCell, isNotCell);
-
- if (!node->child1()->shouldSpeculateObject() || node->child1().useKind() == StringUse) {
- JITCompiler::Jump notString = m_jit.branchIfNotString(payloadGPR);
- if (node->child1().useKind() == StringUse)
- DFG_TYPE_CHECK(JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecString, notString);
- m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.stringString()), resultGPR);
- doneJumps.append(m_jit.jump());
- if (node->child1().useKind() != StringUse) {
- notString.link(&m_jit);
- callOperation(operationTypeOf, resultGPR, payloadGPR);
- doneJumps.append(m_jit.jump());
- }
- } else {
- callOperation(operationTypeOf, resultGPR, payloadGPR);
- doneJumps.append(m_jit.jump());
- }
-
- if (node->child1().useKind() == UntypedUse) {
- 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.vm()->smallStrings.numberString()), 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.vm()->smallStrings.undefinedString()), 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.vm()->smallStrings.objectString()), resultGPR);
- doneJumps.append(m_jit.jump());
- notNull.link(&m_jit);
-
- // Only boolean left
- m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.booleanString()), resultGPR);
- }
- doneJumps.link(&m_jit);
- cellResult(resultGPR, node);
+ compileTypeOf(node);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 1d0857f..35c41e4 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -4148,82 +4148,17 @@
}
case IsObjectOrNull: {
- JSValueOperand value(this, node->child1());
- GPRReg valueGPR = value.gpr();
- GPRFlushedCallResult result(this);
- GPRReg resultGPR = result.gpr();
- flushRegisters();
- callOperation(operationIsObjectOrNull, resultGPR, valueGPR);
- m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
- jsValueResult(result.gpr(), node, DataFormatJSBoolean);
+ compileIsObjectOrNull(node);
break;
}
case IsFunction: {
- JSValueOperand value(this, node->child1());
- GPRReg valueGPR = value.gpr();
- GPRFlushedCallResult result(this);
- GPRReg resultGPR = result.gpr();
- flushRegisters();
- callOperation(operationIsFunction, resultGPR, valueGPR);
- m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
- jsValueResult(result.gpr(), node, DataFormatJSBoolean);
+ compileIsFunction(node);
break;
}
case TypeOf: {
- JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
- GPRReg valueGPR = value.gpr();
- GPRFlushedCallResult result(this);
- GPRReg resultGPR = result.gpr();
- JITCompiler::JumpList doneJumps;
-
- flushRegisters();
-
- ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == CellUse || node->child1().useKind() == StringUse);
-
- JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(JSValueRegs(valueGPR));
- if (node->child1().useKind() != UntypedUse)
- DFG_TYPE_CHECK(JSValueSource(valueGPR), node->child1(), SpecCell, isNotCell);
-
- if (!node->child1()->shouldSpeculateObject() || node->child1().useKind() == StringUse) {
- JITCompiler::Jump notString = m_jit.branchIfNotString(valueGPR);
- if (node->child1().useKind() == StringUse)
- DFG_TYPE_CHECK(JSValueSource(valueGPR), node->child1(), SpecString, notString);
- m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.stringString()), resultGPR);
- doneJumps.append(m_jit.jump());
- if (node->child1().useKind() != StringUse) {
- notString.link(&m_jit);
- callOperation(operationTypeOf, resultGPR, valueGPR);
- doneJumps.append(m_jit.jump());
- }
- } else {
- callOperation(operationTypeOf, resultGPR, valueGPR);
- doneJumps.append(m_jit.jump());
- }
-
- if (node->child1().useKind() == UntypedUse) {
- isNotCell.link(&m_jit);
- JITCompiler::Jump notNumber = m_jit.branchTest64(JITCompiler::Zero, valueGPR, GPRInfo::tagTypeNumberRegister);
- m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.numberString()), 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.vm()->smallStrings.undefinedString()), 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.vm()->smallStrings.objectString()), resultGPR);
- doneJumps.append(m_jit.jump());
- notNull.link(&m_jit);
-
- // Only boolean left
- m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.booleanString()), resultGPR);
- }
- doneJumps.link(&m_jit);
- cellResult(resultGPR, node);
+ compileTypeOf(node);
break;
}