Title: [159427] trunk/Source/_javascript_Core
Revision
159427
Author
[email protected]
Date
2013-11-18 09:56:27 -0800 (Mon, 18 Nov 2013)

Log Message

Crash in virtualForThunkGenerator generated code on ARM64
https://bugs.webkit.org/show_bug.cgi?id=124447

Reviewed by Geoffrey Garen.

The baseline JIT generates slow path call code with the caller in regT0.  The DFG
generates call code with the caller in nonArgGPR0.  The virtualForThunkGenerator
generates code with the caller in nonArgGPR0.  For X86 and X86_64, regT0 and nonArgGPR0
are the same CPU register, eax.  For other platforms this isn't the case.  The same
issue exists for JSVALUE32_64 ports as well, where there also is an issue with the callee
tag registers being regT1 and nonArgGPR1 in the various locations.

Changed nonArgGPR0, nonArgGPR1 and nonArgGPR2 for X86 and X86_64 to not match up with
regT0-2.  Changing these registers will cause a crash on all ports should we have a
similar problem in the future.  Changed the DFG call generating code to use regT0 and
regT1.  Now all slow path call code is generated using regT0 and for JSVALUE32_64 regT1.
Added r12 to X86_64 as a new temp register (regT9) and moved r13 down to regT10.
The new temp register decreases the likelihood of inadvertant register overlap.

* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::emitCall):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::emitCall):
* jit/GPRInfo.h:
(JSC::GPRInfo::toRegister):
(JSC::GPRInfo::toIndex):
* jit/ThunkGenerators.cpp:
(JSC::virtualForThunkGenerator):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (159426 => 159427)


--- trunk/Source/_javascript_Core/ChangeLog	2013-11-18 17:06:49 UTC (rev 159426)
+++ trunk/Source/_javascript_Core/ChangeLog	2013-11-18 17:56:27 UTC (rev 159427)
@@ -1,3 +1,34 @@
+2013-11-18  Michael Saboff  <[email protected]>
+
+        Crash in virtualForThunkGenerator generated code on ARM64
+        https://bugs.webkit.org/show_bug.cgi?id=124447
+
+        Reviewed by Geoffrey Garen.
+
+        The baseline JIT generates slow path call code with the caller in regT0.  The DFG
+        generates call code with the caller in nonArgGPR0.  The virtualForThunkGenerator
+        generates code with the caller in nonArgGPR0.  For X86 and X86_64, regT0 and nonArgGPR0
+        are the same CPU register, eax.  For other platforms this isn't the case.  The same
+        issue exists for JSVALUE32_64 ports as well, where there also is an issue with the callee
+        tag registers being regT1 and nonArgGPR1 in the various locations.
+
+        Changed nonArgGPR0, nonArgGPR1 and nonArgGPR2 for X86 and X86_64 to not match up with
+        regT0-2.  Changing these registers will cause a crash on all ports should we have a
+        similar problem in the future.  Changed the DFG call generating code to use regT0 and
+        regT1.  Now all slow path call code is generated using regT0 and for JSVALUE32_64 regT1.
+        Added r12 to X86_64 as a new temp register (regT9) and moved r13 down to regT10.
+        The new temp register decreases the likelihood of inadvertant register overlap.
+
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::emitCall):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::emitCall):
+        * jit/GPRInfo.h:
+        (JSC::GPRInfo::toRegister):
+        (JSC::GPRInfo::toIndex):
+        * jit/ThunkGenerators.cpp:
+        (JSC::virtualForThunkGenerator):
+
 2013-11-18  Balazs Kilvady  <[email protected]>
 
         Add missing load8/branch8 with AbsoluteAddress parameter to MIPS port.

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (159426 => 159427)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2013-11-18 17:06:49 UTC (rev 159426)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2013-11-18 17:56:27 UTC (rev 159427)
@@ -701,16 +701,17 @@
 
     slowPath.link(&m_jit);
 
