Title: [191360] trunk
Revision
191360
Author
[email protected]
Date
2015-10-20 15:02:37 -0700 (Tue, 20 Oct 2015)

Log Message

REGRESSION (r191175): OSR Exit from an inlined tail callee trashes callee save registers
https://bugs.webkit.org/show_bug.cgi?id=150336

Reviewed by Mark Lam.

Source/_javascript_Core:

During OSR exit, we need to restore and transform the active stack into what the baseline
JIT expects.  Inlined call frames become true call frames.  When we reify an inlined call
frame and it is a tail call which we will be continuing from, we need to restore the tag
constant callee save registers with what was saved by the outermost caller.

Re-enabled tail calls and restored tests for tail calls.

* dfg/DFGOSRExitCompilerCommon.cpp:
(JSC::DFG::reifyInlinedCallFrames): Select whether or not we use the callee save tag register
contents or what was saved by the inlining caller when populating an inlined callee's
callee save registers.
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::emitSaveCalleeSavesFor): This function no longer needs a stack offset.
(JSC::AssemblyHelpers::emitSaveOrCopyCalleeSavesFor): New helper.
* runtime/Options.h: Turned tail calls back on.
* tests/es6.yaml:
* tests/stress/dfg-tail-calls.js:
(nonInlinedTailCall.callee):
* tests/stress/mutual-tail-call-no-stack-overflow.js:
(shouldThrow):
* tests/stress/tail-call-in-inline-cache.js:
(tail):
* tests/stress/tail-call-no-stack-overflow.js:
(shouldThrow):
* tests/stress/tail-call-recognize.js:
(callerMustBeRun):
* tests/stress/tail-call-varargs-no-stack-overflow.js:
(shouldThrow):

LayoutTests:

Added a new regression test and restored tail call test results for js/caller-property.

* js/caller-property-expected.txt:
* js/regress-150336-expected.txt: Added.
* js/regress-150336.html: Added.
* js/script-tests/regress-150336.js: Added.
(bar):
(foo):
(test):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (191359 => 191360)


--- trunk/LayoutTests/ChangeLog	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/LayoutTests/ChangeLog	2015-10-20 22:02:37 UTC (rev 191360)
@@ -1,3 +1,20 @@
+2015-10-20  Michael Saboff  <[email protected]>
+
+        REGRESSION (r191175): OSR Exit from an inlined tail callee trashes callee save registers
+        https://bugs.webkit.org/show_bug.cgi?id=150336
+
+        Reviewed by Mark Lam.
+
+        Added a new regression test and restored tail call test results for js/caller-property.
+
+        * js/caller-property-expected.txt:
+        * js/regress-150336-expected.txt: Added.
+        * js/regress-150336.html: Added.
+        * js/script-tests/regress-150336.js: Added.
+        (bar):
+        (foo):
+        (test):
+
 2015-10-20  Ryan Haddad  <[email protected]>
 
         Take 2 on rebaselining fast/dynamic/insert-before-table-part-in-continuation.html

Modified: trunk/LayoutTests/js/caller-property-expected.txt (191359 => 191360)


--- trunk/LayoutTests/js/caller-property-expected.txt	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/LayoutTests/js/caller-property-expected.txt	2015-10-20 22:02:37 UTC (rev 191360)
@@ -10,13 +10,13 @@
 PASS nonStrictCaller(strictCallee) threw exception TypeError: Type error.
 PASS strictCaller(nonStrictCallee) threw exception TypeError: Function.caller used to retrieve strict caller.
 PASS strictCaller(strictCallee) threw exception TypeError: Type error.
-FAIL strictTailCaller(nonStrictCallee) should be null. Threw exception TypeError: Function.caller used to retrieve strict caller
+PASS strictTailCaller(nonStrictCallee) is null
 PASS strictTailCaller(strictCallee) threw exception TypeError: Type error.
 PASS nonStrictCaller(boundNonStrictCallee) is nonStrictCaller
 PASS nonStrictCaller(boundStrictCallee) threw exception TypeError: Type error.
 PASS strictCaller(boundNonStrictCallee) threw exception TypeError: Function.caller used to retrieve strict caller.
 PASS strictCaller(boundStrictCallee) threw exception TypeError: Type error.
-FAIL strictTailCaller(boundNonStrictCallee) should be null. Threw exception TypeError: Function.caller used to retrieve strict caller
+PASS strictTailCaller(boundNonStrictCallee) is null
 PASS strictTailCaller(boundStrictCallee) threw exception TypeError: Type error.
 PASS nonStrictGetter(nonStrictAccessor) is nonStrictGetter
 PASS nonStrictSetter(nonStrictAccessor) is true

