Title: [155243] trunk/Source/_javascript_Core
Revision
155243
Author
[email protected]
Date
2013-09-06 22:47:57 -0700 (Fri, 06 Sep 2013)

Log Message

FTL should support Call/Construct in the worst way possible
https://bugs.webkit.org/show_bug.cgi?id=120916

Reviewed by Oliver Hunt.
        
This adds support for Call/Construct by just calling out to C code that uses
the JSC::call/JSC::construct runtime functions for making calls. This is slow
and terrible, but it dramatically extends FTL coverage.
        
Supporting calls in a meaningful way meant also supporting
GlobalVarWatchpoint.
        
The extension of coverage helped to find a bunch of bugs:
        
- ObjectOrOtherUse was claimed to be supported in the FTL but speculate()
  didn't support it. That means that any node with an ObjectOrOtherUse edge
  that got DCE'd would cause the FTL to ICE.
        
- There was a bad fall-through compileCompareStrictEq() that led to ICE.
        
- The OSR exit reconstruction code was assuming it could do fast checks on
  node->child1() before even determining the type of node; that crashes if
  the node is HasVarArgs. Fixed by checking HasVarArgs first.
        
- The OSR exit compiler was using the wrong peekOffset for CArgumentGetter.
  The default is 1, which assumes that you didn't push anything onto the
  stack after getting called. The OSR exit thunks push FP, so the offset
  should be 2.
        
This passes stress tests and is probably huge performance regression if you
--useExperimentalFTL=true. The regression will be fixed in
https://bugs.webkit.org/show_bug.cgi?id=113621.

* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileGlobalVarWatchpoint):
(JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
(JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct):
(JSC::FTL::LowerDFGToLLVM::speculate):
(JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther):
(JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileStub):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (155242 => 155243)


--- trunk/Source/_javascript_Core/ChangeLog	2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/ChangeLog	2013-09-07 05:47:57 UTC (rev 155243)
@@ -1,5 +1,56 @@
 2013-09-06  Filip Pizlo  <[email protected]>
 
+        FTL should support Call/Construct in the worst way possible
+        https://bugs.webkit.org/show_bug.cgi?id=120916
+
+        Reviewed by Oliver Hunt.
+        
+        This adds support for Call/Construct by just calling out to C code that uses
+        the JSC::call/JSC::construct runtime functions for making calls. This is slow
+        and terrible, but it dramatically extends FTL coverage.
+        
+        Supporting calls in a meaningful way meant also supporting
+        GlobalVarWatchpoint.
+        
+        The extension of coverage helped to find a bunch of bugs:
+        
+        - ObjectOrOtherUse was claimed to be supported in the FTL but speculate()
+          didn't support it. That means that any node with an ObjectOrOtherUse edge
+          that got DCE'd would cause the FTL to ICE.
+        
+        - There was a bad fall-through compileCompareStrictEq() that led to ICE.
+        
+        - The OSR exit reconstruction code was assuming it could do fast checks on
+          node->child1() before even determining the type of node; that crashes if
+          the node is HasVarArgs. Fixed by checking HasVarArgs first.
+        
+        - The OSR exit compiler was using the wrong peekOffset for CArgumentGetter.
+          The default is 1, which assumes that you didn't push anything onto the
+          stack after getting called. The OSR exit thunks push FP, so the offset
+          should be 2.
+        
+        This passes stress tests and is probably huge performance regression if you
+        --useExperimentalFTL=true. The regression will be fixed in
+        https://bugs.webkit.org/show_bug.cgi?id=113621.
+
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLIntrinsicRepository.h:
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::LowerDFGToLLVM::compileGlobalVarWatchpoint):
+        (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
+        (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct):
+        (JSC::FTL::LowerDFGToLLVM::speculate):
+        (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther):
+        (JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
+        * ftl/FTLOSRExitCompiler.cpp:
+        (JSC::FTL::compileStub):
+
+2013-09-06  Filip Pizlo  <[email protected]>
+
         jsc shell should destroy VM as a workaround for LLVM's exit-time destructors
         https://bugs.webkit.org/show_bug.cgi?id=120921
 

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (155242 => 155243)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2013-09-07 05:47:57 UTC (rev 155243)
@@ -2200,6 +2200,46 @@
         jitCode->optimizeAfterWarmUp(codeBlock);
     return static_cast<char*>(address);
 }
+
+// FIXME: Make calls work well. Currently they're a pure regression.
+// https://bugs.webkit.org/show_bug.cgi?id=113621
+EncodedJSValue DFG_OPERATION operationFTLCall(ExecState* exec)
+{
+    ExecState* callerExec = exec->callerFrame();
+    
+    VM* vm = &callerExec->vm();
+    NativeCallFrameTracer tracer(vm, callerExec);
+    
+    JSValue callee = exec->calleeAsValue();
+    CallData callData;
+    CallType callType = getCallData(callee, callData);
+    if (callType == CallTypeNone) {
+        vm->throwException(callerExec, createNotAFunctionError(callerExec, callee));
+        return JSValue::encode(jsUndefined());
+    }
+    
+    return JSValue::encode(call(callerExec, callee, callType, callData, exec->thisValue(), exec));
+}
+
+// FIXME: Make calls work well. Currently they're a pure regression.
+// https://bugs.webkit.org/show_bug.cgi?id=113621
+EncodedJSValue DFG_OPERATION operationFTLConstruct(ExecState* exec)
+{
+    ExecState* callerExec = exec->callerFrame();
+    
+    VM* vm = &callerExec->vm();
+    NativeCallFrameTracer tracer(vm, callerExec);
+    
+    JSValue callee = exec->calleeAsValue();
+    ConstructData constructData;
+    ConstructType constructType = getConstructData(callee, constructData);
+    if (constructType == ConstructTypeNone) {
+        vm->throwException(callerExec, createNotAFunctionError(callerExec, callee));
+        return JSValue::encode(jsUndefined());
+    }
+    
+    return JSValue::encode(construct(callerExec, callee, constructType, constructData, exec));
+}
 #endif // ENABLE(FTL_JIT)
 
 } // extern "C"

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (155242 => 155243)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2013-09-07 05:47:57 UTC (rev 155243)
@@ -254,6 +254,13 @@
 char* DFG_OPERATION operationFindSwitchImmTargetForDouble(ExecState*, EncodedJSValue, size_t tableIndex);
 char* DFG_OPERATION operationSwitchString(ExecState*, size_t tableIndex, JSString*);
 