-    if (calleeTagGPR == GPRInfo::nonArgGPR0) {
-        if (calleePayloadGPR == GPRInfo::nonArgGPR1)
-            m_jit.swap(GPRInfo::nonArgGPR1, GPRInfo::nonArgGPR0);
+    // Callee payload needs to be in regT0, tag in regT1
+    if (calleeTagGPR == GPRInfo::regT0) {
+        if (calleePayloadGPR == GPRInfo::regT1)
+            m_jit.swap(GPRInfo::regT1, GPRInfo::regT0);
         else {
-            m_jit.move(calleeTagGPR, GPRInfo::nonArgGPR1);
-            m_jit.move(calleePayloadGPR, GPRInfo::nonArgGPR0);
+            m_jit.move(calleeTagGPR, GPRInfo::regT1);
+            m_jit.move(calleePayloadGPR, GPRInfo::regT0);
         }
     } else {
-        m_jit.move(calleePayloadGPR, GPRInfo::nonArgGPR0);
-        m_jit.move(calleeTagGPR, GPRInfo::nonArgGPR1);
+        m_jit.move(calleePayloadGPR, GPRInfo::regT0);
+        m_jit.move(calleeTagGPR, GPRInfo::regT1);
     }
     JITCompiler::Call slowCall = m_jit.nearCall();
 

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (159426 => 159427)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2013-11-18 17:06:49 UTC (rev 159426)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2013-11-18 17:56:27 UTC (rev 159427)
@@ -723,7 +723,7 @@
     
     slowPath.link(&m_jit);
     
-    m_jit.move(calleeGPR, GPRInfo::nonArgGPR0);
+    m_jit.move(calleeGPR, GPRInfo::regT0); // Callee needs to be in regT0
     JITCompiler::Call slowCall = m_jit.nearCall();
     
     done.link(&m_jit);

Modified: trunk/Source/_javascript_Core/jit/GPRInfo.h (159426 => 159427)


--- trunk/Source/_javascript_Core/jit/GPRInfo.h	2013-11-18 17:06:49 UTC (rev 159426)
+++ trunk/Source/_javascript_Core/jit/GPRInfo.h	2013-11-18 17:56:27 UTC (rev 159427)
@@ -305,9 +305,9 @@
     // These constants provide the names for the general purpose argument & return value registers.
     static const GPRReg argumentGPR0 = X86Registers::ecx; // regT2
     static const GPRReg argumentGPR1 = X86Registers::edx; // regT1
-    static const GPRReg nonArgGPR0 = X86Registers::eax; // regT0
-    static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3
-    static const GPRReg nonArgGPR2 = X86Registers::esi; // regT4
+    static const GPRReg nonArgGPR0 = X86Registers::esi; // regT4
+    static const GPRReg nonArgGPR1 = X86Registers::eax; // regT0
+    static const GPRReg nonArgGPR2 = X86Registers::ebx; // regT3
     static const GPRReg returnValueGPR = X86Registers::eax; // regT0
     static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1
     static const GPRReg nonPreservedNonReturnGPR = X86Registers::ecx;
@@ -355,7 +355,7 @@
 class GPRInfo {
 public:
     typedef GPRReg RegisterType;
-    static const unsigned numberOfRegisters = 10;
+    static const unsigned numberOfRegisters = 11;
     static const unsigned numberOfArgumentRegisters = NUMBER_OF_ARGUMENT_REGISTERS;
 
     // Note: regT3 is required to be callee-preserved.
@@ -375,7 +375,8 @@
     static const GPRReg regT6 = X86Registers::r8;
     static const GPRReg regT7 = X86Registers::r9;
     static const GPRReg regT8 = X86Registers::r10;
-    static const GPRReg regT9 = X86Registers::r13;
+    static const GPRReg regT9 = X86Registers::r12;
+    static const GPRReg regT10 = X86Registers::r13;
     // These constants provide the names for the general purpose argument & return value registers.
 #if !OS(WINDOWS)
     static const GPRReg argumentGPR0 = X86Registers::edi; // regT4
@@ -390,9 +391,9 @@
     static const GPRReg argumentGPR2 = X86Registers::r8; // regT6
     static const GPRReg argumentGPR3 = X86Registers::r9; // regT7
 #endif
-    static const GPRReg nonArgGPR0 = X86Registers::eax; // regT0
+    static const GPRReg nonArgGPR0 = X86Registers::r10; // regT8
     static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3
-    static const GPRReg nonArgGPR2 = X86Registers::r10; // regT8
+    static const GPRReg nonArgGPR2 = X86Registers::r12; // regT9
     static const GPRReg returnValueGPR = X86Registers::eax; // regT0
     static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1
     static const GPRReg nonPreservedNonReturnGPR = X86Registers::esi;
@@ -400,7 +401,7 @@
     static GPRReg toRegister(unsigned index)
     {
         ASSERT(index < numberOfRegisters);
-        static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7, regT8, regT9 };
+        static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7, regT8, regT9, regT10 };
         return registerForIndex[index];
     }
     