Added: trunk/LayoutTests/js/regress-150336-expected.txt (0 => 191360)


--- trunk/LayoutTests/js/regress-150336-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress-150336-expected.txt	2015-10-20 22:02:37 UTC (rev 191360)
@@ -0,0 +1,10 @@
+Regression test for https://webkit.org/b/150336.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Properly handled OSR exit from a bound function with an inlined tail callee.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress-150336.html (0 => 191360)


--- trunk/LayoutTests/js/regress-150336.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress-150336.html	2015-10-20 22:02:37 UTC (rev 191360)
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/script-tests/regress-150336.js (0 => 191360)


--- trunk/LayoutTests/js/script-tests/regress-150336.js	                        (rev 0)
+++ trunk/LayoutTests/js/script-tests/regress-150336.js	2015-10-20 22:02:37 UTC (rev 191360)
@@ -0,0 +1,45 @@
+description("Regression test for https://webkit.org/b/150336.");
+
+// This test verifies that an OSR exit from a bound function with an inlined tail callee
+// properly transitions to the baseline JIT without crashing.
+
+myObj = {
+    val: 1
+}
+
+function bar(a, idx)
+{
+    "use strict";
+
+    if (idx == 9900)
+        myObj.dfgOSR = "Test";
+
+    if (idx == 199900)
+        myObj.ftlOSR = "Test";
+
+    return myObj.val + a;
+}
+
+function foo(a, idx)
+{
+    "use strict";
+
+    return bar(a, idx);
+}
+
+boundFoo = foo.bind(null, 41);
+
+function test()
+{
+    for (var i = 0; i < 200000; i++) {
+        got = boundFoo(i);
+        if (got != 42)
+            testFailed("Function returned " + got + " but expected 42!");
+    }
+}
+
+noInline(test);
+
+test();
+
+testPassed("Properly handled OSR exit from a bound function with an inlined tail callee.");

Modified: trunk/Source/_javascript_Core/ChangeLog (191359 => 191360)


--- trunk/Source/_javascript_Core/ChangeLog	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-10-20 22:02:37 UTC (rev 191360)
@@ -1,3 +1,39 @@
+2015-10-20  Michael Saboff  <[email protected]>
+
+        REGRESSION (r191175): OSR Exit from an inlined tail callee trashes callee save registers
+        https://bugs.webkit.org/show_bug.cgi?id=150336
+
+        Reviewed by Mark Lam.
+
+        During OSR exit, we need to restore and transform the active stack into what the baseline
+        JIT expects.  Inlined call frames become true call frames.  When we reify an inlined call
+        frame and it is a tail call which we will be continuing from, we need to restore the tag
+        constant callee save registers with what was saved by the outermost caller.
+
+        Re-enabled tail calls and restored tests for tail calls.
+
+        * dfg/DFGOSRExitCompilerCommon.cpp:
+        (JSC::DFG::reifyInlinedCallFrames): Select whether or not we use the callee save tag register
+        contents or what was saved by the inlining caller when populating an inlined callee's
+        callee save registers.
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::emitSaveCalleeSavesFor): This function no longer needs a stack offset.
+        (JSC::AssemblyHelpers::emitSaveOrCopyCalleeSavesFor): New helper.
+        * runtime/Options.h: Turned tail calls back on.
+        * tests/es6.yaml:
+        * tests/stress/dfg-tail-calls.js:
+        (nonInlinedTailCall.callee):
+        * tests/stress/mutual-tail-call-no-stack-overflow.js:
+        (shouldThrow):
+        * tests/stress/tail-call-in-inline-cache.js:
+        (tail):
+        * tests/stress/tail-call-no-stack-overflow.js:
+        (shouldThrow):
+        * tests/stress/tail-call-recognize.js:
+        (callerMustBeRun):
+        * tests/stress/tail-call-varargs-no-stack-overflow.js:
+        (shouldThrow):
+
 2015-10-20  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: _javascript_Core should parse sourceURL and sourceMappingURL directives
@@ -68,6 +104,7 @@
         (JSC::GCAwareJITStubRoutineWithExceptionHandler::~GCAwareJITStubRoutineWithExceptionHandler): Deleted.
         * jit/GCAwareJITStubRoutine.h:
 
+>>>>>>> .r191351
 2015-10-20  Tim Horton  <[email protected]>
 
         Try to fix the build by disabling MAC_GESTURE_EVENTS on 10.9 and 10.10

Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExitCompilerCommon.cpp (191359 => 191360)


