Title: [183235] trunk
Revision
183235
Author
[email protected]
Date
2015-04-23 19:23:36 -0700 (Thu, 23 Apr 2015)

Log Message

Allow function allocation sinking
https://bugs.webkit.org/show_bug.cgi?id=144016

Patch by Basile Clement <[email protected]> on 2015-04-23
Reviewed by Filip Pizlo.

Source/_javascript_Core:

This adds the ability to sink function allocations in the
DFGObjectAllocationSinkingPhase.

In order to enable this, we add a new PhantomNewFunction node that is
used similarily to the PhantomNewObject node, i.e. as a placeholder to replace
a sunk NewFunction and keep track of the allocations that have to be performed
in case of OSR exit after the sunk allocation but before the real one.
The FunctionExecutable and JSLexicalEnvironment (activation) of the function
are stored onto the PhantomNewFunction through PutHints in order for them
to be recovered on OSR exit.

Contrary to sunk object allocations, sunk function allocations do not
support any kind of operations (e.g. storing into a field) ; any such operation
will mark the function allocation as escaping and trigger materialization. As
such, function allocations can only be sunk to places where it would have been
correct to syntactically move them, and we don't need a special
MaterializeNewFunction node to recover possible operations on the function. A
sunk NewFunction node will simply create new NewFunction nodes, then replace
itself with a PhantomNewFunction node.

In itself, this change is not expected to have a significant impact on
performances other than in degenerate cases (see e.g.
JSRegress/sink-function), but it is a step towards being able to sink recursive
closures onces we support CreateActivation sinking as well as allocation cycles
sinking.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToPhantomNewFunction):
(JSC::DFG::Node::isPhantomAllocation):
* dfg/DFGNodeType.h:
* dfg/DFGObjectAllocationSinkingPhase.cpp:
(JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations):
(JSC::DFG::ObjectAllocationSinkingPhase::handleNode):
(JSC::DFG::ObjectAllocationSinkingPhase::createMaterialize):
(JSC::DFG::ObjectAllocationSinkingPhase::populateMaterialize):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGPromotedHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGPromotedHeapLocation.h:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::validateCPS):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
* ftl/FTLOperations.cpp:
(JSC::FTL::operationMaterializeObjectInOSR):
* tests/stress/function-sinking-no-double-allocate.js: Added.
(call):
(.f):
(sink):
* tests/stress/function-sinking-osrexit.js: Added.
(.g):
(sink):
* tests/stress/function-sinking-put.js: Added.
(.g):
(sink):

LayoutTests:

Add a new test in JSRegress to check function sinking is being
performed.

* js/regress/script-tests/sink-function.js: Added.
(foo.f1):
(foo.f2):
(foo.f3):
(foo.f4):
(foo.f5):
(foo.f6):
(foo.f7):
(foo.f8):
(foo.f9):
(foo.f10):
(foo.f11):
(foo.f12):
(foo.f13):
(foo.f14):
(foo.f15):
(foo.f16):
(foo.f17):
(foo.f18):
(foo.f19):
(foo):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (183234 => 183235)


--- trunk/LayoutTests/ChangeLog	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/LayoutTests/ChangeLog	2015-04-24 02:23:36 UTC (rev 183235)
@@ -1,3 +1,35 @@
+2015-04-23  Basile Clement  <[email protected]>
+
+        Allow function allocation sinking
+        https://bugs.webkit.org/show_bug.cgi?id=144016
+
+        Reviewed by Filip Pizlo.
+
+        Add a new test in JSRegress to check function sinking is being
+        performed.
+
+        * js/regress/script-tests/sink-function.js: Added.
+        (foo.f1):
+        (foo.f2):
+        (foo.f3):
+        (foo.f4):
+        (foo.f5):
+        (foo.f6):
+        (foo.f7):
+        (foo.f8):
+        (foo.f9):
+        (foo.f10):
+        (foo.f11):
+        (foo.f12):
+        (foo.f13):
+        (foo.f14):
+        (foo.f15):
+        (foo.f16):
+        (foo.f17):
+        (foo.f18):
+        (foo.f19):
+        (foo):
+
 2015-04-23  Alexey Proskuryakov  <[email protected]>
 
         Test compositing/scrolling/touch-scroll-to-clip.html fails in WK1

