+2015-09-17 Sukolsak Sakshuwong <sukolsak@gmail.com>
+
+ Save and restore callee save registers in WebAssembly
+ https://bugs.webkit.org/show_bug.cgi?id=149247
+
+ Reviewed by Michael Saboff.
+
+ Save callee save registers when entering WebAssembly functions
+ and restore them when returning.
+
+ * jit/RegisterSet.cpp:
+ (JSC::RegisterSet::webAssemblyCalleeSaveRegisters):
+ * jit/RegisterSet.h:
+ * wasm/WASMFunctionCompiler.h:
+ (JSC::WASMFunctionCompiler::startFunction):
+ (JSC::WASMFunctionCompiler::endFunction):
+ (JSC::WASMFunctionCompiler::buildReturn):
+ (JSC::WASMFunctionCompiler::localAddress):
+ (JSC::WASMFunctionCompiler::temporaryAddress):
+ (JSC::WASMFunctionCompiler::boxArgumentsAndAdjustStackPointer):
+ (JSC::WASMFunctionCompiler::callAndUnboxResult):
+
2015-09-16 Sukolsak Sakshuwong <sukolsak@gmail.com>
Implement indirect calls in WebAssembly
return result;
}
+#if ENABLE(WEBASSEMBLY)
+RegisterSet RegisterSet::webAssemblyCalleeSaveRegisters()
+{
+ RegisterSet result;
+#if CPU(X86)
+#elif CPU(X86_64)
+#if !OS(WINDOWS)
+ ASSERT(GPRInfo::regCS3 == GPRInfo::tagTypeNumberRegister);
+ ASSERT(GPRInfo::regCS4 == GPRInfo::tagMaskRegister);
+ result.set(GPRInfo::regCS3);
+ result.set(GPRInfo::regCS4);
+#else
+ ASSERT(GPRInfo::regCS5 == GPRInfo::tagTypeNumberRegister);
+ ASSERT(GPRInfo::regCS6 == GPRInfo::tagMaskRegister);
+ result.set(GPRInfo::regCS5);
+ result.set(GPRInfo::regCS6);
+#endif
+#elif CPU(ARM_THUMB2)
+#elif CPU(ARM_TRADITIONAL)
+#elif CPU(ARM64)
+ ASSERT(GPRInfo::regCS8 == GPRInfo::tagTypeNumberRegister);
+ ASSERT(GPRInfo::regCS9 == GPRInfo::tagMaskRegister);
+ result.set(GPRInfo::regCS8);
+ result.set(GPRInfo::regCS9);
+#elif CPU(MIPS)
+#elif CPU(SH4)
+#else
+ UNREACHABLE_FOR_PLATFORM();
+#endif
+ return result;
+}
+#endif
+
RegisterSet RegisterSet::allGPRs()
{
RegisterSet result;
void startFunction(const Vector<WASMType>& arguments, uint32_t numberOfI32LocalVariables, uint32_t numberOfF32LocalVariables, uint32_t numberOfF64LocalVariables)
{
+ m_calleeSaveSpace = WTF::roundUpToMultipleOf(sizeof(StackSlot), RegisterSet::webAssemblyCalleeSaveRegisters().numberOfSetRegisters() * sizeof(void*));
+ m_codeBlock->setCalleeSaveRegisters(RegisterSet::webAssemblyCalleeSaveRegisters());
+
emitFunctionPrologue();
emitPutImmediateToCallFrameHeader(m_codeBlock, JSStack::CodeBlock);
m_beginLabel = label();
- addPtr(TrustedImm32(-WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot) - maxFrameExtentForSlowPathCall), GPRInfo::callFrameRegister, GPRInfo::regT1);
+ addPtr(TrustedImm32(-m_calleeSaveSpace - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot) - maxFrameExtentForSlowPathCall), GPRInfo::callFrameRegister, GPRInfo::regT1);
m_stackOverflow = branchPtr(Above, AbsoluteAddress(m_vm->addressOfStackLimit()), GPRInfo::regT1);
move(GPRInfo::regT1, stackPointerRegister);
checkStackPointerAlignment();
+ emitSaveCalleeSaves();
+ emitMaterializeTagCheckRegisters();
+
m_numberOfLocals = arguments.size() + numberOfI32LocalVariables + numberOfF32LocalVariables + numberOfF64LocalVariables;
unsigned localIndex = 0;
JSValueRegs returnValueRegs(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
#endif
moveTrustedValue(jsUndefined(), returnValueRegs);
+ emitRestoreCalleeSaves();
emitFunctionEpilogue();
ret();
if (!m_exceptionChecks.empty()) {
m_exceptionChecks.link(this);
+ copyCalleeSavesToVMCalleeSavesBuffer();
+
// lookupExceptionHandler is passed two arguments, the VM and the exec (the CallFrame*).
move(TrustedImmPtr(vm()), GPRInfo::argumentGPR0);
move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
default:
ASSERT_NOT_REACHED();
}
+ emitRestoreCalleeSaves();
emitFunctionEpilogue();
ret();
}
Address localAddress(unsigned localIndex) const
{
ASSERT(localIndex < m_numberOfLocals);
- return Address(GPRInfo::callFrameRegister, -(localIndex + 1) * sizeof(StackSlot));
+ return Address(GPRInfo::callFrameRegister, -m_calleeSaveSpace - (localIndex + 1) * sizeof(StackSlot));
}
Address temporaryAddress(unsigned temporaryIndex) const
{
ASSERT(m_numberOfLocals + temporaryIndex < m_stackHeight);
- return Address(GPRInfo::callFrameRegister, -(m_numberOfLocals + temporaryIndex + 1) * sizeof(StackSlot));
+ return Address(GPRInfo::callFrameRegister, -m_calleeSaveSpace - (m_numberOfLocals + temporaryIndex + 1) * sizeof(StackSlot));
}
void appendCall(const FunctionPtr& function)
void boxArgumentsAndAdjustStackPointer(const Vector<WASMType>& arguments)
{
size_t argumentCount = arguments.size();
- int stackOffset = -WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_numberOfLocals + m_tempStackTop + argumentCount + 1 + JSStack::CallFrameHeaderSize);
+ int stackOffset = -m_calleeSaveSpace - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_numberOfLocals + m_tempStackTop + argumentCount + 1 + JSStack::CallFrameHeaderSize);
storeTrustedValue(jsUndefined(), Address(GPRInfo::callFrameRegister, (stackOffset + CallFrame::thisArgumentOffset()) * sizeof(Register)));
m_callCompilationInfo.last().callReturnLocation = emitNakedCall(m_vm->getCTIStub(linkCallThunkGenerator).code());
end.link(this);
- addPtr(TrustedImm32(-WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot) - maxFrameExtentForSlowPathCall), GPRInfo::callFrameRegister, stackPointerRegister);
+ addPtr(TrustedImm32(-m_calleeSaveSpace - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot) - maxFrameExtentForSlowPathCall), GPRInfo::callFrameRegister, stackPointerRegister);
checkStackPointerAlignment();
switch (returnType) {
unsigned m_stackHeight;
unsigned m_numberOfLocals;
unsigned m_tempStackTop { 0 };
+ unsigned m_calleeSaveSpace;
Vector<JumpTarget> m_breakTargets;
Vector<JumpTarget> m_continueTargets;