--- trunk/Source/_javascript_Core/dfg/DFGOSRExitCompilerCommon.cpp	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExitCompilerCommon.cpp	2015-10-20 22:02:37 UTC (rev 191360)
@@ -214,7 +214,16 @@
             jit.storePtr(AssemblyHelpers::TrustedImmPtr(trueReturnPC), AssemblyHelpers::addressFor(inlineCallFrame->stackOffset + virtualRegisterForArgument(inlineCallFrame->arguments.size()).offset()));
                          
         jit.storePtr(AssemblyHelpers::TrustedImmPtr(baselineCodeBlock), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::CodeBlock)));
-        jit.emitSaveCalleeSavesFor(baselineCodeBlock, static_cast<VirtualRegister>(inlineCallFrame->stackOffset));
+
+        // Restore the inline call frame's callee save registers.
+        // If this inlined frame is a tail call that will return back to the original caller, we need to
+        // copy the prior contents of the tag registers already saved for the outer frame to this frame.
+        jit.emitSaveOrCopyCalleeSavesFor(
+            baselineCodeBlock,
+            static_cast<VirtualRegister>(inlineCallFrame->stackOffset),
+            trueCaller ? AssemblyHelpers::UseExistingTagRegisterContents : AssemblyHelpers::CopySavedTagRegistersFromBaseFrame,
+            GPRInfo::regT2);
+
         if (!inlineCallFrame->isVarargs())
             jit.store32(AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount)));
 #if USE(JSVALUE64)

Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.h (191359 => 191360)


--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.h	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.h	2015-10-20 22:02:37 UTC (rev 191360)
@@ -178,7 +178,7 @@
 #endif
     }
 
-    void emitSaveCalleeSavesFor(CodeBlock* codeBlock, VirtualRegister offsetVirtualRegister = static_cast<VirtualRegister>(0))
+    void emitSaveCalleeSavesFor(CodeBlock* codeBlock)
     {
         ASSERT(codeBlock);
 
@@ -190,10 +190,43 @@
             RegisterAtOffset entry = calleeSaves->at(i);
             if (dontSaveRegisters.get(entry.reg()))
                 continue;
-            storePtr(entry.reg().gpr(), Address(framePointerRegister, offsetVirtualRegister.offsetInBytes() + entry.offset()));
+            storePtr(entry.reg().gpr(), Address(framePointerRegister, entry.offset()));
         }
     }
+    
+    enum RestoreTagRegisterMode { UseExistingTagRegisterContents, CopySavedTagRegistersFromBaseFrame };
 
