#include "config.h"
#include "FTLThunks.h"
#if ENABLE(FTL_JIT)
#include "AssemblyHelpers.h"
#include "FPRInfo.h"
#include "FTLOSRExitCompiler.h"
#include "FTLSaveRestore.h"
#include "GPRInfo.h"
#include "LinkBuffer.h"
namespace JSC { namespace FTL {
using namespace DFG;
MacroAssemblerCodeRef osrExitGenerationThunkGenerator(VM* vm)
{
AssemblyHelpers jit(vm, 0);
ptrdiff_t stackMisalignment = MacroAssembler::pushToSaveByteOffset();
jit.pushToSave(MacroAssembler::framePointerRegister);
jit.move(MacroAssembler::stackPointerRegister, MacroAssembler::framePointerRegister);
stackMisalignment += MacroAssembler::pushToSaveByteOffset();
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());
saveAllRegisters(jit, buffer);
jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::nonArgGPR1);
jit.storePtr(MacroAssembler::TrustedImmPtr(requiredScratchMemorySizeInBytes()), GPRInfo::nonArgGPR1);
jit.loadPtr(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
jit.peek(
GPRInfo::argumentGPR1,
(stackMisalignment - MacroAssembler::pushToSaveByteOffset()) / sizeof(void*));
MacroAssembler::Call functionCall = jit.call();
jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0);
jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT1);
jit.storePtr(MacroAssembler::TrustedImmPtr(0), GPRInfo::regT1);
while (numberOfRequiredPops--)
jit.popToRestore(GPRInfo::regT1);
jit.popToRestore(MacroAssembler::framePointerRegister);
jit.restoreReturnAddressBeforeReturn(GPRInfo::regT0);
restoreAllRegisters(jit, buffer);
jit.ret();
LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
patchBuffer.link(functionCall, compileFTLOSRExit);
return FINALIZE_CODE(patchBuffer, ("FTL OSR exit generation thunk"));
}
static void registerClobberCheck(AssemblyHelpers& jit, RegisterSet dontClobber)
{
if (!Options::clobberAllRegsInFTLICSlowPath())
return;
RegisterSet clobber = RegisterSet::allRegisters();
clobber.exclude(RegisterSet::reservedHardwareRegisters());
clobber.exclude(RegisterSet::stackRegisters());
clobber.exclude(RegisterSet::calleeSaveRegisters());
clobber.exclude(dontClobber);
GPRReg someGPR;
for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
if (!clobber.get(reg) || !reg.isGPR())
continue;
jit.move(AssemblyHelpers::TrustedImm32(0x1337beef), reg.gpr());
someGPR = reg.gpr();
}
for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
if (!clobber.get(reg) || !reg.isFPR())
continue;
jit.move64ToDouble(someGPR, reg.fpr());
}
}
MacroAssemblerCodeRef slowPathCallThunkGenerator(VM& vm, const SlowPathCallKey& key)
{
AssemblyHelpers jit(&vm, 0);
size_t currentOffset = key.offset() + sizeof(void*);
#if CPU(X86) || CPU(X86_64)
currentOffset += sizeof(void*);
#endif
for (MacroAssembler::RegisterID reg = MacroAssembler::firstRegister(); reg <= MacroAssembler::lastRegister(); reg = static_cast<MacroAssembler::RegisterID>(reg + 1)) {
if (!key.usedRegisters().get(reg))
continue;
jit.storePtr(reg, AssemblyHelpers::Address(MacroAssembler::stackPointerRegister, currentOffset));
currentOffset += sizeof(void*);
}
for (MacroAssembler::FPRegisterID reg = MacroAssembler::firstFPRegister(); reg <= MacroAssembler::lastFPRegister(); reg = static_cast<MacroAssembler::FPRegisterID>(reg + 1)) {
if (!key.usedRegisters().get(reg))
continue;
jit.storeDouble(reg, AssemblyHelpers::Address(MacroAssembler::stackPointerRegister, currentOffset));
currentOffset += sizeof(double);
}
jit.preserveReturnAddressAfterCall(GPRInfo::nonArgGPR0);
jit.storePtr(GPRInfo::nonArgGPR0, AssemblyHelpers::Address(MacroAssembler::stackPointerRegister, key.offset()));
registerClobberCheck(jit, key.argumentRegisters());
AssemblyHelpers::Call call = jit.call();
jit.loadPtr(AssemblyHelpers::Address(MacroAssembler::stackPointerRegister, key.offset()), GPRInfo::nonPreservedNonReturnGPR);
jit.restoreReturnAddressBeforeReturn(GPRInfo::nonPreservedNonReturnGPR);
for (MacroAssembler::FPRegisterID reg = MacroAssembler::lastFPRegister(); ; reg = static_cast<MacroAssembler::FPRegisterID>(reg - 1)) {
if (key.usedRegisters().get(reg)) {
currentOffset -= sizeof(double);
jit.loadDouble(AssemblyHelpers::Address(MacroAssembler::stackPointerRegister, currentOffset), reg);
}
if (reg == MacroAssembler::firstFPRegister())
break;
}
for (MacroAssembler::RegisterID reg = MacroAssembler::lastRegister(); ; reg = static_cast<MacroAssembler::RegisterID>(reg - 1)) {
if (key.usedRegisters().get(reg)) {
currentOffset -= sizeof(void*);
jit.loadPtr(AssemblyHelpers::Address(MacroAssembler::stackPointerRegister, currentOffset), reg);
}
if (reg == MacroAssembler::firstRegister())
break;
}
jit.ret();
LinkBuffer patchBuffer(vm, jit, GLOBAL_THUNK_ID);
patchBuffer.link(call, FunctionPtr(key.callTarget()));
return FINALIZE_CODE(patchBuffer, ("FTL slow path call thunk for %s", toCString(key).data()));
}
} }
#endif // ENABLE(FTL_JIT)