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;