+    void emitSaveOrCopyCalleeSavesFor(CodeBlock* codeBlock, VirtualRegister offsetVirtualRegister, RestoreTagRegisterMode tagRegisterMode, GPRReg temp)
+    {
+        ASSERT(codeBlock);
+        
+        RegisterAtOffsetList* calleeSaves = codeBlock->calleeSaveRegisters();
+        RegisterSet dontSaveRegisters = RegisterSet(RegisterSet::stackRegisters(), RegisterSet::allFPRs());
+        unsigned registerCount = calleeSaves->size();
+        
+        for (unsigned i = 0; i < registerCount; i++) {
+            RegisterAtOffset entry = calleeSaves->at(i);
+            if (dontSaveRegisters.get(entry.reg()))
+                continue;
+            
+            GPRReg registerToWrite;
+            
+#if USE(JSVALUE32_64)
+            UNUSED_PARAM(tagRegisterMode);
+            UNUSED_PARAM(temp);
+#else
+            if (tagRegisterMode == CopySavedTagRegistersFromBaseFrame
+                && (entry.reg() == GPRInfo::tagTypeNumberRegister || entry.reg() == GPRInfo::tagMaskRegister)) {
+                registerToWrite = temp;
+                loadPtr(AssemblyHelpers::Address(GPRInfo::callFrameRegister, entry.offset()), registerToWrite);
+            } else
+#endif
+                registerToWrite = entry.reg().gpr();
+
+            storePtr(registerToWrite, Address(framePointerRegister, offsetVirtualRegister.offsetInBytes() + entry.offset()));
+        }
+    }
+    
     void emitRestoreCalleeSavesFor(CodeBlock* codeBlock)
     {
         ASSERT(codeBlock);

Modified: trunk/Source/_javascript_Core/runtime/Options.h (191359 => 191360)


--- trunk/Source/_javascript_Core/runtime/Options.h	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/Source/_javascript_Core/runtime/Options.h	2015-10-20 22:02:37 UTC (rev 191360)
@@ -131,7 +131,7 @@
     v(bool, forceProfilerBytecodeGeneration, false, nullptr) \
     \
     v(bool, useFunctionDotArguments, true, nullptr) \
-    v(bool, useTailCalls, false, nullptr) \
+    v(bool, useTailCalls, true, nullptr) \
     \
     /* dumpDisassembly implies dumpDFGDisassembly. */ \
     v(bool, dumpDisassembly, false, "dumps disassembly of all JIT compiled code upon compilation") \

Modified: trunk/Source/_javascript_Core/tests/es6.yaml (191359 => 191360)


--- trunk/Source/_javascript_Core/tests/es6.yaml	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/Source/_javascript_Core/tests/es6.yaml	2015-10-20 22:02:37 UTC (rev 191360)
@@ -879,9 +879,9 @@
 - path: es6/Promise_Promise[Symbol.species].js
   cmd: runES6 :fail
 - path: es6/proper_tail_calls_tail_call_optimisation_direct_recursion.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/proper_tail_calls_tail_call_optimisation_mutual_recursion.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/prototype_of_bound_functions_arrow_functions.js
   cmd: runES6 :fail
 - path: es6/prototype_of_bound_functions_basic_functions.js

Modified: trunk/Source/_javascript_Core/tests/stress/dfg-tail-calls.js (191359 => 191360)


--- trunk/Source/_javascript_Core/tests/stress/dfg-tail-calls.js	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/Source/_javascript_Core/tests/stress/dfg-tail-calls.js	2015-10-20 22:02:37 UTC (rev 191360)
@@ -1,4 +1,3 @@
-//@ skip
 (function nonInlinedTailCall() {
     function callee() { if (callee.caller != nonInlinedTailCall) throw new Error(); }
     noInline(callee);

Modified: trunk/Source/_javascript_Core/tests/stress/mutual-tail-call-no-stack-overflow.js (191359 => 191360)


--- trunk/Source/_javascript_Core/tests/stress/mutual-tail-call-no-stack-overflow.js	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/Source/_javascript_Core/tests/stress/mutual-tail-call-no-stack-overflow.js	2015-10-20 22:02:37 UTC (rev 191360)
@@ -1,4 +1,3 @@
-//@ skip
 function shouldThrow(func, errorMessage) {
     var errorThrown = false;
     var error = null;

Modified: trunk/Source/_javascript_Core/tests/stress/tail-call-in-inline-cache.js (191359 => 191360)


--- trunk/Source/_javascript_Core/tests/stress/tail-call-in-inline-cache.js	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/Source/_javascript_Core/tests/stress/tail-call-in-inline-cache.js	2015-10-20 22:02:37 UTC (rev 191360)
@@ -1,4 +1,3 @@
-//@ skip
 "use strict";
 
 function tail() { }

Modified: trunk/Source/_javascript_Core/tests/stress/tail-call-no-stack-overflow.js (191359 => 191360)


--- trunk/Source/_javascript_Core/tests/stress/tail-call-no-stack-overflow.js	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/Source/_javascript_Core/tests/stress/tail-call-no-stack-overflow.js	2015-10-20 22:02:37 UTC (rev 191360)
@@ -1,4 +1,3 @@
-//@ skip
 function shouldThrow(func, errorMessage) {
     var errorThrown = false;
     var error = null;

Modified: trunk/Source/_javascript_Core/tests/stress/tail-call-recognize.js (191359 => 191360)


--- trunk/Source/_javascript_Core/tests/stress/tail-call-recognize.js	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/Source/_javascript_Core/tests/stress/tail-call-recognize.js	2015-10-20 22:02:37 UTC (rev 191360)
@@ -1,4 +1,3 @@
-//@ skip
 function callerMustBeRun() {
     if (!Object.is(callerMustBeRun.caller, runTests))
         throw Error("Wrong caller, expected run but got ", callerMustBeRun.caller);

Modified: trunk/Source/_javascript_Core/tests/stress/tail-call-varargs-no-stack-overflow.js (191359 => 191360)


--- trunk/Source/_javascript_Core/tests/stress/tail-call-varargs-no-stack-overflow.js	2015-10-20 22:00:24 UTC (rev 191359)
+++ trunk/Source/_javascript_Core/tests/stress/tail-call-varargs-no-stack-overflow.js	2015-10-20 22:02:37 UTC (rev 191360)
@@ -1,4 +1,3 @@
-//@ skip
 function shouldThrow(func, errorMessage) {
     var errorThrown = false;
     var error = null;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to