Added: trunk/LayoutTests/js/regress/script-tests/sink-function.js (0 => 183235)


--- trunk/LayoutTests/js/regress/script-tests/sink-function.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/sink-function.js	2015-04-24 02:23:36 UTC (rev 183235)
@@ -0,0 +1,35 @@
+function foo(p) {
+    var f1 = function (x) { return x; };
+    var f2 = function (x) { return x; };
+    var f3 = function (x) { return x; };
+    var f4 = function (x) { return x; };
+    var f5 = function (x) { return x; };
+    var f6 = function (x) { return x; };
+    var f7 = function (x) { return x; };
+    var f8 = function (x) { return x; };
+    var f9 = function (x) { return x; };
+    var f10 = function (x) { return x; };
+    var f11 = function (x) { return x; };
+    var f12 = function (x) { return x; };
+    var f13 = function (x) { return x; };
+    var f14 = function (x) { return x; };
+    var f15 = function (x) { return x; };
+    var f16 = function (x) { return x; };
+    var f17 = function (x) { return x; };
+    var f18 = function (x) { return x; };
+    var f19 = function (x) { return x; };
+    if (p)
+        return f1(f2(f3(f4(f5(f6(f7(f8(f9(f10(f11(f12(f13(f14(f15(f16(f17(f18(f19(p)))))))))))))))))));
+}
+noInline(foo);
+
+for (var i = 0; i < 100000; ++i) {
+    var result = foo(false);
+    if (result)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo(true);
+if (result !== true)
+    throw "Error: bad result: " + result;
+

Modified: trunk/Source/_javascript_Core/ChangeLog (183234 => 183235)


--- trunk/Source/_javascript_Core/ChangeLog	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-04-24 02:23:36 UTC (rev 183235)
@@ -1,5 +1,85 @@
 2015-04-23  Basile Clement  <[email protected]>
 
+        Allow function allocation sinking
+        https://bugs.webkit.org/show_bug.cgi?id=144016
+
+        Reviewed by Filip Pizlo.
+
+        This adds the ability to sink function allocations in the
+        DFGObjectAllocationSinkingPhase.
+
+        In order to enable this, we add a new PhantomNewFunction node that is
+        used similarily to the PhantomNewObject node, i.e. as a placeholder to replace
+        a sunk NewFunction and keep track of the allocations that have to be performed
+        in case of OSR exit after the sunk allocation but before the real one.
+        The FunctionExecutable and JSLexicalEnvironment (activation) of the function
+        are stored onto the PhantomNewFunction through PutHints in order for them
+        to be recovered on OSR exit.
+
+        Contrary to sunk object allocations, sunk function allocations do not
+        support any kind of operations (e.g. storing into a field) ; any such operation
+        will mark the function allocation as escaping and trigger materialization. As
+        such, function allocations can only be sunk to places where it would have been
+        correct to syntactically move them, and we don't need a special
+        MaterializeNewFunction node to recover possible operations on the function. A
+        sunk NewFunction node will simply create new NewFunction nodes, then replace
+        itself with a PhantomNewFunction node.
+
+        In itself, this change is not expected to have a significant impact on
+        performances other than in degenerate cases (see e.g.
+        JSRegress/sink-function), but it is a step towards being able to sink recursive
+        closures onces we support CreateActivation sinking as well as allocation cycles
+        sinking.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::convertToPhantomNewFunction):
+        (JSC::DFG::Node::isPhantomAllocation):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGObjectAllocationSinkingPhase.cpp:
+        (JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations):
+        (JSC::DFG::ObjectAllocationSinkingPhase::handleNode):
+        (JSC::DFG::ObjectAllocationSinkingPhase::createMaterialize):
+        (JSC::DFG::ObjectAllocationSinkingPhase::populateMaterialize):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGPromotedHeapLocation.cpp:
+        (WTF::printInternal):
+        * dfg/DFGPromotedHeapLocation.h:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGValidate.cpp:
+        (JSC::DFG::Validate::validateCPS):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        * ftl/FTLOperations.cpp:
+        (JSC::FTL::operationMaterializeObjectInOSR):
+        * tests/stress/function-sinking-no-double-allocate.js: Added.
+        (call):
+        (.f):
+        (sink):
+        * tests/stress/function-sinking-osrexit.js: Added.
+        (.g):
+        (sink):
+        * tests/stress/function-sinking-put.js: Added.
+        (.g):
+        (sink):
+
+2015-04-23  Basile Clement  <[email protected]>
+
         Make FunctionRareData allocation thread-safe
         https://bugs.webkit.org/show_bug.cgi?id=144001
 

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-04-24 02:23:36 UTC (rev 183235)
@@ -1353,6 +1353,7 @@
         break;
         
     case PhantomNewObject:
+    case PhantomNewFunction:
     case PhantomDirectArguments:
     case PhantomClonedArguments:
     case BottomValue:

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2015-04-24 02:23:36 UTC (rev 183235)
@@ -857,6 +857,7 @@
     case NewStringObject:
     case PhantomNewObject:
     case MaterializeNewObject:
+    case PhantomNewFunction:
         read(HeapObjectCount);
         write(HeapObjectCount);
         return;

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2015-04-24 02:23:36 UTC (rev 183235)
@@ -197,6 +197,7 @@
     case CheckBadCell:
     case BottomValue:
     case PhantomNewObject:
+    case PhantomNewFunction:
     case PhantomDirectArguments:
     case PhantomClonedArguments:
     case GetMyArgumentByVal:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-04-24 02:23:36 UTC (rev 183235)
@@ -1035,6 +1035,7 @@
         case Identity: // This should have been cleaned up.
         case BooleanToNumber:
         case PhantomNewObject:
+        case PhantomNewFunction:
         case PhantomDirectArguments:
         case PhantomClonedArguments:
         case ForwardVarargs:

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2015-04-24 02:23:36 UTC (rev 183235)
@@ -581,7 +581,17 @@
         m_opInfo2 = 0;
         children = AdjacencyList();
     }
-    
+
+    void convertToPhantomNewFunction()
+    {
+        ASSERT(m_op == NewFunction);
+        m_op = PhantomNewFunction;
+        m_flags |= NodeMustGenerate;
+        m_opInfo = 0;
+        m_opInfo2 = 0;
+        children = AdjacencyList();
+    }
+
     void convertPhantomToPhantomLocal()
     {
         ASSERT(m_op == Phantom && (child1()->op() == Phi || child1()->op() == SetLocal || child1()->op() == SetArgument));
@@ -1427,6 +1437,7 @@
         case PhantomNewObject:
         case PhantomDirectArguments:
         case PhantomClonedArguments:
+        case PhantomNewFunction:
             return true;
         default:
             return false;

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2015-04-24 02:23:36 UTC (rev 183235)
@@ -246,6 +246,7 @@
     macro(PutHint, NodeMustGenerate) \
     macro(CheckStructureImmediate, NodeMustGenerate) \
     macro(MaterializeNewObject, NodeResultJS | NodeHasVarArgs) \
+    macro(PhantomNewFunction, NodeResultJS | NodeMustGenerate) \
     \
     /* Nodes for misc operations. */\
     macro(Breakpoint, NodeMustGenerate) \

Modified: trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp	2015-04-24 02:23:36 UTC (rev 183235)
@@ -510,13 +510,15 @@
                 Node* node = block->at(nodeIndex);
                 switch (node->op()) {
                 case PutByOffset: {
-                    if (m_sinkCandidates.contains(node->child2().node()))
+                    Node* target = node->child2().node();
+                    if (target->isPhantomObjectAllocation() && m_sinkCandidates.contains(target))
                         node->convertToPutByOffsetHint();
                     break;
                 }
                     
                 case PutStructure: {
-                    if (m_sinkCandidates.contains(node->child1().node())) {
+                    Node* target = node->child1().node();
+                    if (target->isPhantomObjectAllocation() && m_sinkCandidates.contains(target)) {
                         Node* structure = m_insertionSet.insertConstant(
                             nodeIndex, node->origin, JSValue(node->transition()->next));
                         node->convertToPutStructureHint(structure);
@@ -557,10 +559,28 @@
                     }
                     break;
                 }
-                    
+
+                case NewFunction: {
+                    if (m_sinkCandidates.contains(node)) {
+                        Node* executable = m_insertionSet.insertConstant(
+                            nodeIndex + 1, node->origin, node->cellOperand());
+                        m_insertionSet.insert(
+                            nodeIndex + 1,
+                            PromotedHeapLocation(FunctionExecutablePLoc, node).createHint(
+                                m_graph, node->origin, executable));
+                        m_insertionSet.insert(
+                            nodeIndex + 1,
+                            PromotedHeapLocation(FunctionActivationPLoc, node).createHint(
+                                m_graph, node->origin, node->child1().node()));
+                        node->convertToPhantomNewFunction();
+                    }
+                    break;
+                }
+
                 case StoreBarrier:
                 case StoreBarrierWithNullCheck: {
-                    if (m_sinkCandidates.contains(node->child1().node()))
+                    Node* target = node->child1().node();
+                    if (target->isPhantomObjectAllocation() && m_sinkCandidates.contains(target))
                         node->convertToPhantom();
                     break;
                 }
@@ -759,7 +779,16 @@
                     escape(edge.node());
                 });
             break;
-            
+
+        case NewFunction:
+            sinkCandidate();
+            m_graph.doToChildren(
+                node,
+                [&] (Edge edge) {
+                    escape(edge.node());
+                });
+            break;
+
         case CheckStructure:
         case GetByOffset:
         case MultiGetByOffset:
@@ -815,7 +844,17 @@
                 OpInfo(data), OpInfo(), 0, 0);
             break;
         }
