Fix handling of indirect stackmap locations in FTL OSR exit
https://bugs.webkit.org/show_bug.cgi?id=122666

Reviewed by Mark Hahnenberg.
        
With this change, the llvm.webkit.stackmap-based OSR exit only fails one test, down from
five tests previously.

* ftl/FTLLocation.cpp:
(JSC::FTL::Location::gpr): It's OK to call this method when kind() == Indirect, so asserting that isGPR() is wrong; change to assert that involvesGPR().
(JSC::FTL::Location::restoreInto): Stack-related registers aren't saved to the scratch buffer, so use them directly.
* ftl/FTLLocation.h: Add comment about requirements for stack layout.
* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileStubWithOSRExitStackmap): Make enough room on the stack so that saveAllRegisters() has a scratchpad to save things to. Without this, saveAllRegisters() may clobber a spilled value.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@157326 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index c47234a..c5c7d06 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,20 @@
+2013-10-11  Filip Pizlo  <fpizlo@apple.com>
+
+        Fix handling of indirect stackmap locations in FTL OSR exit
+        https://bugs.webkit.org/show_bug.cgi?id=122666
+
+        Reviewed by Mark Hahnenberg.
+        
+        With this change, the llvm.webkit.stackmap-based OSR exit only fails one test, down from
+        five tests previously.
+
+        * ftl/FTLLocation.cpp:
+        (JSC::FTL::Location::gpr): It's OK to call this method when kind() == Indirect, so asserting that isGPR() is wrong; change to assert that involvesGPR().
+        (JSC::FTL::Location::restoreInto): Stack-related registers aren't saved to the scratch buffer, so use them directly.
+        * ftl/FTLLocation.h: Add comment about requirements for stack layout.
+        * ftl/FTLOSRExitCompiler.cpp:
+        (JSC::FTL::compileStubWithOSRExitStackmap): Make enough room on the stack so that saveAllRegisters() has a scratchpad to save things to. Without this, saveAllRegisters() may clobber a spilled value.
+
 2013-10-11  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r157307.
diff --git a/Source/JavaScriptCore/ftl/FTLLocation.cpp b/Source/JavaScriptCore/ftl/FTLLocation.cpp
index fbabf57..cd1084e 100644
--- a/Source/JavaScriptCore/ftl/FTLLocation.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLocation.cpp
@@ -87,7 +87,7 @@
     // for example, the architecture encodes CX as 1 and DX as 2 while Dwarf does the
     // opposite. Hence we need the switch.
     
-    ASSERT(isGPR());
+    ASSERT(involvesGPR());
     
     switch (dwarfRegNum()) {
     case 0:
@@ -127,6 +127,12 @@
 void Location::restoreInto(MacroAssembler& jit, char* savedRegisters, GPRReg result) const
 {
     if (isGPR()) {
+        if (MacroAssembler::isStackRelated(gpr())) {
+            // These don't get saved.
+            jit.move(gpr(), result);
+            return;
+        }
+        
         jit.load64(savedRegisters + offsetOfGPR(gpr()), result);
         return;
     }
@@ -143,6 +149,12 @@
         return;
         
     case Indirect:
+        if (MacroAssembler::isStackRelated(gpr())) {
+            // These don't get saved.
+            jit.load64(MacroAssembler::Address(gpr(), offset()), result);
+            return;
+        }
+        
         jit.load64(savedRegisters + offsetOfGPR(gpr()), result);
         jit.load64(MacroAssembler::Address(result, offset()), result);
         return;
diff --git a/Source/JavaScriptCore/ftl/FTLLocation.h b/Source/JavaScriptCore/ftl/FTLLocation.h
index 74fcf16..2ec22f3 100644
--- a/Source/JavaScriptCore/ftl/FTLLocation.h
+++ b/Source/JavaScriptCore/ftl/FTLLocation.h
@@ -155,7 +155,11 @@
     
     // Assuming that all registers are saved to the savedRegisters buffer according
     // to FTLSaveRestore convention, this loads the value into the given register.
-    // The code that this generates isn't exactly super fast.
+    // The code that this generates isn't exactly super fast. This assumes that FP
+    // and SP contain the same values that they would have contained in the original
+    // frame. If we did push things onto the stack then probably we'll have to change
+    // the signature of this method to take a stack offset for stack-relative
+    // indirects.
     void restoreInto(MacroAssembler&, char* savedRegisters, GPRReg result) const;
     
 private:
diff --git a/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp b/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp
index c596832..a3a7c3b 100644
--- a/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp
+++ b/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp
@@ -67,10 +67,17 @@
     EncodedJSValue* scratch = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
     char* registerScratch = bitwise_cast<char*>(scratch + exit.m_values.size());
     
+    // Make sure that saveAllRegisters() has a place on top of the stack to spill things. That
+    // function expects to be able to use top of stack for scratch memory.
+    jit.push(GPRInfo::regT0);
     saveAllRegisters(jit, registerScratch);
     
     // Bring the stack back into a sane form.
     jit.pop(GPRInfo::regT0);
+    jit.pop(GPRInfo::regT0);
+    
+    // The remaining code assumes that SP/FP are in the same state that they were in the FTL's
+    // call frame.
     
     // Get the call frame and tag thingies.
     record->locations[0].restoreInto(jit, jitCode->stackmaps, registerScratch, GPRInfo::callFrameRegister);