Title: [160958] branches/jsCStack/Source/_javascript_Core
Revision
160958
Author
[email protected]
Date
2013-12-20 20:58:15 -0800 (Fri, 20 Dec 2013)

Log Message

FTL OSR exit should be able to handle the arity check fail case
https://bugs.webkit.org/show_bug.cgi?id=126111

Not yet reviewed.

* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileStub):
* jit/RegisterPreservationWrapperGenerator.cpp:
(JSC::generateRegisterRestoration):
* tests/stress: Added.
* tests/stress/exit-from-ftl-with-arity-check-fail.js: Added.
(foo):
(bar):
* tests/stress/repeated-arity-check-fail.js: Added.
(bar):

Modified Paths

Added Paths

Diff

Modified: branches/jsCStack/Source/_javascript_Core/ChangeLog (160957 => 160958)


--- branches/jsCStack/Source/_javascript_Core/ChangeLog	2013-12-21 03:50:12 UTC (rev 160957)
+++ branches/jsCStack/Source/_javascript_Core/ChangeLog	2013-12-21 04:58:15 UTC (rev 160958)
@@ -1,5 +1,23 @@
 2013-12-20  Filip Pizlo  <[email protected]>
 
+        FTL OSR exit should be able to handle the arity check fail case
+        https://bugs.webkit.org/show_bug.cgi?id=126111
+
+        Not yet reviewed.
+
+        * ftl/FTLOSRExitCompiler.cpp:
+        (JSC::FTL::compileStub):
+        * jit/RegisterPreservationWrapperGenerator.cpp:
+        (JSC::generateRegisterRestoration):
+        * tests/stress: Added.
+        * tests/stress/exit-from-ftl-with-arity-check-fail.js: Added.
+        (foo):
+        (bar):
+        * tests/stress/repeated-arity-check-fail.js: Added.
+        (bar):
+
+2013-12-20  Filip Pizlo  <[email protected]>
+
         Arity check stack restoration should preserve the ArgumentCount in case there is a register restoration thunk below it
         https://bugs.webkit.org/show_bug.cgi?id=126106
 

Modified: branches/jsCStack/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp (160957 => 160958)


--- branches/jsCStack/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp	2013-12-21 03:50:12 UTC (rev 160957)
+++ branches/jsCStack/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp	2013-12-21 04:58:15 UTC (rev 160958)
@@ -162,7 +162,44 @@
     }
     
     jit.load32(CCallHelpers::payloadFor(JSStack::ArgumentCount), GPRInfo::regT2);
+    
+    // Let's say that the FTL function had failed its arity check. In that case, the stack will
+    // contain some extra stuff.
+    //
+    // First we compute the padded stack space:
+    //
+    //     paddedStackSpace = roundUp(codeBlock->numParameters - regT2 + 1)
+    //
+    // The stack will have regT2 + CallFrameHeaderSize stuff, but above it there will be
+    // paddedStackSpace gunk used by the arity check fail restoration thunk. When that happens
+    // we want to make the stack look like this, from higher addresses down:
+    //
+    //     - register preservation return PC
+    //     - preserved registers
+    //     - arity check fail return PC
+    //     - argument padding
+    //     - actual arguments
+    //     - call frame header
+    //
+    // So that the actual call frame header appears to return to the arity check fail return
+    // PC, and that then returns to the register preservation thunk. The arity check thunk that
+    // we return to will have the padding size encoded into it. It will then know to return
+    // into the register preservation thunk, which uses the argument count to figure out where
+    // registers are preserved.
 
