AbstractMacroAssembler.h [plain text]
#ifndef AbstractMacroAssembler_h
#define AbstractMacroAssembler_h
#include <wtf/Platform.h>
#if ENABLE(ASSEMBLER)
namespace JSC {
template <class AssemblerType>
class AbstractMacroAssembler {
public:
class Jump;
class PatchBuffer;
class CodeLocationInstruction;
class CodeLocationLabel;
class CodeLocationJump;
class CodeLocationCall;
class CodeLocationDataLabel32;
class CodeLocationDataLabelPtr;
typedef typename AssemblerType::RegisterID RegisterID;
typedef typename AssemblerType::FPRegisterID FPRegisterID;
typedef typename AssemblerType::JmpSrc JmpSrc;
typedef typename AssemblerType::JmpDst JmpDst;
enum Scale {
TimesOne,
TimesTwo,
TimesFour,
TimesEight,
};
struct Address {
explicit Address(RegisterID base, int32_t offset = 0)
: base(base)
, offset(offset)
{
}
RegisterID base;
int32_t offset;
};
struct ImplicitAddress {
ImplicitAddress(RegisterID base)
: base(base)
, offset(0)
{
}
ImplicitAddress(Address address)
: base(address.base)
, offset(address.offset)
{
}
RegisterID base;
int32_t offset;
};
struct BaseIndex {
BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
: base(base)
, index(index)
, scale(scale)
, offset(offset)
{
}
RegisterID base;
RegisterID index;
Scale scale;
int32_t offset;
};
struct AbsoluteAddress {
explicit AbsoluteAddress(void* ptr)
: m_ptr(ptr)
{
}
void* m_ptr;
};
struct ImmPtr {
explicit ImmPtr(void* value)
: m_value(value)
{
}
intptr_t asIntptr()
{
return reinterpret_cast<intptr_t>(m_value);
}
void* m_value;
};
struct Imm32 {
explicit Imm32(int32_t value)
: m_value(value)
{
}
#if !PLATFORM(X86_64)
explicit Imm32(ImmPtr ptr)
: m_value(ptr.asIntptr())
{
}
#endif
int32_t m_value;
};
class Label {
friend class Jump;
template<class AssemblerType_T>
friend class AbstractMacroAssembler;
friend class PatchBuffer;
public:
Label()
{
}
Label(AbstractMacroAssembler<AssemblerType>* masm)
: m_label(masm->m_assembler.label())
{
}
bool isUsed() const { return m_label.isUsed(); }
void used() { m_label.used(); }
private:
JmpDst m_label;
};
class DataLabelPtr {
template<class AssemblerType_T>
friend class AbstractMacroAssembler;
friend class PatchBuffer;
public:
DataLabelPtr()
{
}
DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
: m_label(masm->m_assembler.label())
{
}
private:
JmpDst m_label;
};
class DataLabel32 {
template<class AssemblerType_T>
friend class AbstractMacroAssembler;
friend class PatchBuffer;
public:
DataLabel32()
{
}
DataLabel32(AbstractMacroAssembler<AssemblerType>* masm)
: m_label(masm->m_assembler.label())
{
}
private:
JmpDst m_label;
};
class Call {
friend class PatchBuffer;
template<class AssemblerType_T>
friend class AbstractMacroAssembler;
public:
enum Flags {
None = 0x0,
Linkable = 0x1,
Near = 0x2,
LinkableNear = 0x3,
};
Call()
: m_flags(None)
{
}
Call(JmpSrc jmp, Flags flags)
: m_jmp(jmp)
, m_flags(flags)
{
}
bool isFlagSet(Flags flag)
{
return m_flags & flag;
}
static Call fromTailJump(Jump jump)
{
return Call(jump.m_jmp, Linkable);
}
private:
JmpSrc m_jmp;
Flags m_flags;
};
class Jump {
friend class PatchBuffer;
template<class AssemblerType_T>
friend class AbstractMacroAssembler;
friend class Call;
public:
Jump()
{
}
Jump(JmpSrc jmp)
: m_jmp(jmp)
{
}
void link(AbstractMacroAssembler<AssemblerType>* masm)
{
masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label());
}
void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
{
masm->m_assembler.linkJump(m_jmp, label.m_label);
}
private:
JmpSrc m_jmp;
};
class JumpList {
friend class PatchBuffer;
public:
void link(AbstractMacroAssembler<AssemblerType>* masm)
{
size_t size = m_jumps.size();
for (size_t i = 0; i < size; ++i)
m_jumps[i].link(masm);
m_jumps.clear();
}
void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
{
size_t size = m_jumps.size();
for (size_t i = 0; i < size; ++i)
m_jumps[i].linkTo(label, masm);
m_jumps.clear();
}
void append(Jump jump)
{
m_jumps.append(jump);
}
void append(JumpList& other)
{
m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
}
bool empty()
{
return !m_jumps.size();
}
private:
Vector<Jump, 16> m_jumps;
};
class CodeLocationCommon {
public:
CodeLocationCommon()
: m_location(0)
{
}
CodeLocationInstruction instructionAtOffset(int offset);
CodeLocationLabel labelAtOffset(int offset);
CodeLocationJump jumpAtOffset(int offset);
CodeLocationCall callAtOffset(int offset);
CodeLocationDataLabelPtr dataLabelPtrAtOffset(int offset);
CodeLocationDataLabel32 dataLabel32AtOffset(int offset);
operator bool() { return m_location; }
void reset() { m_location = 0; }
protected:
explicit CodeLocationCommon(void* location)
: m_location(location)
{
}
void* m_location;
};
class CodeLocationInstruction : public CodeLocationCommon {
friend class CodeLocationCommon;
public:
CodeLocationInstruction()
{
}
void patchLoadToLEA() {
AssemblerType::patchLoadToLEA(reinterpret_cast<intptr_t>(this->m_location));
}
private:
explicit CodeLocationInstruction(void* location)
: CodeLocationCommon(location)
{
}
};
class CodeLocationLabel : public CodeLocationCommon {
friend class CodeLocationCommon;
friend class CodeLocationJump;
friend class PatchBuffer;
public:
CodeLocationLabel()
{
}
void* addressForSwitch() { return this->m_location; }
void* addressForExceptionHandler() { return this->m_location; }
void* addressForJSR() { return this->m_location; }
private:
explicit CodeLocationLabel(void* location)
: CodeLocationCommon(location)
{
}
void* getJumpDestination() { return this->m_location; }
};
class CodeLocationJump : public CodeLocationCommon {
friend class CodeLocationCommon;
friend class PatchBuffer;
public:
CodeLocationJump()
{
}
void relink(CodeLocationLabel destination)
{
AssemblerType::patchJump(reinterpret_cast<intptr_t>(this->m_location), destination.m_location);
}
private:
explicit CodeLocationJump(void* location)
: CodeLocationCommon(location)
{
}
};
class CodeLocationCall : public CodeLocationCommon {
friend class CodeLocationCommon;
friend class PatchBuffer;
public:
CodeLocationCall()
{
}
template<typename FunctionSig>
void relink(FunctionSig* function)
{
AssemblerType::patchMacroAssemblerCall(reinterpret_cast<intptr_t>(this->m_location), reinterpret_cast<void*>(function));
}
void* calleeReturnAddressValue()
{
return this->m_location;
}
private:
explicit CodeLocationCall(void* location)
: CodeLocationCommon(location)
{
}
};
class CodeLocationNearCall : public CodeLocationCommon {
friend class CodeLocationCommon;
friend class PatchBuffer;
public:
CodeLocationNearCall()
{
}
template<typename FunctionSig>
void relink(FunctionSig* function)
{
AssemblerType::patchCall(reinterpret_cast<intptr_t>(this->m_location), reinterpret_cast<void*>(function));
}
void* calleeReturnAddressValue()
{
return this->m_location;
}
private:
explicit CodeLocationNearCall(void* location)
: CodeLocationCommon(location)
{
}
};
class CodeLocationDataLabel32 : public CodeLocationCommon {
friend class CodeLocationCommon;
friend class PatchBuffer;
public:
CodeLocationDataLabel32()
{
}
void repatch(int32_t value)
{
AssemblerType::patchImmediate(reinterpret_cast<intptr_t>(this->m_location), value);
}
private:
explicit CodeLocationDataLabel32(void* location)
: CodeLocationCommon(location)
{
}
};
class CodeLocationDataLabelPtr : public CodeLocationCommon {
friend class CodeLocationCommon;
friend class PatchBuffer;
public:
CodeLocationDataLabelPtr()
{
}
void repatch(void* value)
{
AssemblerType::patchPointer(reinterpret_cast<intptr_t>(this->m_location), reinterpret_cast<intptr_t>(value));
}
private:
explicit CodeLocationDataLabelPtr(void* location)
: CodeLocationCommon(location)
{
}
};
class ProcessorReturnAddress {
public:
ProcessorReturnAddress(void* location)
: m_location(location)
{
}
template<typename FunctionSig>
void relinkCallerToFunction(FunctionSig* newCalleeFunction)
{
AssemblerType::patchMacroAssemblerCall(reinterpret_cast<intptr_t>(this->m_location), reinterpret_cast<void*>(newCalleeFunction));
}
template<typename FunctionSig>
void relinkNearCallerToFunction(FunctionSig* newCalleeFunction)
{
AssemblerType::patchCall(reinterpret_cast<intptr_t>(this->m_location), reinterpret_cast<void*>(newCalleeFunction));
}
operator void*()
{
return m_location;
}
private:
void* m_location;
};
class PatchBuffer {
public:
PatchBuffer(void* code)
: m_code(code)
{
}
CodeLocationLabel entry()
{
return CodeLocationLabel(m_code);
}
void* trampolineAt(Label label)
{
return AssemblerType::getRelocatedAddress(m_code, label.m_label);
}
template<typename FunctionSig>
void link(Call call, FunctionSig* function)
{
ASSERT(call.isFlagSet(Call::Linkable));
#if PLATFORM(X86_64)
if (call.isFlagSet(Call::Near)) {
AssemblerType::linkCall(m_code, call.m_jmp, reinterpret_cast<void*>(function));
} else {
intptr_t callLocation = reinterpret_cast<intptr_t>(AssemblerType::getRelocatedAddress(m_code, call.m_jmp));
AssemblerType::patchMacroAssemblerCall(callLocation, reinterpret_cast<void*>(function));
}
#else
AssemblerType::linkCall(m_code, call.m_jmp, reinterpret_cast<void*>(function));
#endif
}
template<typename FunctionSig>
void linkTailRecursive(Jump jump, FunctionSig* function)
{
AssemblerType::linkJump(m_code, jump.m_jmp, reinterpret_cast<void*>(function));
}
template<typename FunctionSig>
void linkTailRecursive(JumpList list, FunctionSig* function)
{
for (unsigned i = 0; i < list.m_jumps.size(); ++i) {
AssemblerType::linkJump(m_code, list.m_jumps[i].m_jmp, reinterpret_cast<void*>(function));
}
}
void link(Jump jump, CodeLocationLabel label)
{
AssemblerType::linkJump(m_code, jump.m_jmp, label.m_location);
}
void link(JumpList list, CodeLocationLabel label)
{
for (unsigned i = 0; i < list.m_jumps.size(); ++i)
AssemblerType::linkJump(m_code, list.m_jumps[i].m_jmp, label.m_location);
}
void patch(DataLabelPtr label, void* value)
{
AssemblerType::patchAddress(m_code, label.m_label, value);
}
CodeLocationCall locationOf(Call call)
{
ASSERT(call.isFlagSet(Call::Linkable));
ASSERT(!call.isFlagSet(Call::Near));
return CodeLocationCall(AssemblerType::getRelocatedAddress(m_code, call.m_jmp));
}
CodeLocationNearCall locationOfNearCall(Call call)
{
ASSERT(call.isFlagSet(Call::Linkable));
ASSERT(call.isFlagSet(Call::Near));
return CodeLocationNearCall(AssemblerType::getRelocatedAddress(m_code, call.m_jmp));
}
CodeLocationLabel locationOf(Label label)
{
return CodeLocationLabel(AssemblerType::getRelocatedAddress(m_code, label.m_label));
}
CodeLocationDataLabelPtr locationOf(DataLabelPtr label)
{
return CodeLocationDataLabelPtr(AssemblerType::getRelocatedAddress(m_code, label.m_label));
}
CodeLocationDataLabel32 locationOf(DataLabel32 label)
{
return CodeLocationDataLabel32(AssemblerType::getRelocatedAddress(m_code, label.m_label));
}
unsigned returnAddressOffset(Call call)
{
return AssemblerType::getCallReturnOffset(call.m_jmp);
}
private:
void* m_code;
};
size_t size()
{
return m_assembler.size();
}
void* copyCode(ExecutablePool* allocator)
{
return m_assembler.executableCopy(allocator);
}
Label label()
{
return Label(this);
}
Label align()
{
m_assembler.align(16);
return Label(this);
}
ptrdiff_t differenceBetween(Label from, Jump to)
{
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
}
ptrdiff_t differenceBetween(Label from, Call to)
{
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
}
ptrdiff_t differenceBetween(Label from, Label to)
{
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
}
ptrdiff_t differenceBetween(Label from, DataLabelPtr to)
{
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
}
ptrdiff_t differenceBetween(Label from, DataLabel32 to)
{
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
}
ptrdiff_t differenceBetween(DataLabelPtr from, Jump to)
{
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
}
ptrdiff_t differenceBetween(DataLabelPtr from, Call to)
{
return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
}
protected:
AssemblerType m_assembler;
};
template <class AssemblerType>
typename AbstractMacroAssembler<AssemblerType>::CodeLocationInstruction AbstractMacroAssembler<AssemblerType>::CodeLocationCommon::instructionAtOffset(int offset)
{
return typename AbstractMacroAssembler::CodeLocationInstruction(reinterpret_cast<char*>(m_location) + offset);
}
template <class AssemblerType>
typename AbstractMacroAssembler<AssemblerType>::CodeLocationLabel AbstractMacroAssembler<AssemblerType>::CodeLocationCommon::labelAtOffset(int offset)
{
return typename AbstractMacroAssembler::CodeLocationLabel(reinterpret_cast<char*>(m_location) + offset);
}
template <class AssemblerType>
typename AbstractMacroAssembler<AssemblerType>::CodeLocationJump AbstractMacroAssembler<AssemblerType>::CodeLocationCommon::jumpAtOffset(int offset)
{
return typename AbstractMacroAssembler::CodeLocationJump(reinterpret_cast<char*>(m_location) + offset);
}
template <class AssemblerType>
typename AbstractMacroAssembler<AssemblerType>::CodeLocationCall AbstractMacroAssembler<AssemblerType>::CodeLocationCommon::callAtOffset(int offset)
{
return typename AbstractMacroAssembler::CodeLocationCall(reinterpret_cast<char*>(m_location) + offset);
}
template <class AssemblerType>
typename AbstractMacroAssembler<AssemblerType>::CodeLocationDataLabelPtr AbstractMacroAssembler<AssemblerType>::CodeLocationCommon::dataLabelPtrAtOffset(int offset)
{
return typename AbstractMacroAssembler::CodeLocationDataLabelPtr(reinterpret_cast<char*>(m_location) + offset);
}
template <class AssemblerType>
typename AbstractMacroAssembler<AssemblerType>::CodeLocationDataLabel32 AbstractMacroAssembler<AssemblerType>::CodeLocationCommon::dataLabel32AtOffset(int offset)
{
return typename AbstractMacroAssembler::CodeLocationDataLabel32(reinterpret_cast<char*>(m_location) + offset);
}
}
#endif // ENABLE(ASSEMBLER)
#endif // AbstractMacroAssembler_h