-            
+
+        case NewFunction:
+            result = m_graph.addNode(
+                escapee->prediction(), NewFunction,
+                NodeOrigin(
+                    escapee->origin.semantic,
+                    where->origin.forExit),
+                OpInfo(escapee->cellOperand()),
+                escapee->child1());
+            break;
+
         default:
             DFG_CRASH(m_graph, escapee, "Bad escapee op");
             break;
@@ -874,7 +913,40 @@
                 firstChild, m_graph.m_varArgChildren.size() - firstChild);
             break;
         }
-            
+
+        case NewFunction: {
+            if (!ASSERT_DISABLED) {
+                Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee);
+
+                ASSERT(locations.size() == 2);
+
+                PromotedHeapLocation executable(FunctionExecutablePLoc, escapee);
+                ASSERT(locations.contains(executable));
+
+                PromotedHeapLocation activation(FunctionActivationPLoc, escapee);
+                ASSERT(locations.contains(activation));
+
+                for (unsigned i = 0; i < locations.size(); ++i) {
+                    switch (locations[i].kind()) {
+                    case FunctionExecutablePLoc: {
+                        ASSERT(locations[i] == executable);
+                        break;
+                    }
+
+                    case FunctionActivationPLoc: {
+                        ASSERT(locations[i] == activation);
+                        break;
+                    }
+
+                    default:
+                        DFG_CRASH(m_graph, node, "Bad location kind");
+                    }
+                }
+            }
+
+            break;
+        }
+
         default:
             DFG_CRASH(m_graph, node, "Bad materialize op");
             break;

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2015-04-24 02:23:36 UTC (rev 183235)
@@ -542,6 +542,7 @@
         case Identity:
         case BooleanToNumber:
         case PhantomNewObject:
+        case PhantomNewFunction:
         case PhantomDirectArguments:
         case PhantomClonedArguments:
         case GetMyArgumentByVal:

Modified: trunk/Source/_javascript_Core/dfg/DFGPromotedHeapLocation.cpp (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGPromotedHeapLocation.cpp	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGPromotedHeapLocation.cpp	2015-04-24 02:23:36 UTC (rev 183235)
@@ -82,6 +82,14 @@
     case ArgumentsCalleePLoc:
         out.print("ArgumentsCalleePLoc");
         return;
+
+    case FunctionExecutablePLoc:
+        out.print("FunctionExecutablePLoc");
+        return;
+
+    case FunctionActivationPLoc:
+        out.print("FunctionActivationPLoc");
+        return;
     }
     
     RELEASE_ASSERT_NOT_REACHED();

Modified: trunk/Source/_javascript_Core/dfg/DFGPromotedHeapLocation.h (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGPromotedHeapLocation.h	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGPromotedHeapLocation.h	2015-04-24 02:23:36 UTC (rev 183235)
@@ -40,7 +40,10 @@
     NamedPropertyPLoc,
     ArgumentPLoc,
     ArgumentCountPLoc,
-    ArgumentsCalleePLoc
+    ArgumentsCalleePLoc,
+
+    FunctionExecutablePLoc,
+    FunctionActivationPLoc,
 };
 
 class PromotedLocationDescriptor {

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2015-04-24 02:23:36 UTC (rev 183235)
@@ -272,6 +272,7 @@
     case GetEnumeratorGenericPname:
     case ToIndexString:
     case PhantomNewObject:
+    case PhantomNewFunction:
     case PutHint:
     case CheckStructureImmediate:
     case MaterializeNewObject:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-04-24 02:23:36 UTC (rev 183235)
@@ -4656,6 +4656,7 @@
     case CheckBadCell:
     case BottomValue:
     case PhantomNewObject:
+    case PhantomNewFunction:
     case PutHint:
     case CheckStructureImmediate:
     case MaterializeNewObject:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-04-24 02:23:36 UTC (rev 183235)
@@ -4741,6 +4741,7 @@
     case CheckBadCell:
     case BottomValue:
     case PhantomNewObject:
+    case PhantomNewFunction:
     case GetMyArgumentByVal:
     case PutHint:
     case CheckStructureImmediate:

Modified: trunk/Source/_javascript_Core/dfg/DFGValidate.cpp (183234 => 183235)


--- trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2015-04-24 02:23:36 UTC (rev 183235)
@@ -452,6 +452,7 @@
                 case Upsilon:
                 case CheckInBounds:
                 case PhantomNewObject:
+                case PhantomNewFunction:
                 case GetMyArgumentByVal:
                 case PutHint:
                 case CheckStructureImmediate:

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (183234 => 183235)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2015-04-24 02:23:36 UTC (rev 183235)
@@ -180,6 +180,7 @@
     case ToIndexString:
     case BottomValue:
     case PhantomNewObject:
+    case PhantomNewFunction:
     case PutHint:
     case CheckStructureImmediate:
     case MaterializeNewObject:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (183234 => 183235)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-04-24 02:23:36 UTC (rev 183235)
@@ -849,6 +849,7 @@
         case MovHint:
         case ZombieHint:
         case PhantomNewObject:
+        case PhantomNewFunction:
         case PhantomDirectArguments:
         case PhantomClonedArguments:
         case PutHint:

Modified: trunk/Source/_javascript_Core/ftl/FTLOperations.cpp (183234 => 183235)


--- trunk/Source/_javascript_Core/ftl/FTLOperations.cpp	2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/_javascript_Core/ftl/FTLOperations.cpp	2015-04-24 02:23:36 UTC (rev 183235)
@@ -92,7 +92,25 @@
     
         return result;
     }
