RegisterPreservationWrapperGenerator.cpp [plain text]
#include "config.h"
#include "RegisterPreservationWrapperGenerator.h"
#if ENABLE(JIT)
#include "AssemblyHelpers.h"
#include "LinkBuffer.h"
#include "JSCInlines.h"
#include "StackAlignment.h"
namespace JSC {
RegisterSet registersToPreserve()
{
RegisterSet calleeSaves = RegisterSet::calleeSaveRegisters();
calleeSaves.clear(GPRInfo::callFrameRegister);
return calleeSaves;
}
ptrdiff_t registerPreservationOffset()
{
unsigned numberOfCalleeSaves = registersToPreserve().numberOfSetRegisters();
unsigned numberOfValuesToSave = numberOfCalleeSaves + 1;
unsigned numberOfNewStackSlots =
WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numberOfValuesToSave);
return sizeof(Register) * numberOfNewStackSlots;
}
MacroAssemblerCodeRef generateRegisterPreservationWrapper(VM& vm, ExecutableBase* executable, MacroAssemblerCodePtr target)
{
#if ENABLE(FTL_JIT)
RegisterSet toSave = registersToPreserve();
ptrdiff_t offset = registerPreservationOffset();
AssemblyHelpers jit(&vm, 0);
jit.preserveReturnAddressAfterCall(GPRInfo::regT1);
jit.load32(
AssemblyHelpers::Address(
AssemblyHelpers::stackPointerRegister,
(JSStack::ArgumentCount - JSStack::CallerFrameAndPCSize) * sizeof(Register) + PayloadOffset),
GPRInfo::regT2);
jit.subPtr(AssemblyHelpers::TrustedImm32(offset), AssemblyHelpers::stackPointerRegister);
jit.add32(
AssemblyHelpers::TrustedImm32(
JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize),
GPRInfo::regT2);
ASSERT(!toSave.get(GPRInfo::regT4));
jit.move(AssemblyHelpers::stackPointerRegister, GPRInfo::regT4);
AssemblyHelpers::Label loop = jit.label();
jit.sub32(AssemblyHelpers::TrustedImm32(1), GPRInfo::regT2);
jit.load64(AssemblyHelpers::Address(GPRInfo::regT4, offset), GPRInfo::regT0);
jit.store64(GPRInfo::regT0, GPRInfo::regT4);
jit.addPtr(AssemblyHelpers::TrustedImm32(sizeof(Register)), GPRInfo::regT4);
jit.branchTest32(AssemblyHelpers::NonZero, GPRInfo::regT2).linkTo(loop, &jit);
ptrdiff_t currentOffset = 0;
jit.storePtr(GPRInfo::regT1, AssemblyHelpers::Address(GPRInfo::regT4, currentOffset));
for (GPRReg gpr = AssemblyHelpers::firstRegister(); gpr <= AssemblyHelpers::lastRegister(); gpr = static_cast<GPRReg>(gpr + 1)) {
if (!toSave.get(gpr))
continue;
currentOffset += sizeof(Register);
jit.store64(gpr, AssemblyHelpers::Address(GPRInfo::regT4, currentOffset));
}
for (FPRReg fpr = AssemblyHelpers::firstFPRegister(); fpr <= AssemblyHelpers::lastFPRegister(); fpr = static_cast<FPRReg>(fpr + 1)) {
if (!toSave.get(fpr))
continue;
currentOffset += sizeof(Register);
jit.storeDouble(fpr, AssemblyHelpers::Address(GPRInfo::regT4, currentOffset));
}
jit.move(AssemblyHelpers::TrustedImm64(TagTypeNumber), GPRInfo::tagTypeNumberRegister);
jit.add64(AssemblyHelpers::TrustedImm32(TagMask - TagTypeNumber), GPRInfo::tagTypeNumberRegister, GPRInfo::tagMaskRegister);
jit.move(
AssemblyHelpers::TrustedImmPtr(
vm.getCTIStub(registerRestorationThunkGenerator).code().executableAddress()),
GPRInfo::nonArgGPR0);
jit.restoreReturnAddressBeforeReturn(GPRInfo::nonArgGPR0);
AssemblyHelpers::Jump jump = jit.jump();
LinkBuffer linkBuffer(vm, jit, GLOBAL_THUNK_ID);
linkBuffer.link(jump, CodeLocationLabel(target));
if (Options::verboseFTLToJSThunk())
dataLog("Need a thunk for calls from FTL to non-FTL version of ", *executable, "\n");
return FINALIZE_DFG_CODE(linkBuffer, ("Register preservation wrapper for %s/%s, %p", toCString(executable->hashFor(CodeForCall)).data(), toCString(executable->hashFor(CodeForConstruct)).data(), target.executableAddress()));
#else // ENABLE(FTL_JIT)
UNUSED_PARAM(vm);
UNUSED_PARAM(executable);
UNUSED_PARAM(target);
UNREACHABLE_FOR_PLATFORM();
return MacroAssemblerCodeRef();
#endif // ENABLE(FTL_JIT)
}
static void generateRegisterRestoration(AssemblyHelpers& jit)
{
#if ENABLE(FTL_JIT)
RegisterSet toSave = registersToPreserve();
ptrdiff_t offset = registerPreservationOffset();
ASSERT(!toSave.get(GPRInfo::regT4));
jit.load32(
AssemblyHelpers::Address(
AssemblyHelpers::stackPointerRegister,
(JSStack::ArgumentCount - JSStack::CallerFrameAndPCSize) * sizeof(Register) + PayloadOffset),
GPRInfo::regT4);
jit.move(GPRInfo::regT4, GPRInfo::regT2);
jit.lshift32(AssemblyHelpers::TrustedImm32(3), GPRInfo::regT2);
jit.addPtr(AssemblyHelpers::TrustedImm32(offset), AssemblyHelpers::stackPointerRegister);
jit.addPtr(AssemblyHelpers::stackPointerRegister, GPRInfo::regT2);
ptrdiff_t currentOffset = -offset + sizeof(Register) * (
JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize);
jit.loadPtr(AssemblyHelpers::Address(GPRInfo::regT2, currentOffset), GPRInfo::regT1);
for (GPRReg gpr = AssemblyHelpers::firstRegister(); gpr <= AssemblyHelpers::lastRegister(); gpr = static_cast<GPRReg>(gpr + 1)) {
if (!toSave.get(gpr))
continue;
currentOffset += sizeof(Register);
jit.load64(AssemblyHelpers::Address(GPRInfo::regT2, currentOffset), gpr);
}
for (FPRReg fpr = AssemblyHelpers::firstFPRegister(); fpr <= AssemblyHelpers::lastFPRegister(); fpr = static_cast<FPRReg>(fpr + 1)) {
if (!toSave.get(fpr))
continue;
currentOffset += sizeof(Register);
jit.loadDouble(AssemblyHelpers::Address(GPRInfo::regT2, currentOffset), fpr);
}
jit.store32(
GPRInfo::regT4,
AssemblyHelpers::Address(
AssemblyHelpers::stackPointerRegister,
(JSStack::ArgumentCount - JSStack::CallerFrameAndPCSize) * sizeof(Register) + PayloadOffset));
if (!ASSERT_DISABLED) {
AssemblyHelpers::Jump ok = jit.branchPtr(
AssemblyHelpers::Above, GPRInfo::regT1, AssemblyHelpers::TrustedImmPtr(static_cast<size_t>(0x1000)));
jit.abortWithReason(RPWUnreasonableJumpTarget);
ok.link(&jit);
}
jit.jump(GPRInfo::regT1);
#else // ENABLE(FTL_JIT)
UNUSED_PARAM(jit);
UNREACHABLE_FOR_PLATFORM();
#endif // ENABLE(FTL_JIT)
}
MacroAssemblerCodeRef registerRestorationThunkGenerator(VM* vm)
{
AssemblyHelpers jit(vm, 0);
generateRegisterRestoration(jit);
LinkBuffer linkBuffer(*vm, jit, GLOBAL_THUNK_ID);
return FINALIZE_CODE(linkBuffer, ("Register restoration thunk"));
}
}
#endif // ENABLE(JIT)