SpecializedThunkJIT.h [plain text]
#ifndef SpecializedThunkJIT_h
#define SpecializedThunkJIT_h
#if ENABLE(JIT)
#include "Executable.h"
#include "JIT.h"
#include "JITInlines.h"
#include "JSInterfaceJIT.h"
#include "JSStack.h"
#include "LinkBuffer.h"
namespace JSC {
class SpecializedThunkJIT : public JSInterfaceJIT {
public:
static const int ThisArgument = -1;
SpecializedThunkJIT(VM* vm, int expectedArgCount)
: JSInterfaceJIT(vm)
{
emitFunctionPrologue();
m_failures.append(branch32(NotEqual, payloadFor(JSStack::ArgumentCount), TrustedImm32(expectedArgCount + 1)));
}
explicit SpecializedThunkJIT(VM* vm)
: JSInterfaceJIT(vm)
{
emitFunctionPrologue();
}
void loadDoubleArgument(int argument, FPRegisterID dst, RegisterID scratch)
{
unsigned src = CallFrame::argumentOffset(argument);
m_failures.append(emitLoadDouble(src, dst, scratch));
}
void loadCellArgument(int argument, RegisterID dst)
{
unsigned src = CallFrame::argumentOffset(argument);
m_failures.append(emitLoadJSCell(src, dst));
}
void loadJSStringArgument(VM& vm, int argument, RegisterID dst)
{
loadCellArgument(argument, dst);
m_failures.append(branchStructure(*this, NotEqual,
Address(dst, JSCell::structureIDOffset()),
vm.stringStructure.get()));
}
void loadArgumentWithSpecificClass(const ClassInfo* classInfo, int argument, RegisterID dst, RegisterID scratch)
{
loadCellArgument(argument, dst);
emitLoadStructure(dst, scratch, dst);
appendFailure(branchPtr(NotEqual, Address(scratch, Structure::classInfoOffset()), TrustedImmPtr(classInfo)));
loadCellArgument(argument, dst);
}
void loadInt32Argument(int argument, RegisterID dst, Jump& failTarget)
{
unsigned src = CallFrame::argumentOffset(argument);
failTarget = emitLoadInt32(src, dst);
}
void loadInt32Argument(int argument, RegisterID dst)
{
Jump conversionFailed;
loadInt32Argument(argument, dst, conversionFailed);
m_failures.append(conversionFailed);
}
void appendFailure(const Jump& failure)
{
m_failures.append(failure);
}
#if USE(JSVALUE64)
void returnJSValue(RegisterID src)
{
if (src != regT0)
move(src, regT0);
emitFunctionEpilogue();
ret();
}
#else
void returnJSValue(RegisterID payload, RegisterID tag)
{
ASSERT_UNUSED(payload, payload == regT0);
ASSERT_UNUSED(tag, tag == regT1);
emitFunctionEpilogue();
ret();
}
#endif
void returnDouble(FPRegisterID src)
{
#if USE(JSVALUE64)
moveDoubleTo64(src, regT0);
Jump zero = branchTest64(Zero, regT0);
sub64(tagTypeNumberRegister, regT0);
Jump done = jump();
zero.link(this);
move(tagTypeNumberRegister, regT0);
done.link(this);
#else
#if !CPU(X86)
moveDoubleToInts(src, regT0, regT1);
#else
storeDouble(src, Address(stackPointerRegister, -(int)sizeof(double)));
loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(JSValue, u.asBits.tag) - sizeof(double)), regT1);
loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(JSValue, u.asBits.payload) - sizeof(double)), regT0);
#endif
Jump lowNonZero = branchTestPtr(NonZero, regT1);
Jump highNonZero = branchTestPtr(NonZero, regT0);
move(TrustedImm32(0), regT0);
move(TrustedImm32(Int32Tag), regT1);
lowNonZero.link(this);
highNonZero.link(this);
#endif
emitFunctionEpilogue();
ret();
}
void returnInt32(RegisterID src)
{
if (src != regT0)
move(src, regT0);
tagReturnAsInt32();
emitFunctionEpilogue();
ret();
}
void returnJSCell(RegisterID src)
{
if (src != regT0)
move(src, regT0);
tagReturnAsJSCell();
emitFunctionEpilogue();
ret();
}
MacroAssemblerCodeRef finalize(MacroAssemblerCodePtr fallback, const char* thunkKind)
{
LinkBuffer patchBuffer(*m_vm, *this, GLOBAL_THUNK_ID);
patchBuffer.link(m_failures, CodeLocationLabel(fallback));
for (unsigned i = 0; i < m_calls.size(); i++)
patchBuffer.link(m_calls[i].first, m_calls[i].second);
return FINALIZE_CODE(patchBuffer, ("Specialized thunk for %s", thunkKind));
}
void callDoubleToDouble(FunctionPtr function)
{
m_calls.append(std::make_pair(call(), function));
}
void callDoubleToDoublePreservingReturn(FunctionPtr function)
{
if (!isX86())
preserveReturnAddressAfterCall(regT3);
callDoubleToDouble(function);
if (!isX86())
restoreReturnAddressBeforeReturn(regT3);
}
private:
void tagReturnAsInt32()
{
#if USE(JSVALUE64)
or64(tagTypeNumberRegister, regT0);
#else
move(TrustedImm32(JSValue::Int32Tag), regT1);
#endif
}
void tagReturnAsJSCell()
{
#if USE(JSVALUE32_64)
move(TrustedImm32(JSValue::CellTag), regT1);
#endif
}
MacroAssembler::JumpList m_failures;
Vector<std::pair<Call, FunctionPtr>> m_calls;
};
}
#endif // ENABLE(JIT)
#endif // SpecializedThunkJIT_h