+#if ENABLE(FTL_JIT)
+// FIXME: Make calls work well. Currently they're a pure regression.
+// https://bugs.webkit.org/show_bug.cgi?id=113621
+EncodedJSValue DFG_OPERATION operationFTLCall(ExecState*) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationFTLConstruct(ExecState*) WTF_INTERNAL;
+#endif // ENABLE(FTL_JIT)
+
 // This method is used to lookup an exception hander, keyed by faultLocation, which is
 // the return location from one of the calls out to one of the helper operations above.
 

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (155242 => 155243)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2013-09-07 05:47:57 UTC (rev 155243)
@@ -86,6 +86,9 @@
     case Upsilon:
     case ExtractOSREntryLocal:
     case LoopHint:
+    case Call:
+    case Construct:
+    case GlobalVarWatchpoint:
         // These are OK.
         break;
     case GetArrayLength:

Modified: trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h (155242 => 155243)


--- trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h	2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h	2013-09-07 05:47:57 UTC (rev 155243)
@@ -46,6 +46,7 @@
 
 #define FOR_EACH_FUNCTION_TYPE(macro) \
     macro(I_DFGOperation_EJss, functionType(intPtr, intPtr, intPtr)) \
+    macro(J_DFGOperation_E, functionType(int64, intPtr)) \
     macro(P_DFGOperation_EC, functionType(intPtr, intPtr, intPtr)) \
     macro(V_DFGOperation_EOZD, functionType(voidType, intPtr, intPtr, int32, doubleType)) \
     macro(V_DFGOperation_EOZJ, functionType(voidType, intPtr, intPtr, int32, int64))

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (155242 => 155243)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2013-09-07 05:47:57 UTC (rev 155243)
@@ -363,6 +363,9 @@
         case PutGlobalVar:
             compilePutGlobalVar();
             break;
+        case GlobalVarWatchpoint:
+            compileGlobalVarWatchpoint();
+            break;
         case CompareEq:
             compileCompareEq();
             break;
@@ -390,6 +393,10 @@
         case LogicalNot:
             compileLogicalNot();
             break;
+        case Call:
+        case Construct:
+            compileCallOrConstruct();
+            break;
         case Jump:
             compileJump();
             break;
@@ -1396,6 +1403,12 @@
             lowJSValue(m_node->child1()), m_out.absolute(m_node->registerPointer()));
     }
     
