FTL OSR exit shouldn't make X86-specific assumptions
https://bugs.webkit.org/show_bug.cgi?id=128890
Reviewed by Mark Hahnenberg.
Mostly this is about not using push/pop, but instead using the more abstract pushToSave() and popToRestore() while reflecting on the stack alignment.
* assembler/MacroAssembler.h:
(JSC::MacroAssembler::pushToSaveImmediateWithoutTouchingRegisters):
(JSC::MacroAssembler::pushToSaveByteOffset):
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::pushToSaveImmediateWithoutTouchingRegisters):
(JSC::MacroAssemblerARM64::pushToSaveByteOffset):
* ftl/FTLExitThunkGenerator.cpp:
(JSC::FTL::ExitThunkGenerator::emitThunk):
* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileStub):
* ftl/FTLThunks.cpp:
(JSC::FTL::osrExitGenerationThunkGenerator):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@164228 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 78af889..82f71e5 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,25 @@
+2014-02-16 Filip Pizlo <fpizlo@apple.com>
+
+ FTL OSR exit shouldn't make X86-specific assumptions
+ https://bugs.webkit.org/show_bug.cgi?id=128890
+
+ Reviewed by Mark Hahnenberg.
+
+ Mostly this is about not using push/pop, but instead using the more abstract pushToSave() and popToRestore() while reflecting on the stack alignment.
+
+ * assembler/MacroAssembler.h:
+ (JSC::MacroAssembler::pushToSaveImmediateWithoutTouchingRegisters):
+ (JSC::MacroAssembler::pushToSaveByteOffset):
+ * assembler/MacroAssemblerARM64.h:
+ (JSC::MacroAssemblerARM64::pushToSaveImmediateWithoutTouchingRegisters):
+ (JSC::MacroAssemblerARM64::pushToSaveByteOffset):
+ * ftl/FTLExitThunkGenerator.cpp:
+ (JSC::FTL::ExitThunkGenerator::emitThunk):
+ * ftl/FTLOSRExitCompiler.cpp:
+ (JSC::FTL::compileStub):
+ * ftl/FTLThunks.cpp:
+ (JSC::FTL::osrExitGenerationThunkGenerator):
+
2014-02-17 Filip Pizlo <fpizlo@apple.com>
Unreviewed, make this test pass without DFG. It was assuming that you always have DFG
diff --git a/Source/JavaScriptCore/assembler/MacroAssembler.h b/Source/JavaScriptCore/assembler/MacroAssembler.h
index 57fc3a6..35b2ba7 100644
--- a/Source/JavaScriptCore/assembler/MacroAssembler.h
+++ b/Source/JavaScriptCore/assembler/MacroAssembler.h
@@ -258,6 +258,10 @@
{
push(src);
}
+ void pushToSaveImmediateWithoutTouchingRegisters(TrustedImm32 imm)
+ {
+ push(imm);
+ }
void popToRestore(RegisterID dest)
{
pop(dest);
@@ -272,6 +276,8 @@
loadDouble(stackPointerRegister, dest);
addPtr(TrustedImm32(sizeof(double)), stackPointerRegister);
}
+
+ static ptrdiff_t pushToSaveByteOffset() { return sizeof(void*); }
#endif // !CPU(ARM64)
#if CPU(X86_64) || CPU(ARM64)
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h b/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
index 42857b4..fbc9461 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
@@ -1459,6 +1459,15 @@
{
m_assembler.str<64>(src, ARM64Registers::sp, PreIndex(-16));
}
+
+ void pushToSaveImmediateWithoutTouchingRegisters(TrustedImm32 imm)
+ {
+ RegisterID reg = dataTempRegister;
+ pushPair(reg, reg);
+ move(imm, reg);
+ store64(reg, stackPointerRegister);
+ load64(Address(stackPointerRegister, 8), reg);
+ }
void pushToSave(Address address)
{
@@ -1484,6 +1493,7 @@
storeDouble(src, stackPointerRegister);
}
+ static ptrdiff_t pushToSaveByteOffset() { return 16; }
// Register move operations:
diff --git a/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp b/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp
index 86c8723..3d40bdf 100644
--- a/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp
+++ b/Source/JavaScriptCore/ftl/FTLExitThunkGenerator.cpp
@@ -51,7 +51,7 @@
OSRExitCompilationInfo& info = m_state.finalizer->osrExit[index];
info.m_thunkLabel = label();
- push(TrustedImm32(index));
+ pushToSaveImmediateWithoutTouchingRegisters(TrustedImm32(index));
info.m_thunkJump = patchableJump();
m_didThings = true;
diff --git a/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp b/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp
index f37a6f6..c1eb2f9 100644
--- a/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp
+++ b/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp
@@ -70,14 +70,14 @@
char* registerScratch = bitwise_cast<char*>(scratch + exit.m_values.size());
uint64_t* unwindScratch = bitwise_cast<uint64_t*>(registerScratch + requiredScratchMemorySizeInBytes());
- // 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);
+ // Note that we come in here, the stack used to be as LLVM left it except that someone called pushToSave().
+ // We don't care about the value they saved. But, we do appreciate the fact that they did it, because we use
+ // that slot for saveAllRegisters().
+
saveAllRegisters(jit, registerScratch);
// Bring the stack back into a sane form.
- jit.pop(GPRInfo::regT0);
- jit.pop(GPRInfo::regT0);
+ jit.popToRestore(GPRInfo::regT0);
if (vm->m_perBytecodeProfiler && codeBlock->jitCode()->dfgCommon()->compilation) {
Profiler::Database& database = *vm->m_perBytecodeProfiler;
diff --git a/Source/JavaScriptCore/ftl/FTLThunks.cpp b/Source/JavaScriptCore/ftl/FTLThunks.cpp
index e25407f..0c306c6 100644
--- a/Source/JavaScriptCore/ftl/FTLThunks.cpp
+++ b/Source/JavaScriptCore/ftl/FTLThunks.cpp
@@ -45,11 +45,20 @@
// Note that the "return address" will be the OSR exit ID.
+ ptrdiff_t stackMisalignment = MacroAssembler::pushToSaveByteOffset();
+
// Pretend that we're a C call frame.
- jit.push(MacroAssembler::framePointerRegister);
+ jit.pushToSave(MacroAssembler::framePointerRegister);
jit.move(MacroAssembler::stackPointerRegister, MacroAssembler::framePointerRegister);
- jit.push(GPRInfo::regT0);
- jit.push(GPRInfo::regT0);
+ stackMisalignment += MacroAssembler::pushToSaveByteOffset();
+
+ // Now create ourselves enough stack space to give saveAllRegisters() a scratch slot.
+ unsigned numberOfRequiredPops = 0;
+ do {
+ jit.pushToSave(GPRInfo::regT0);
+ stackMisalignment += MacroAssembler::pushToSaveByteOffset();
+ numberOfRequiredPops++;
+ } while (stackMisalignment % stackAlignmentBytes());
ScratchBuffer* scratchBuffer = vm->scratchBufferForSize(requiredScratchMemorySizeInBytes());
char* buffer = static_cast<char*>(scratchBuffer->dataBuffer());
@@ -61,7 +70,7 @@
jit.storePtr(MacroAssembler::TrustedImmPtr(requiredScratchMemorySizeInBytes()), GPRInfo::nonArgGPR1);
jit.loadPtr(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
- jit.peek(GPRInfo::argumentGPR1, 3);
+ jit.peek(GPRInfo::argumentGPR1, (stackMisalignment / sizeof(void*)) - 1);
MacroAssembler::Call functionCall = jit.call();
// At this point we want to make a tail call to what was returned to us in the
@@ -76,9 +85,9 @@
jit.storePtr(MacroAssembler::TrustedImmPtr(0), GPRInfo::regT1);
// Prepare for tail call.
- jit.pop(GPRInfo::regT1);
- jit.pop(GPRInfo::regT1);
- jit.pop(MacroAssembler::framePointerRegister);
+ while (numberOfRequiredPops--)
+ jit.popToRestore(GPRInfo::regT1);
+ jit.popToRestore(MacroAssembler::framePointerRegister);
// At this point we're sitting on the return address - so if we did a jump right now, the
// tail-callee would be happy. Instead we'll stash the callee in the return address and then