Title: [183724] trunk/Source/_javascript_Core
Revision
183724
Author
[email protected]
Date
2015-05-02 17:15:27 -0700 (Sat, 02 May 2015)

Log Message

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.

Modified Paths

Added Paths

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();
+
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to