@@ -419,7 +420,7 @@
     {
         ASSERT(reg != InvalidGPRReg);
         ASSERT(static_cast<int>(reg) < 16);
-        static const unsigned indexForRegister[16] = { 0, 2, 1, 3, InvalidIndex, InvalidIndex, 5, 4, 6, 7, 8, InvalidIndex, InvalidIndex, 9, InvalidIndex, InvalidIndex };
+        static const unsigned indexForRegister[16] = { 0, 2, 1, 3, InvalidIndex, InvalidIndex, 5, 4, 6, 7, 8, InvalidIndex, 9, 10, InvalidIndex, InvalidIndex };
         return indexForRegister[reg];
     }
 

Modified: trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp (159426 => 159427)


--- trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp	2013-11-18 17:06:49 UTC (rev 159426)
+++ trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp	2013-11-18 17:56:27 UTC (rev 159427)
@@ -147,6 +147,7 @@
 static MacroAssemblerCodeRef virtualForThunkGenerator(
     VM* vm, CodeSpecializationKind kind)
 {
+    // The callee is in regT0 (for JSVALUE32_64, the tag is in regT1).
     // The return address is on the stack, or in the link register. We will hence
     // jump to the callee, or save the return address to the call frame while we
     // make a C++ function call to the appropriate JIT operation.
@@ -161,14 +162,14 @@
 #if USE(JSVALUE64)
     slowCase.append(
         jit.branchTest64(
-            CCallHelpers::NonZero, GPRInfo::nonArgGPR0, GPRInfo::tagMaskRegister));
+            CCallHelpers::NonZero, GPRInfo::regT0, GPRInfo::tagMaskRegister));
 #else
     slowCase.append(
         jit.branch32(
-            CCallHelpers::NotEqual, GPRInfo::nonArgGPR1,
+            CCallHelpers::NotEqual, GPRInfo::regT1,
             CCallHelpers::TrustedImm32(JSValue::CellTag)));
 #endif
-    jit.loadPtr(CCallHelpers::Address(GPRInfo::nonArgGPR0, JSCell::structureOffset()), GPRInfo::nonArgGPR2);
+    jit.loadPtr(CCallHelpers::Address(GPRInfo::regT0, JSCell::structureOffset()), GPRInfo::nonArgGPR2);
     slowCase.append(
         jit.branchPtr(
             CCallHelpers::NotEqual,
@@ -178,7 +179,7 @@
     // Now we know we have a JSFunction.
     
     jit.loadPtr(
-        CCallHelpers::Address(GPRInfo::nonArgGPR0, JSFunction::offsetOfExecutable()),
+        CCallHelpers::Address(GPRInfo::regT0, JSFunction::offsetOfExecutable()),
         GPRInfo::nonArgGPR2);
     slowCase.append(
         jit.branch32(
@@ -191,17 +192,17 @@
     // call.
     
     jit.loadPtr(
-        CCallHelpers::Address(GPRInfo::nonArgGPR0, JSFunction::offsetOfScopeChain()),
-        GPRInfo::nonArgGPR1);
+        CCallHelpers::Address(GPRInfo::regT0, JSFunction::offsetOfScopeChain()),
+        GPRInfo::regT1);
 #if USE(JSVALUE64)
     jit.store64(
-        GPRInfo::nonArgGPR1,
+        GPRInfo::regT1,
         CCallHelpers::Address(
             GPRInfo::callFrameRegister,
             static_cast<ptrdiff_t>(sizeof(Register)) * JSStack::ScopeChain));
 #else
     jit.storePtr(
-        GPRInfo::nonArgGPR1,
+        GPRInfo::regT1,
         CCallHelpers::Address(
             GPRInfo::callFrameRegister,
             static_cast<ptrdiff_t>(sizeof(Register)) * JSStack::ScopeChain +
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to