+    // This code assumes that we're dealing with FunctionCode.
+    RELEASE_ASSERT(codeBlock->codeType() == FunctionCode);
+    
+    jit.add32(
+        MacroAssembler::TrustedImm32(-codeBlock->numParameters()), GPRInfo::regT2,
+        GPRInfo::regT3);
+    MacroAssembler::Jump arityIntact = jit.branchTest32(MacroAssembler::Zero, GPRInfo::regT3);
+    jit.neg32(GPRInfo::regT3);
+    jit.add32(MacroAssembler::TrustedImm32(1 + stackAlignmentRegisters() - 1), GPRInfo::regT3);
+    jit.and32(MacroAssembler::TrustedImm32(-stackAlignmentRegisters()), GPRInfo::regT3);
+    jit.add32(GPRInfo::regT3, GPRInfo::regT2);
+    arityIntact.link(&jit);
+
     // First set up SP so that our data doesn't get clobbered by signals.
     jit.addPtr(
         MacroAssembler::TrustedImm32(
@@ -207,13 +244,34 @@
         jit.store64(GPRInfo::regT0, AssemblyHelpers::Address(GPRInfo::regT1, currentOffset));
     }
     
-    // We need to make sure that we return into the register restoration thunk.
+    // We need to make sure that we return into the register restoration thunk. This works
+    // differently depending on whether or not we had arity issues.
+    MacroAssembler::Jump arityIntactForReturnPC =
+        jit.branchTest32(MacroAssembler::Zero, GPRInfo::regT3);
+    
+    // The return PC in the call frame header points at exactly the right arity restoration
+    // thunk. We don't want to change that. But the arity restoration thunk's frame has a
+    // return PC and we want to reroute that to our register restoration thunk. The arity
+    // restoration's return PC just just below regT1, and the register restoration's return PC
+    // is right at regT1.
+    jit.loadPtr(MacroAssembler::Address(GPRInfo::regT1, -static_cast<ptrdiff_t>(sizeof(Register))), GPRInfo::regT0);
+    jit.storePtr(GPRInfo::regT0, GPRInfo::regT1);
+    jit.storePtr(
+        MacroAssembler::TrustedImmPtr(vm->getCTIStub(registerRestorationThunkGenerator).code().executableAddress()),
+        MacroAssembler::Address(GPRInfo::regT1, -static_cast<ptrdiff_t>(sizeof(Register))));
+    
+    MacroAssembler::Jump arityReturnPCReady = jit.jump();
+
+    arityIntactForReturnPC.link(&jit);
+    
     jit.loadPtr(MacroAssembler::Address(MacroAssembler::framePointerRegister, CallFrame::returnPCOffset()), GPRInfo::regT0);
     jit.storePtr(GPRInfo::regT0, GPRInfo::regT1);
     jit.storePtr(
         MacroAssembler::TrustedImmPtr(vm->getCTIStub(registerRestorationThunkGenerator).code().executableAddress()),
         MacroAssembler::Address(MacroAssembler::framePointerRegister, CallFrame::returnPCOffset()));
     
+    arityReturnPCReady.link(&jit);
+    
     // Now get state out of the scratch buffer and place it back into the stack. This part does
     // all reboxing.
     for (unsigned index = exit.m_values.size(); index--;) {

Modified: branches/jsCStack/Source/_javascript_Core/jit/RegisterPreservationWrapperGenerator.cpp (160957 => 160958)


--- branches/jsCStack/Source/_javascript_Core/jit/RegisterPreservationWrapperGenerator.cpp	2013-12-21 03:50:12 UTC (rev 160957)
+++ branches/jsCStack/Source/_javascript_Core/jit/RegisterPreservationWrapperGenerator.cpp	2013-12-21 04:58:15 UTC (rev 160958)
@@ -147,13 +147,21 @@
         AssemblyHelpers::Address(
             AssemblyHelpers::stackPointerRegister,
             (JSStack::ArgumentCount - JSStack::CallerFrameAndPCSize) * sizeof(Register) + PayloadOffset),
-        GPRInfo::regT2);
+        GPRInfo::regT1);
     
+    jit.move(GPRInfo::regT1, GPRInfo::regT2);
     jit.lshift32(AssemblyHelpers::TrustedImm32(3), GPRInfo::regT2);
     
     jit.addPtr(AssemblyHelpers::TrustedImm32(offset), AssemblyHelpers::stackPointerRegister);
     jit.addPtr(AssemblyHelpers::stackPointerRegister, GPRInfo::regT2);
     
+    // Thunks like this rely on the ArgumentCount being intact. Pay it forward.
+    jit.store32(
+        GPRInfo::regT1,
+        AssemblyHelpers::Address(
+            AssemblyHelpers::stackPointerRegister,
+            (JSStack::ArgumentCount - JSStack::CallerFrameAndPCSize) * sizeof(Register) + PayloadOffset));
+    
     // We saved things at:
     //
     //     adjSP + (JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize + NumArgs) * 8

Added: branches/jsCStack/Source/_javascript_Core/tests/stress/exit-from-ftl-with-arity-check-fail.js (0 => 160958)


--- branches/jsCStack/Source/_javascript_Core/tests/stress/exit-from-ftl-with-arity-check-fail.js	                        (rev 0)
+++ branches/jsCStack/Source/_javascript_Core/tests/stress/exit-from-ftl-with-arity-check-fail.js	2013-12-21 04:58:15 UTC (rev 160958)
@@ -0,0 +1,18 @@
+function foo(o, a, b, c, d, e, f, g, h, i, j) {
+    return o.f;
+}
+
+function bar(o) {
+    return foo(o);
+}
+
+noInline(foo);
+noInline(bar);
+
+for (var i = 0; i < 100000; ++i)
+    bar({f:42});
+
+var result = bar({g:24, f:43});
+if (result != 43)
+    throw "Error: bad result: " + result;
+

Added: branches/jsCStack/Source/_javascript_Core/tests/stress/repeated-arity-check-fail.js (0 => 160958)


--- branches/jsCStack/Source/_javascript_Core/tests/stress/repeated-arity-check-fail.js	                        (rev 0)
+++ branches/jsCStack/Source/_javascript_Core/tests/stress/repeated-arity-check-fail.js	2013-12-21 04:58:15 UTC (rev 160958)
@@ -0,0 +1,8 @@
+function bar(a,b,c,d,e,f,g,h,i,j,k) {
+}
+
+noInline(bar);
+
+for (var i = 0; i < 10000000; ++i)
+    bar();
+
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to