+    void compileGlobalVarWatchpoint()
+    {
+        // FIXME: Implement watchpoints.
+        // https://bugs.webkit.org/show_bug.cgi?id=113647
+    }
+    
     void compileCompareEq()
     {
         if (m_node->isBinaryUseKind(Int32Use)
@@ -1428,6 +1441,7 @@
         if (m_node->isBinaryUseKind(NumberUse)) {
             setBoolean(
                 m_out.doubleEqual(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
+            return;
         }
         
         if (m_node->isBinaryUseKind(ObjectUse)) {
@@ -1541,6 +1555,39 @@
         setBoolean(m_out.bitNot(boolify(m_node->child1())));
     }
     
+    void compileCallOrConstruct()
+    {
+        // FIXME: This is unacceptably slow.
+        // https://bugs.webkit.org/show_bug.cgi?id=113621
+        
+        J_DFGOperation_E function =
+            m_node->op() == Call ? operationFTLCall : operationFTLConstruct;
+        
+        int dummyThisArgument = m_node->op() == Call ? 0 : 1;
+        
+        int numPassedArgs = m_node->numChildren() - 1;
+        
+        LValue calleeFrame = m_out.add(
+            m_callFrame,
+            m_out.constIntPtr(sizeof(Register) * codeBlock()->m_numCalleeRegisters));
+        
+        m_out.store32(
+            m_out.constInt32(numPassedArgs + dummyThisArgument),
+            payloadFor(calleeFrame, JSStack::ArgumentCount));
+        m_out.store64(m_callFrame, addressFor(calleeFrame, JSStack::CallerFrame));
+        m_out.store64(
+            lowJSValue(m_graph.varArgChild(m_node, 0)),
+            addressFor(calleeFrame, JSStack::Callee));
+        
+        for (int i = 0; i < numPassedArgs; ++i) {
+            m_out.store64(
+                lowJSValue(m_graph.varArgChild(m_node, 1 + i)),
+                addressFor(calleeFrame, argumentToOperand(i + dummyThisArgument)));
+        }
+        
+        setJSValue(vmCall(m_out.operation(function), calleeFrame));
+    }
+    
     void compileJump()
     {
         m_out.jump(lowBlock(m_node->takenBlock()));
@@ -2212,6 +2259,9 @@
         case ObjectUse:
             speculateObject(edge);
             break;
+        case ObjectOrOtherUse:
+            speculateObjectOrOther(edge);
+            break;
         case StringUse:
             speculateString(edge);
             break;
@@ -2225,6 +2275,7 @@
             speculateBoolean(edge);
             break;
         default:
+            dataLog("Unsupported speculation use kind: ", edge.useKind(), "\n");
             RELEASE_ASSERT_NOT_REACHED();
         }
     }
@@ -2278,6 +2329,42 @@
         speculateObject(edge, lowCell(edge));
     }
     
+    void speculateObjectOrOther(Edge edge)
+    {
+        if (!m_interpreter.needsTypeCheck(edge))
+            return;
+        
+        LValue value = lowJSValue(edge);
+        
+        LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther cell case"));
+        LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther primitive case"));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther continuation"));
+        
+        m_out.branch(isNotCell(value), primitiveCase, cellCase);
+        
+        LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase);
+        
+        FTL_TYPE_CHECK(
+            jsValueValue(value), edge, (~SpecCell) | SpecObject,
+            m_out.equal(
+                m_out.loadPtr(value, m_heaps.JSCell_structure),
+                m_out.constIntPtr(vm().stringStructure.get())));
+        
+        m_out.jump(continuation);
+        
+        m_out.appendTo(primitiveCase, continuation);
+        
+        FTL_TYPE_CHECK(
+            jsValueValue(value), edge, SpecCell | SpecOther,
+            m_out.notEqual(
+                m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)),
+                m_out.constInt64(ValueNull)));
+        
+        m_out.jump(continuation);
+        
+        m_out.appendTo(continuation, lastNext);
+    }
+    
     void speculateString(Edge edge, LValue cell)
     {
         FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecString, isNotString(cell));
@@ -2634,6 +2721,8 @@
                 HashSet<Node*>::iterator end = m_live.end();
                 for (; iter != end; ++iter) {
                     Node* candidate = *iter;
+                    if (candidate->flags() & NodeHasVarArgs)
+                        continue;
                     if (!candidate->child1())
                         continue;
                     if (candidate->child1() != node)

Modified: trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp (155242 => 155243)


--- trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp	2013-09-07 05:36:45 UTC (rev 155242)
+++ trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp	2013-09-07 05:47:57 UTC (rev 155243)
@@ -56,7 +56,7 @@
     // of: we know that it's two frames beneath us. This is terrible and I feel
     // ashamed of it, but it will work for now.
     
-    CArgumentGetter arguments(jit);
+    CArgumentGetter arguments(jit, 2);
     
     // First recover our call frame and tag thingies.
     arguments.loadNextPtr(GPRInfo::callFrameRegister);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to