Diff
Modified: trunk/Source/_javascript_Core/CMakeLists.txt (183723 => 183724)
--- trunk/Source/_javascript_Core/CMakeLists.txt 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/CMakeLists.txt 2015-05-03 00:15:27 UTC (rev 183724)
@@ -581,6 +581,7 @@
runtime/TypeSet.cpp
runtime/TypedArrayController.cpp
runtime/TypedArrayType.cpp
+ runtime/TypeofType.cpp
runtime/VM.cpp
runtime/VMEntryScope.cpp
runtime/VarOffset.cpp
Modified: trunk/Source/_javascript_Core/ChangeLog (183723 => 183724)
--- trunk/Source/_javascript_Core/ChangeLog 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-05-03 00:15:27 UTC (rev 183724)
@@ -1,3 +1,82 @@
+2015-05-01 Filip Pizlo <[email protected]>
+
+ 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:
+ * _javascript_Core.vcxproj/_javascript_Core.vcxproj:
+ * _javascript_Core.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.
+
2015-05-02 Filip Pizlo <[email protected]>
Unreviewed, add a FIXME referencing https://bugs.webkit.org/show_bug.cgi?id=144527.
Modified: trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj (183723 => 183724)
--- trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/_javascript_Core.vcxproj/_javascript_Core.vcxproj 2015-05-03 00:15:27 UTC (rev 183724)
@@ -841,6 +841,7 @@
<ClCompile Include="..\runtime\TestRunnerUtils.cpp" />
<ClCompile Include="..\runtime\TypedArrayController.cpp" />
<ClCompile Include="..\runtime\TypedArrayType.cpp" />
+ <ClCompile Include="..\runtime\TypeofType.cpp" />
<ClCompile Include="..\runtime\TypeLocationCache.cpp" />
<ClCompile Include="..\runtime\TypeProfiler.cpp" />
<ClCompile Include="..\runtime\TypeProfilerLog.cpp" />
@@ -1688,6 +1689,7 @@
<ClInclude Include="..\runtime\TypedArrayController.h" />
<ClInclude Include="..\runtime\TypedArrayInlines.h" />
<ClInclude Include="..\runtime\TypedArrayType.h" />
+ <ClInclude Include="..\runtime\TypeofType.h" />
<ClInclude Include="..\runtime\TypeLocationCache.h" />
<ClInclude Include="..\runtime\TypeProfiler.h" />
<ClInclude Include="..\runtime\TypeProfilerLog.h" />
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (183723 => 183724)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2015-05-03 00:15:27 UTC (rev 183724)
@@ -726,6 +726,8 @@
0FF922D414F46B410041A24E /* LLIntOffsetsExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F4680A114BA7F8200BFE272 /* LLIntOffsetsExtractor.cpp */; };
0FFA549716B8835000B3A982 /* A64DOpcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 652A3A221651C69700A80AFE /* A64DOpcode.cpp */; };
0FFA549816B8835300B3A982 /* A64DOpcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 652A3A231651C69700A80AFE /* A64DOpcode.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0FFB6C381AF48DDC00DB1BF7 /* TypeofType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFB6C361AF48DDC00DB1BF7 /* TypeofType.cpp */; };
+ 0FFB6C391AF48DDC00DB1BF7 /* TypeofType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFB6C371AF48DDC00DB1BF7 /* TypeofType.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FFB921816D02EB20055A5DB /* DFGAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB4B51916B62772003F696B /* DFGAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FFB921A16D02EC50055A5DB /* DFGBasicBlockInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD5652216AB780A00197653 /* DFGBasicBlockInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FFB921B16D02F010055A5DB /* DFGNodeAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB4B51F16B62772003F696B /* DFGNodeAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -2462,6 +2464,8 @@
0FF8BDE81AD4CF7100DFE884 /* InferredValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InferredValue.cpp; sourceTree = "<group>"; };
0FF8BDE91AD4CF7100DFE884 /* InferredValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InferredValue.h; sourceTree = "<group>"; };
0FF922CF14F46B130041A24E /* JSCLLIntOffsetsExtractor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = JSCLLIntOffsetsExtractor; sourceTree = BUILT_PRODUCTS_DIR; };
+ 0FFB6C361AF48DDC00DB1BF7 /* TypeofType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TypeofType.cpp; sourceTree = "<group>"; };
+ 0FFB6C371AF48DDC00DB1BF7 /* TypeofType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeofType.h; sourceTree = "<group>"; };
0FFC99D0184EC8AD009C10AB /* ConstantMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstantMode.h; sourceTree = "<group>"; };
0FFC99D2184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayBufferNeuteringWatchpoint.cpp; sourceTree = "<group>"; };
0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayBufferNeuteringWatchpoint.h; sourceTree = "<group>"; };
@@ -4451,9 +4455,9 @@
BC9BB95B0E19680600DF8855 /* InternalFunction.cpp */,
BC11667A0E199C05008066DD /* InternalFunction.h */,
86BF642A148DB2B5004DE36A /* Intrinsic.h */,
+ FE4D55B71AE716CA0052E459 /* IterationStatus.h */,
70113D491A8DB093003848C4 /* IteratorOperations.cpp */,
70113D4A1A8DB093003848C4 /* IteratorOperations.h */,
- FE4D55B71AE716CA0052E459 /* IterationStatus.h */,
93ADFCE60CCBD7AC00D30B08 /* JSArray.cpp */,
938772E5038BFE19008635CE /* JSArray.h */,
0F2B66B417B6B5AB00A7AE3F /* JSArrayBuffer.cpp */,
@@ -4739,6 +4743,8 @@
0F2B66DD17B6B5AB00A7AE3F /* TypedArrayType.h */,
52B310FE1975B4240080857C /* TypeLocationCache.cpp */,
52B311001975B4670080857C /* TypeLocationCache.h */,
+ 0FFB6C361AF48DDC00DB1BF7 /* TypeofType.cpp */,
+ 0FFB6C371AF48DDC00DB1BF7 /* TypeofType.h */,
52C952B819A28A1C0069B386 /* TypeProfiler.cpp */,
52C952B619A289850069B386 /* TypeProfiler.h */,
0F2D4DDF19832D91007D4B19 /* TypeProfilerLog.cpp */,
@@ -5711,6 +5717,7 @@
BC18C3F40E16F5CD00B34460 /* Completion.h in Headers */,
0FDB2CEA174896C7007B3C1B /* ConcurrentJITLock.h in Headers */,
BC18C3F50E16F5CD00B34460 /* config.h in Headers */,
+ 0FFB6C391AF48DDC00DB1BF7 /* TypeofType.h in Headers */,
144836E7132DA7BE005BE785 /* ConservativeRoots.h in Headers */,
A5FD007A189B051000633231 /* ConsoleMessage.h in Headers */,
A5FD0074189B038C00633231 /* ConsoleTypes.h in Headers */,
@@ -7361,6 +7368,7 @@
147F39D4107EC37600427A48 /* JSObject.cpp in Sources */,
1482B7E40A43076000517CFC /* JSObjectRef.cpp in Sources */,
A7F993600FD7325100A0B2D0 /* JSONObject.cpp in Sources */,
+ 0FFB6C381AF48DDC00DB1BF7 /* TypeofType.cpp in Sources */,
95F6E6950E5B5F970091E860 /* JSProfilerPrivate.cpp in Sources */,
7C184E1A17BEDBD3007CB63A /* JSPromise.cpp in Sources */,
7C184E2217BEE240007CB63A /* JSPromiseConstructor.cpp in Sources */,
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (183723 => 183724)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2015-05-03 00:15:27 UTC (rev 183724)
@@ -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:
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (183723 => 183724)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2015-05-03 00:15:27 UTC (rev 183724)
@@ -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:
Modified: trunk/Source/_javascript_Core/dfg/DFGHeapLocation.cpp (183723 => 183724)
--- trunk/Source/_javascript_Core/dfg/DFGHeapLocation.cpp 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/dfg/DFGHeapLocation.cpp 2015-05-03 00:15:27 UTC (rev 183724)
@@ -68,10 +68,6 @@
out.print("IsFunctionLoc");
return;
- case TypeOfLoc:
- out.print("TypeOfLoc");
- return;
-
case GetterLoc:
out.print("GetterLoc");
return;
Modified: trunk/Source/_javascript_Core/dfg/DFGHeapLocation.h (183723 => 183724)
--- trunk/Source/_javascript_Core/dfg/DFGHeapLocation.h 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/dfg/DFGHeapLocation.h 2015-05-03 00:15:27 UTC (rev 183724)
@@ -53,7 +53,6 @@
NamedPropertyLoc,
SetterLoc,
StructureLoc,
- TypeOfLoc,
TypedArrayByteOffsetLoc,
VarInjectionWatchpointLoc,
StackLoc,
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (183723 => 183724)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2015-05-03 00:15:27 UTC (rev 183724)
@@ -860,23 +860,86 @@
return result;
}
-size_t JIT_OPERATION operationIsObjectOrNull(ExecState* exec, EncodedJSValue value)
+size_t JIT_OPERATION operationObjectIsObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
{
- return jsIsObjectTypeOrNull(exec, JSValue::decode(value));
+ 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 false;
+ if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
+ CallData callData;
+ if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
+ return false;
+ }
+
+ return true;
}
-size_t JIT_OPERATION operationIsFunction(EncodedJSValue value)
+size_t JIT_OPERATION operationObjectIsFunction(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
{
- return jsIsFunctionType(JSValue::decode(value));
+ 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 operationTypeOf(ExecState* exec, JSCell* value)
+JSCell* JIT_OPERATION operationTypeOfObject(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 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)
{
VM& vm = exec->vm();
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (183723 => 183724)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2015-05-03 00:15:27 UTC (rev 183724)
@@ -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;
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (183723 => 183724)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2015-05-03 00:15:27 UTC (rev 183724)
@@ -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()) {
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (183723 => 183724)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2015-05-03 00:15:27 UTC (rev 183724)
@@ -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);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (183723 => 183724)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2015-05-03 00:15:27 UTC (rev 183724)
@@ -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;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (183723 => 183724)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2015-05-03 00:15:27 UTC (rev 183724)
@@ -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;
}
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (183723 => 183724)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2015-05-03 00:15:27 UTC (rev 183724)
@@ -189,6 +189,7 @@
case GetMyArgumentByVal:
case ForwardVarargs:
case Switch:
+ case TypeOf:
// These are OK.
break;
case Identity:
Modified: trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h (183723 => 183724)
--- trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h 2015-05-03 00:15:27 UTC (rev 183724)
@@ -60,6 +60,7 @@
macro(C_JITOperation_EC, functionType(intPtr, intPtr, intPtr)) \
macro(C_JITOperation_ECZ, functionType(intPtr, intPtr, intPtr, int32)) \
macro(C_JITOperation_ECZC, functionType(intPtr, intPtr, intPtr, int32, intPtr)) \
+ macro(C_JITOperation_EGC, functionType(intPtr, intPtr, intPtr, intPtr)) \
macro(C_JITOperation_EJ, functionType(intPtr, intPtr, int64)) \
macro(C_JITOperation_EJssJss, functionType(intPtr, intPtr, intPtr, intPtr)) \
macro(C_JITOperation_EJssJssJss, functionType(intPtr, intPtr, intPtr, intPtr, intPtr)) \
@@ -97,6 +98,7 @@
macro(P_JITOperation_EStZ, functionType(intPtr, intPtr, intPtr, int32)) \
macro(Q_JITOperation_D, functionType(int64, doubleType)) \
macro(Q_JITOperation_J, functionType(int64, int64)) \
+ macro(S_JITOperation_EGC, functionType(intPtr, intPtr, intPtr, intPtr)) \
macro(S_JITOperation_EJ, functionType(intPtr, intPtr, int64)) \
macro(S_JITOperation_EJJ, functionType(intPtr, intPtr, int64, int64)) \
macro(S_JITOperation_J, functionType(intPtr, int64)) \
@@ -112,6 +114,7 @@
macro(V_JITOperation_Z, functionType(voidType, int32)) \
macro(Z_JITOperation_D, functionType(int32, doubleType)) \
macro(Z_JITOperation_EC, functionType(int32, intPtr, intPtr)) \
+ macro(Z_JITOperation_EGC, functionType(int32, intPtr, intPtr, intPtr)) \
macro(Z_JITOperation_EJZ, functionType(int32, intPtr, int64, int32)) \
macro(Z_JITOperation_ESJss, functionType(int32, intPtr, intPtr, int64)) \
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (183723 => 183724)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2015-05-03 00:15:27 UTC (rev 183724)
@@ -796,6 +796,9 @@
case IsFunction:
compileIsFunction();
break;
+ case TypeOf:
+ compileTypeOf();
+ break;
case CheckHasInstance:
compileCheckHasInstance();
break;
@@ -4623,18 +4626,119 @@
void compileIsObjectOrNull()
{
- LValue pointerResult = vmCall(
- m_out.operation(operationIsObjectOrNull), m_callFrame, lowJSValue(m_node->child1()));
- setBoolean(m_out.notNull(pointerResult));
+ JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
+
+ Edge child = m_node->child1();
+ LValue value = lowJSValue(child);
+
+ LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull cell case"));
+ LBasicBlock notFunctionCase = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull not function case"));
+ LBasicBlock objectCase = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull object case"));
+ LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull slow path"));
+ LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull not cell case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull continuation"));
+
+ m_out.branch(isCell(value, provenType(child)), unsure(cellCase), unsure(notCellCase));
+
+ LBasicBlock lastNext = m_out.appendTo(cellCase, notFunctionCase);
+ ValueFromBlock isFunctionResult = m_out.anchor(m_out.booleanFalse);
+ m_out.branch(
+ isFunction(value, provenType(child)),
+ unsure(continuation), unsure(notFunctionCase));
+
+ m_out.appendTo(notFunctionCase, objectCase);
+ ValueFromBlock notObjectResult = m_out.anchor(m_out.booleanFalse);
+ m_out.branch(
+ isObject(value, provenType(child)),
+ unsure(objectCase), unsure(continuation));
+
+ m_out.appendTo(objectCase, slowPath);
+ ValueFromBlock objectResult = m_out.anchor(m_out.booleanTrue);
+ m_out.branch(
+ isExoticForTypeof(value, provenType(child)),
+ rarely(slowPath), usually(continuation));
+
+ m_out.appendTo(slowPath, notCellCase);
+ LValue slowResultValue = vmCall(
+ m_out.operation(operationObjectIsObject), m_callFrame, weakPointer(globalObject),
+ value);
+ ValueFromBlock slowResult = m_out.anchor(m_out.notNull(slowResultValue));
+ m_out.jump(continuation);
+
+ m_out.appendTo(notCellCase, continuation);
+ LValue notCellResultValue = m_out.equal(value, m_out.constInt64(JSValue::encode(jsNull())));
+ ValueFromBlock notCellResult = m_out.anchor(notCellResultValue);
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ LValue result = m_out.phi(
+ m_out.boolean,
+ isFunctionResult, notObjectResult, objectResult, slowResult, notCellResult);
+ setBoolean(result);
}
void compileIsFunction()
{
- LValue pointerResult = vmCall(
- m_out.operation(operationIsFunction), lowJSValue(m_node->child1()));
- setBoolean(m_out.notNull(pointerResult));
+ JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
+
+ Edge child = m_node->child1();
+ LValue value = lowJSValue(child);
+
+ LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("IsFunction cell case"));
+ LBasicBlock notFunctionCase = FTL_NEW_BLOCK(m_out, ("IsFunction not function case"));
+ LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("IsFunction slow path"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("IsFunction continuation"));
+
+ ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
+ m_out.branch(
+ isCell(value, provenType(child)), unsure(cellCase), unsure(continuation));
+
+ LBasicBlock lastNext = m_out.appendTo(cellCase, notFunctionCase);
+ ValueFromBlock functionResult = m_out.anchor(m_out.booleanTrue);
+ m_out.branch(
+ isFunction(value, provenType(child)),
+ unsure(continuation), unsure(notFunctionCase));
+
+ m_out.appendTo(notFunctionCase, slowPath);
+ ValueFromBlock objectResult = m_out.anchor(m_out.booleanFalse);
+ m_out.branch(
+ isExoticForTypeof(value, provenType(child)),
+ rarely(slowPath), usually(continuation));
+
+ m_out.appendTo(slowPath, continuation);
+ LValue slowResultValue = vmCall(
+ m_out.operation(operationObjectIsFunction), m_callFrame, weakPointer(globalObject),
+ value);
+ ValueFromBlock slowResult = m_out.anchor(m_out.notNull(slowResultValue));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ LValue result = m_out.phi(
+ m_out.boolean, notCellResult, functionResult, objectResult, slowResult);
+ setBoolean(result);
}
+ void compileTypeOf()
+ {
+ Edge child = m_node->child1();
+ LValue value = lowJSValue(child);
+
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("TypeOf continuation"));
+ LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation);
+
+ Vector<ValueFromBlock> results;
+
+ buildTypeOf(
+ child, value,
+ [&] (TypeofType type) {
+ results.append(m_out.anchor(weakPointer(vm().smallStrings.typeString(type))));
+ m_out.jump(continuation);
+ });
+
+ m_out.appendTo(continuation, lastNext);
+ setJSValue(m_out.phi(m_out.int64, results));
+ }
+
void compileIn()
{
Edge base = m_node->child2();
@@ -6356,6 +6460,143 @@
Weight(data->fallThrough.count));
}
+ // Calls the functor at the point of code generation where we know what the result type is.
+ // You can emit whatever code you like at that point. Expects you to terminate the basic block.
+ // When buildTypeOf() returns, it will have terminated all basic blocks that it created. So, if
+ // you aren't using this as the terminator of a high-level block, you should create your own
+ // contination and set it as the nextBlock (m_out.insertNewBlocksBefore(continuation)) before
+ // calling this. For example:
+ //
+ // LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("My continuation"));
+ // LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation);
+ // buildTypeOf(
+ // child, value,
+ // [&] (TypeofType type) {
+ // do things;
+ // m_out.jump(continuation);
+ // });
+ // m_out.appendTo(continuation, lastNext);
+ template<typename Functor>
+ void buildTypeOf(Edge child, LValue value, const Functor& functor)
+ {
+ JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
+
+ // Implements the following branching structure:
+ //
+ // if (is cell) {
+ // if (is object) {
+ // if (is function) {
+ // return function;
+ // } else if (doesn't have call trap and doesn't masquerade as undefined) {
+ // return object
+ // } else {
+ // return slowPath();
+ // }
+ // } else if (is string) {
+ // return string
+ // } else {
+ // return symbol
+ // }
+ // } else if (is number) {
+ // return number
+ // } else if (is null) {
+ // return object
+ // } else if (is boolean) {
+ // return boolean
+ // } else {
+ // return undefined
+ // }
+
+ LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf cell case"));
+ LBasicBlock objectCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf object case"));
+ LBasicBlock functionCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf function case"));
+ LBasicBlock notFunctionCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not function case"));
+ LBasicBlock reallyObjectCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf really object case"));
+ LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("buildTypeOf slow path"));
+ LBasicBlock unreachable = FTL_NEW_BLOCK(m_out, ("buildTypeOf unreachable"));
+ LBasicBlock notObjectCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not object case"));
+ LBasicBlock stringCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf string case"));
+ LBasicBlock symbolCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf symbol case"));
+ LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not cell case"));
+ LBasicBlock numberCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf number case"));
+ LBasicBlock notNumberCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not number case"));
+ LBasicBlock notNullCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not null case"));
+ LBasicBlock booleanCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf boolean case"));
+ LBasicBlock undefinedCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf undefined case"));
+
+ m_out.branch(isCell(value, provenType(child)), unsure(cellCase), unsure(notCellCase));
+
+ LBasicBlock lastNext = m_out.appendTo(cellCase, objectCase);
+ m_out.branch(isObject(value, provenType(child)), unsure(objectCase), unsure(notObjectCase));
+
+ m_out.appendTo(objectCase, functionCase);
+ m_out.branch(
+ isFunction(value, provenType(child) & SpecObject),
+ unsure(functionCase), unsure(notFunctionCase));
+
+ m_out.appendTo(functionCase, notFunctionCase);
+ functor(TypeofType::Function);
+
+ m_out.appendTo(notFunctionCase, reallyObjectCase);
+ m_out.branch(
+ isExoticForTypeof(value, provenType(child) & (SpecObject - SpecFunction)),
+ rarely(slowPath), usually(reallyObjectCase));
+
+ m_out.appendTo(reallyObjectCase, slowPath);
+ functor(TypeofType::Object);
+
+ m_out.appendTo(slowPath, unreachable);
+ LValue result = vmCall(
+ m_out.operation(operationTypeOfObjectAsTypeofType), m_callFrame,
+ weakPointer(globalObject), value);
+ Vector<SwitchCase, 3> cases;
+ cases.append(SwitchCase(m_out.constInt32(static_cast<int32_t>(TypeofType::Undefined)), undefinedCase));
+ cases.append(SwitchCase(m_out.constInt32(static_cast<int32_t>(TypeofType::Object)), reallyObjectCase));
+ cases.append(SwitchCase(m_out.constInt32(static_cast<int32_t>(TypeofType::Function)), functionCase));
+ m_out.switchInstruction(result, cases, unreachable, Weight());
+
+ m_out.appendTo(unreachable, notObjectCase);
+ m_out.unreachable();
+
+ m_out.appendTo(notObjectCase, stringCase);
+ m_out.branch(
+ isString(value, provenType(child) & (SpecCell - SpecObject)),
+ unsure(stringCase), unsure(symbolCase));
+
+ m_out.appendTo(stringCase, symbolCase);
+ functor(TypeofType::String);
+
+ m_out.appendTo(symbolCase, notCellCase);
+ functor(TypeofType::Symbol);
+
+ m_out.appendTo(notCellCase, numberCase);
+ m_out.branch(
+ isNumber(value, provenType(child) & ~SpecCell),
+ unsure(numberCase), unsure(notNumberCase));
+
+ m_out.appendTo(numberCase, notNumberCase);
+ functor(TypeofType::Number);
+
+ m_out.appendTo(notNumberCase, notNullCase);
+ LValue isNull;
+ if (provenType(child) & SpecOther)
+ isNull = m_out.equal(value, m_out.constInt64(ValueNull));
+ else
+ isNull = m_out.booleanFalse;
+ m_out.branch(isNull, unsure(reallyObjectCase), unsure(notNullCase));
+
+ m_out.appendTo(notNullCase, booleanCase);
+ m_out.branch(
+ isBoolean(value, provenType(child) & ~(SpecCell | SpecFullNumber)),
+ unsure(booleanCase), unsure(undefinedCase));
+
+ m_out.appendTo(booleanCase, undefinedCase);
+ functor(TypeofType::Boolean);
+
+ m_out.appendTo(undefinedCase, lastNext);
+ functor(TypeofType::Undefined);
+ }
+
LValue doubleToInt32(LValue doubleValue, double low, double high, bool isSigned = true)
{
LBasicBlock greatEnough = FTL_NEW_BLOCK(m_out, ("doubleToInt32 greatEnough"));
@@ -7177,6 +7418,15 @@
return proven;
return isNotType(cell, JSFunctionType);
}
+
+ LValue isExoticForTypeof(LValue cell, SpeculatedType type = SpecFullTop)
+ {
+ if (!(type & SpecObjectOther))
+ return m_out.booleanFalse;
+ return m_out.testNonZero8(
+ m_out.load8(cell, m_heaps.JSCell_typeInfoFlags),
+ m_out.constInt8(MasqueradesAsUndefined | TypeOfShouldCallGetCallData));
+ }
LValue isType(LValue cell, JSType type)
{
Modified: trunk/Source/_javascript_Core/ftl/FTLSwitchCase.h (183723 => 183724)
--- trunk/Source/_javascript_Core/ftl/FTLSwitchCase.h 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/ftl/FTLSwitchCase.h 2015-05-03 00:15:27 UTC (rev 183724)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -41,7 +41,7 @@
{
}
- SwitchCase(LValue value, LBasicBlock target, Weight weight)
+ SwitchCase(LValue value, LBasicBlock target, Weight weight = Weight())
: m_value(value)
, m_target(target)
, m_weight(weight)
Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.h (183723 => 183724)
--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.h 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.h 2015-05-03 00:15:27 UTC (rev 183724)
@@ -33,6 +33,7 @@
#include "GPRInfo.h"
#include "JITCode.h"
#include "MacroAssembler.h"
+#include "TypeofType.h"
#include "VM.h"
namespace JSC {
@@ -367,6 +368,36 @@
storePtr(tag, Address(stackPointerRegister, entry * static_cast<ptrdiff_t>(sizeof(Register)) - prologueStackPointerDelta() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
}
#endif
+
+ JumpList branchIfNotEqual(JSValueRegs regs, JSValue value)
+ {
+#if USE(JSVALUE64)
+ return branch64(NotEqual, regs.gpr(), TrustedImm64(JSValue::encode(value)));
+#else
+ JumpList result;
+ result.append(branch32(NotEqual, regs.tagGPR(), TrustedImm32(value.tag())));
+ if (value.isEmpty() || value.isUndefinedOrNull())
+ return result; // These don't have anything interesting in the payload.
+ result.append(branch32(NotEqual, regs.payloadGPR(), TrustedImm32(value.payload())));
+ return result;
+#endif
+ }
+
+ Jump branchIfEqual(JSValueRegs regs, JSValue value)
+ {
+#if USE(JSVALUE64)
+ return branch64(Equal, regs.gpr(), TrustedImm64(JSValue::encode(value)));
+#else
+ Jump notEqual;
+ // These don't have anything interesting in the payload.
+ if (!value.isEmpty() && !value.isUndefinedOrNull())
+ notEqual = branch32(NotEqual, regs.payloadGPR(), TrustedImm32(value.payload()));
+ Jump result = branch32(Equal, regs.tagGPR(), TrustedImm32(value.tag()));
+ if (notEqual.isSet())
+ notEqual.link(this);
+ return result;
+#endif
+ }
Jump branchIfNotCell(GPRReg reg)
{
@@ -426,6 +457,56 @@
#endif
}
+ // Note that the tempGPR is not used in 64-bit mode.
+ Jump branchIfNumber(JSValueRegs regs, GPRReg tempGPR)
+ {
+#if USE(JSVALUE64)
+ UNUSED_PARAM(tempGPR);
+ return branchTest64(NonZero, regs.gpr(), GPRInfo::tagTypeNumberRegister);
+#else
+ add32(TrustedImm32(1), regs.tagGPR(), tempGPR);
+ return branch32(Below, tempGPR, TrustedImm32(JSValue::LowestTag + 1));
+#endif
+ }
+
+ // Note that the tempGPR is not used in 64-bit mode.
+ Jump branchIfNotNumber(JSValueRegs regs, GPRReg tempGPR)
+ {
+#if USE(JSVALUE64)
+ UNUSED_PARAM(tempGPR);
+ return branchTest64(Zero, regs.gpr(), GPRInfo::tagTypeNumberRegister);
+#else
+ add32(TrustedImm32(1), regs.tagGPR(), tempGPR);
+ return branch32(AboveOrEqual, tempGPR, TrustedImm32(JSValue::LowestTag + 1));
+#endif
+ }
+
+ // Note that the tempGPR is not used in 32-bit mode.
+ Jump branchIfBoolean(JSValueRegs regs, GPRReg tempGPR)
+ {
+#if USE(JSVALUE64)
+ move(regs.gpr(), tempGPR);
+ xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), tempGPR);
+ return branchTest64(Zero, tempGPR, TrustedImm32(static_cast<int32_t>(~1)));
+#else
+ UNUSED_PARAM(tempGPR);
+ return branch32(Equal, regs.tagGPR(), TrustedImm32(JSValue::BooleanTag));
+#endif
+ }
+
+ // Note that the tempGPR is not used in 32-bit mode.
+ Jump branchIfNotBoolean(JSValueRegs regs, GPRReg tempGPR)
+ {
+#if USE(JSVALUE64)
+ move(regs.gpr(), tempGPR);
+ xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), tempGPR);
+ return branchTest64(NonZero, tempGPR, TrustedImm32(static_cast<int32_t>(~1)));
+#else
+ UNUSED_PARAM(tempGPR);
+ return branch32(NotEqual, regs.tagGPR(), TrustedImm32(JSValue::BooleanTag));
+#endif
+ }
+
Jump branchIfObject(GPRReg cellGPR)
{
return branch8(
@@ -707,6 +788,23 @@
}
#endif
+ void boxBooleanPayload(GPRReg boolGPR, GPRReg payloadGPR)
+ {
+#if USE(JSVALUE64)
+ add32(TrustedImm32(ValueFalse), boolGPR, payloadGPR);
+#else
+ move(boolGPR, payloadGPR);
+#endif
+ }
+
+ void boxBoolean(GPRReg boolGPR, JSValueRegs boxedRegs)
+ {
+ boxBooleanPayload(boolGPR, boxedRegs.payloadGPR());
+#if USE(JSVALUE32_64)
+ move(TrustedImm32(JSValue::BooleanTag), boxedRegs.tagGPR());
+#endif
+ }
+
void callExceptionFuzz();
enum ExceptionCheckKind { NormalExceptionCheck, InvertedExceptionCheck };
@@ -843,7 +941,83 @@
uint8_t* address = reinterpret_cast<uint8_t*>(cell) + JSCell::gcDataOffset();
return branchTest8(MacroAssembler::NonZero, MacroAssembler::AbsoluteAddress(address));
}
+
+ // Emits the branch structure for typeof. The code emitted by this doesn't fall through. The
+ // functor is called at those points where we have pinpointed a type. One way to use this is to
+ // have the functor emit the code to put the type string into an appropriate register and then
+ // jump out. A secondary functor is used for the call trap and masquerades-as-undefined slow
+ // case. It is passed the unlinked jump to the slow case.
+ template<typename Functor, typename SlowPathFunctor>
+ void emitTypeOf(
+ JSValueRegs regs, GPRReg tempGPR, const Functor& functor,
+ const SlowPathFunctor& slowPathFunctor)
+ {
+ // Implements the following branching structure:
+ //
+ // if (is cell) {
+ // if (is object) {
+ // if (is function) {
+ // return function;
+ // } else if (doesn't have call trap and doesn't masquerade as undefined) {
+ // return object
+ // } else {
+ // return slowPath();
+ // }
+ // } else if (is string) {
+ // return string
+ // } else {
+ // return symbol
+ // }
+ // } else if (is number) {
+ // return number
+ // } else if (is null) {
+ // return object
+ // } else if (is boolean) {
+ // return boolean
+ // } else {
+ // return undefined
+ // }
+
+ Jump notCell = branchIfNotCell(regs);
+
+ GPRReg cellGPR = regs.payloadGPR();
+ Jump notObject = branchIfNotObject(cellGPR);
+
+ Jump notFunction = branchIfNotFunction(cellGPR);
+ functor(TypeofType::Function, false);
+
+ notFunction.link(this);
+ slowPathFunctor(
+ branchTest8(
+ NonZero,
+ Address(cellGPR, JSCell::typeInfoFlagsOffset()),
+ TrustedImm32(MasqueradesAsUndefined | TypeOfShouldCallGetCallData)));
+ functor(TypeofType::Object, false);
+
+ notObject.link(this);
+
+ Jump notString = branchIfNotString(cellGPR);
+ functor(TypeofType::String, false);
+ notString.link(this);
+ functor(TypeofType::Symbol, false);
+
+ notCell.link(this);
+ Jump notNumber = branchIfNotNumber(regs, tempGPR);
+ functor(TypeofType::Number, false);
+ notNumber.link(this);
+
+ JumpList notNull = branchIfNotEqual(regs, jsNull());
+ functor(TypeofType::Object, false);
+ notNull.link(this);
+
+ Jump notBoolean = branchIfNotBoolean(regs, tempGPR);
+ functor(TypeofType::Boolean, false);
+ notBoolean.link(this);
+
+ functor(TypeofType::Undefined, true);
+ }
+
Vector<BytecodeAndMachineOffset>& decodedCodeMapFor(CodeBlock*);
protected:
Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (183723 => 183724)
--- trunk/Source/_javascript_Core/jit/JITOperations.h 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h 2015-05-03 00:15:27 UTC (rev 183724)
@@ -63,6 +63,7 @@
D: double
E: ExecState*
F: CallFrame*
+ G: JSGlobalObject*
I: StringImpl*
Icf: InlineCallFrame*
Idc: const Identifier*
@@ -127,6 +128,7 @@
typedef JSCell* JIT_OPERATION (*C_JITOperation_ECZ)(ExecState*, JSCell*, int32_t);
typedef JSCell* JIT_OPERATION (*C_JITOperation_ECZC)(ExecState*, JSCell*, int32_t, JSCell*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
+typedef JSCell* JIT_OPERATION (*C_JITOperation_EGC)(ExecState*, JSGlobalObject*, JSCell*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EIcf)(ExecState*, InlineCallFrame*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EJ)(ExecState*, EncodedJSValue);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EJsc)(ExecState*, JSScope*);
@@ -157,10 +159,12 @@
typedef int32_t JIT_OPERATION (*Z_JITOperation_D)(double);
typedef int32_t JIT_OPERATION (*Z_JITOperation_E)(ExecState*);
typedef int32_t JIT_OPERATION (*Z_JITOperation_EC)(ExecState*, JSCell*);
+typedef int32_t JIT_OPERATION (*Z_JITOperation_EGC)(ExecState*, JSGlobalObject*, JSCell*);
typedef int32_t JIT_OPERATION (*Z_JITOperation_ESJss)(ExecState*, size_t, JSString*);
typedef int32_t JIT_OPERATION (*Z_JITOperation_EJZ)(ExecState*, EncodedJSValue, int32_t);
typedef int32_t JIT_OPERATION (*Z_JITOperation_EJZZ)(ExecState*, EncodedJSValue, int32_t, int32_t);
typedef size_t JIT_OPERATION (*S_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
+typedef size_t JIT_OPERATION (*S_JITOperation_EGC)(ExecState*, JSGlobalObject*, JSCell*);
typedef size_t JIT_OPERATION (*S_JITOperation_EJ)(ExecState*, EncodedJSValue);
typedef size_t JIT_OPERATION (*S_JITOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
typedef size_t JIT_OPERATION (*S_JITOperation_EOJss)(ExecState*, JSObject*, JSString*);
Modified: trunk/Source/_javascript_Core/runtime/SmallStrings.h (183723 => 183724)
--- trunk/Source/_javascript_Core/runtime/SmallStrings.h 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/runtime/SmallStrings.h 2015-05-03 00:15:27 UTC (rev 183724)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2009, 2015 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,6 +26,7 @@
#ifndef SmallStrings_h
#define SmallStrings_h
+#include "TypeofType.h"
#include "WriteBarrier.h"
#include <wtf/Noncopyable.h>
@@ -85,6 +86,29 @@
}
JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ACCESSOR_DEFINITION)
#undef JSC_COMMON_STRINGS_ACCESSOR_DEFINITION
+
+ JSString* typeString(TypeofType type) const
+ {
+ switch (type) {
+ case TypeofType::Undefined:
+ return undefinedString();
+ case TypeofType::Boolean:
+ return booleanString();
+ case TypeofType::Number:
+ return numberString();
+ case TypeofType::String:
+ return stringString();
+ case TypeofType::Symbol:
+ return symbolString();
+ case TypeofType::Object:
+ return objectString();
+ case TypeofType::Function:
+ return functionString();
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return nullptr;
+ }
JSString* nullObjectString() const { return m_nullObjectString; }
JSString* undefinedObjectString() const { return m_undefinedObjectString; }
Added: trunk/Source/_javascript_Core/runtime/TypeofType.cpp (0 => 183724)
--- trunk/Source/_javascript_Core/runtime/TypeofType.cpp (rev 0)
+++ trunk/Source/_javascript_Core/runtime/TypeofType.cpp 2015-05-03 00:15:27 UTC (rev 183724)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TypeofType.h"
+
+namespace WTF {
+
+using namespace JSC;
+
+void printInternal(PrintStream& out, TypeofType type)
+{
+ switch (type) {
+ case TypeofType::Undefined:
+ out.print("undefined");
+ return;
+ case TypeofType::Boolean:
+ out.print("boolean");
+ return;
+ case TypeofType::Number:
+ out.print("number");
+ return;
+ case TypeofType::String:
+ out.print("string");
+ return;
+ case TypeofType::Symbol:
+ out.print("symbol");
+ return;
+ case TypeofType::Object:
+ out.print("object");
+ return;
+ case TypeofType::Function:
+ out.print("function");
+ return;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
Added: trunk/Source/_javascript_Core/runtime/TypeofType.h (0 => 183724)
--- trunk/Source/_javascript_Core/runtime/TypeofType.h (rev 0)
+++ trunk/Source/_javascript_Core/runtime/TypeofType.h 2015-05-03 00:15:27 UTC (rev 183724)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TypeofType_h
+#define TypeofType_h
+
+#include <wtf/PrintStream.h>
+
+namespace JSC {
+
+enum class TypeofType {
+ Undefined,
+ Boolean,
+ Number,
+ String,
+ Symbol,
+ Object,
+ Function
+};
+
+} // namespace JSC
+
+namespace WTF {
+
+void printInternal(PrintStream& out, JSC::TypeofType);
+
+} // namespace WTF
+
+#endif // TypeofType_h
+
Modified: trunk/Source/_javascript_Core/tests/stress/type-of-functions-and-objects.js (183723 => 183724)
--- trunk/Source/_javascript_Core/tests/stress/type-of-functions-and-objects.js 2015-05-02 23:06:08 UTC (rev 183723)
+++ trunk/Source/_javascript_Core/tests/stress/type-of-functions-and-objects.js 2015-05-03 00:15:27 UTC (rev 183724)
@@ -26,48 +26,61 @@
noInline(baz);
noInline(fuzz);
-function expect(f, v, expected) {
- var result = f(v);
- if (result != expected)
- throw "Error: " + f.name + "(" + v + ") returned " + result + " instead of " + expected;
-}
+function test() {
+ var errors = [];
-function test(v, expected) {
- switch (expected) {
- case "function":
- expect(foo, v, "function");
- expect(bar, v, 2);
- expect(baz, v, true);
- expect(fuzz, v, false);
- break;
- case "object":
- expect(foo, v, "object");
- expect(bar, v, 1);
- expect(baz, v, false);
- expect(fuzz, v, true);
- break;
- case "other":
- var result = foo(v);
- if (result == "object" || result == "function")
- throw "Error: foo(" + v + ") returned " + result + " but expected something other than object or function";
- expect(bar, v, 3);
- expect(baz, v, false);
- expect(fuzz, v, false);
- break;
- default:
- throw "Bad expected case";
+ function testValue(v, expected) {
+ function expect(f, expected) {
+ var result = f(v);
+ if (result != expected)
+ errors.push(f.name + "(" + v + ") returned " + result + " instead of " + expected);
+ }
+
+ switch (expected) {
+ case "function":
+ expect(foo, "function");
+ expect(bar, 2);
+ expect(baz, true);
+ expect(fuzz, false);
+ break;
+ case "object":
+ expect(foo, "object");
+ expect(bar, 1);
+ expect(baz, false);
+ expect(fuzz, true);
+ break;
+ case "other":
+ var result = foo(v);
+ if (result == "object" || result == "function")
+ errors.push("foo(" + v + ") returned " + result + " but expected something other than object or function");
+ expect(bar, 3);
+ expect(baz, false);
+ expect(fuzz, false);
+ break;
+ default:
+ throw "Bad expected case";
+ }
}
+
+ testValue({}, "object");
+ testValue(function() { }, "function");
+ testValue("hello", "other");
+ testValue(42, "other");
+ testValue(null, "object");
+ testValue(void 0, "other");
+ testValue(42.5, "other");
+ testValue(Map, "function");
+ testValue(Date, "function");
+ testValue(Map.prototype, "object");
+
+ if (!errors.length)
+ return;
+
+ for (var i = 0; i < errors.length; ++i)
+ print("Error: " + errors[i]);
+ throw "Encountered errors during test run.";
}
-for (var i = 0; i < 10000; ++i) {
- test({}, "object");
- test(function() { }, "function");
- test("hello", "other");
- test(42, "other");
- test(null, "object");
- test(void 0, "other");
- test(42.5, "other");
- test(Map, "function");
- test(Date, "function");
- test(Map.prototype, "object");
-}
+for (var i = 0; i < 10000; ++i)
+ test();
+