-        
+
+    case PhantomNewFunction: {
+        // Figure out what the executable and activation are
+        FunctionExecutable* executable = nullptr;
+        JSScope* activation = nullptr;
+        for (unsigned i = materialization->properties().size(); i--;) {
+            const ExitPropertyValue& property = materialization->properties()[i];
+            if (property.location() == PromotedLocationDescriptor(FunctionExecutablePLoc))
+                executable = jsCast<FunctionExecutable*>(JSValue::decode(values[i]));
+            if (property.location() == PromotedLocationDescriptor(FunctionActivationPLoc))
+                activation = jsCast<JSScope*>(JSValue::decode(values[i]));
+        }
+        RELEASE_ASSERT(executable && activation);
+
+        JSFunction* result = JSFunction::create(vm, executable, activation);
+
+        return result;
+    }
+
     case PhantomDirectArguments:
     case PhantomClonedArguments: {
         if (!materialization->origin().inlineCallFrame) {

Added: trunk/Source/_javascript_Core/tests/stress/function-sinking-no-double-allocate.js (0 => 183235)


--- trunk/Source/_javascript_Core/tests/stress/function-sinking-no-double-allocate.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/function-sinking-no-double-allocate.js	2015-04-24 02:23:36 UTC (rev 183235)
@@ -0,0 +1,28 @@
+function call(o) { o.x = 3; }
+noInline(call);
+
+function sink (p, q) {
+    var f = function () { };
+    if (p) {
+        call(f); // Force allocation of f
+        if (q) {
+            OSRExit();
+        }
+        return f;
+    }
+    return { 'x': 2 };
+}
+noInline(sink);
+
+for (var i = 0; i < 100000; ++i) {
+    var o = sink(true, false);
+    if (o.x != 3)
+        throw "Error: expected o.x to be 2 but is " + result;
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Check that the function is properly allocated on OSR exit
+var f = sink(true, true);
+if (f.x != 3)
+    throw "Error: expected o.x to be 3 but is " + result;

Added: trunk/Source/_javascript_Core/tests/stress/function-sinking-osrexit.js (0 => 183235)


--- trunk/Source/_javascript_Core/tests/stress/function-sinking-osrexit.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/function-sinking-osrexit.js	2015-04-24 02:23:36 UTC (rev 183235)
@@ -0,0 +1,21 @@
+function sink (p, q) {
+    var g = function(x) { return x; };
+    if (p) { if (q) OSRExit(); return g; }
+    return function(x) { return x; };
+}
+noInline(sink);
+
+for (var i = 0; i < 10000; ++i) {
+    var f = sink(true, false);
+    var result = f(42);
+    if (result != 42)
+    throw "Error: expected 42 but got " + result;
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Check that the function is properly allocated on OSR exit
+var f = sink(true, true);
+var result = f(42);
+if (result != 42)
+    throw "Error: expected 42 but got " + result;

Added: trunk/Source/_javascript_Core/tests/stress/function-sinking-put.js (0 => 183235)


--- trunk/Source/_javascript_Core/tests/stress/function-sinking-put.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/function-sinking-put.js	2015-04-24 02:23:36 UTC (rev 183235)
@@ -0,0 +1,28 @@
+function sink (p, q) {
+    var g = function(x) { return x; };
+    if (p) { if (q) g.inner = 42; return g; }
+    return function(x) { return x; };
+}
+noInline(sink);
+
+for (var i = 0; i < 10000; ++i) {
+    var f = sink(true, true);
+    var result = f(42);
+    if (result != 42)
+    throw "Error: expected 42 but got " + result;
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Test the allocation on the implicit inner else branch
+var f = sink(true, false);
+var result = f(12);
+if (result != 12)
+    // This shouldn't matter as it should be either correct or completely crash
+    throw "Error: expected 12 but got " + result;
+
+// Check that the allocation did not sink beyond the property assignment
+var f = sink(true, true);
+var result = f.inner;
+if (result != 42)
+    throw "Error: inner should be 42 but is " + result;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to