michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * michael@0: * ***** BEGIN LICENSE BLOCK ***** michael@0: * Copyright (C) 2008 Apple Inc. All rights reserved. michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions michael@0: * are met: michael@0: * 1. Redistributions of source code must retain the above copyright michael@0: * notice, this list of conditions and the following disclaimer. michael@0: * 2. Redistributions in binary form must reproduce the above copyright michael@0: * notice, this list of conditions and the following disclaimer in the michael@0: * documentation and/or other materials provided with the distribution. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY michael@0: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE michael@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR michael@0: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR michael@0: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, michael@0: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, michael@0: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR michael@0: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY michael@0: * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: * michael@0: * ***** END LICENSE BLOCK ***** */ michael@0: michael@0: #ifndef assembler_assembler_AbstractMacroAssembler_h michael@0: #define assembler_assembler_AbstractMacroAssembler_h michael@0: michael@0: #include "assembler/wtf/Platform.h" michael@0: #include "assembler/assembler/MacroAssemblerCodeRef.h" michael@0: #include "assembler/assembler/CodeLocation.h" michael@0: michael@0: #if ENABLE_ASSEMBLER michael@0: michael@0: namespace JSC { michael@0: michael@0: class LinkBuffer; michael@0: class RepatchBuffer; michael@0: michael@0: template michael@0: class AbstractMacroAssembler { michael@0: public: michael@0: typedef AssemblerType AssemblerType_T; michael@0: michael@0: typedef MacroAssemblerCodePtr CodePtr; michael@0: typedef MacroAssemblerCodeRef CodeRef; michael@0: michael@0: class Jump; michael@0: michael@0: typedef typename AssemblerType::RegisterID RegisterID; michael@0: typedef typename AssemblerType::FPRegisterID FPRegisterID; michael@0: typedef typename AssemblerType::JmpSrc JmpSrc; michael@0: typedef typename AssemblerType::JmpDst JmpDst; michael@0: michael@0: #ifdef DEBUG michael@0: void setSpewPath(bool isOOLPath) michael@0: { michael@0: m_assembler.isOOLPath = isOOLPath; michael@0: } michael@0: #endif michael@0: michael@0: // Section 1: MacroAssembler operand types michael@0: // michael@0: // The following types are used as operands to MacroAssembler operations, michael@0: // describing immediate and memory operands to the instructions to be planted. michael@0: michael@0: michael@0: enum Scale { michael@0: TimesOne, michael@0: TimesTwo, michael@0: TimesFour, michael@0: TimesEight michael@0: }; michael@0: michael@0: // Address: michael@0: // michael@0: // Describes a simple base-offset address. michael@0: struct Address { michael@0: explicit Address() {} michael@0: michael@0: explicit Address(RegisterID base, int32_t offset = 0) michael@0: : base(base) michael@0: , offset(offset) michael@0: { michael@0: } michael@0: michael@0: RegisterID base; michael@0: int32_t offset; michael@0: }; michael@0: michael@0: struct ExtendedAddress { michael@0: explicit ExtendedAddress(RegisterID base, intptr_t offset = 0) michael@0: : base(base) michael@0: , offset(offset) michael@0: { michael@0: } michael@0: michael@0: RegisterID base; michael@0: intptr_t offset; michael@0: }; michael@0: michael@0: // ImplicitAddress: michael@0: // michael@0: // This class is used for explicit 'load' and 'store' operations michael@0: // (as opposed to situations in which a memory operand is provided michael@0: // to a generic operation, such as an integer arithmetic instruction). michael@0: // michael@0: // In the case of a load (or store) operation we want to permit michael@0: // addresses to be implicitly constructed, e.g. the two calls: michael@0: // michael@0: // load32(Address(addrReg), destReg); michael@0: // load32(addrReg, destReg); michael@0: // michael@0: // Are equivalent, and the explicit wrapping of the Address in the former michael@0: // is unnecessary. michael@0: struct ImplicitAddress { michael@0: ImplicitAddress(RegisterID base) michael@0: : base(base) michael@0: , offset(0) michael@0: { michael@0: } michael@0: michael@0: ImplicitAddress(Address address) michael@0: : base(address.base) michael@0: , offset(address.offset) michael@0: { michael@0: } michael@0: michael@0: RegisterID base; michael@0: int32_t offset; michael@0: }; michael@0: michael@0: // BaseIndex: michael@0: // michael@0: // Describes a complex addressing mode. michael@0: struct BaseIndex { michael@0: BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0) michael@0: : base(base) michael@0: , index(index) michael@0: , scale(scale) michael@0: , offset(offset) michael@0: { michael@0: } michael@0: michael@0: RegisterID base; michael@0: RegisterID index; michael@0: Scale scale; michael@0: int32_t offset; michael@0: }; michael@0: michael@0: // AbsoluteAddress: michael@0: // michael@0: // Describes an memory operand given by a pointer. For regular load & store michael@0: // operations an unwrapped void* will be used, rather than using this. michael@0: struct AbsoluteAddress { michael@0: explicit AbsoluteAddress(const void* ptr) michael@0: : m_ptr(ptr) michael@0: { michael@0: } michael@0: michael@0: const void* m_ptr; michael@0: }; michael@0: michael@0: // TrustedImmPtr: michael@0: // michael@0: // A pointer sized immediate operand to an instruction - this is wrapped michael@0: // in a class requiring explicit construction in order to differentiate michael@0: // from pointers used as absolute addresses to memory operations michael@0: struct TrustedImmPtr { michael@0: explicit TrustedImmPtr(const void* value) michael@0: : m_value(value) michael@0: { michael@0: } michael@0: michael@0: intptr_t asIntptr() michael@0: { michael@0: return reinterpret_cast(m_value); michael@0: } michael@0: michael@0: const void* m_value; michael@0: }; michael@0: michael@0: struct ImmPtr : public TrustedImmPtr { michael@0: explicit ImmPtr(const void* value) michael@0: : TrustedImmPtr(value) michael@0: { michael@0: } michael@0: }; michael@0: michael@0: // TrustedImm32: michael@0: // michael@0: // A 32bit immediate operand to an instruction - this is wrapped in a michael@0: // class requiring explicit construction in order to prevent RegisterIDs michael@0: // (which are implemented as an enum) from accidentally being passed as michael@0: // immediate values. michael@0: struct TrustedImm32 { michael@0: explicit TrustedImm32(int32_t value) michael@0: : m_value(value) michael@0: #if WTF_CPU_ARM || WTF_CPU_MIPS michael@0: , m_isPointer(false) michael@0: #endif michael@0: { michael@0: } michael@0: michael@0: #if !WTF_CPU_X86_64 michael@0: explicit TrustedImm32(TrustedImmPtr ptr) michael@0: : m_value(ptr.asIntptr()) michael@0: #if WTF_CPU_ARM || WTF_CPU_MIPS michael@0: , m_isPointer(true) michael@0: #endif michael@0: { michael@0: } michael@0: #endif michael@0: michael@0: int32_t m_value; michael@0: #if WTF_CPU_ARM || WTF_CPU_MIPS michael@0: // We rely on being able to regenerate code to recover exception handling michael@0: // information. Since ARMv7 supports 16-bit immediates there is a danger michael@0: // that if pointer values change the layout of the generated code will change. michael@0: // To avoid this problem, always generate pointers (and thus Imm32s constructed michael@0: // from ImmPtrs) with a code sequence that is able to represent any pointer michael@0: // value - don't use a more compact form in these cases. michael@0: // Same for MIPS. michael@0: bool m_isPointer; michael@0: #endif michael@0: }; michael@0: michael@0: michael@0: struct Imm32 : public TrustedImm32 { michael@0: explicit Imm32(int32_t value) michael@0: : TrustedImm32(value) michael@0: { michael@0: } michael@0: #if !WTF_CPU_X86_64 michael@0: explicit Imm32(TrustedImmPtr ptr) michael@0: : TrustedImm32(ptr) michael@0: { michael@0: } michael@0: #endif michael@0: }; michael@0: michael@0: struct ImmDouble { michael@0: union { michael@0: struct { michael@0: #if WTF_CPU_BIG_ENDIAN || WTF_CPU_MIDDLE_ENDIAN michael@0: uint32_t msb, lsb; michael@0: #else michael@0: uint32_t lsb, msb; michael@0: #endif michael@0: } s; michael@0: uint64_t u64; michael@0: double d; michael@0: } u; michael@0: michael@0: explicit ImmDouble(double d) { michael@0: u.d = d; michael@0: } michael@0: }; michael@0: michael@0: // Section 2: MacroAssembler code buffer handles michael@0: // michael@0: // The following types are used to reference items in the code buffer michael@0: // during JIT code generation. For example, the type Jump is used to michael@0: // track the location of a jump instruction so that it may later be michael@0: // linked to a label marking its destination. michael@0: michael@0: michael@0: // Label: michael@0: // michael@0: // A Label records a point in the generated instruction stream, typically such that michael@0: // it may be used as a destination for a jump. michael@0: class Label { michael@0: template michael@0: friend class AbstractMacroAssembler; michael@0: friend class Jump; michael@0: friend class MacroAssemblerCodeRef; michael@0: friend class LinkBuffer; michael@0: michael@0: public: michael@0: Label() michael@0: { michael@0: } michael@0: michael@0: Label(AbstractMacroAssembler* masm) michael@0: : m_label(masm->m_assembler.label()) michael@0: { michael@0: } michael@0: michael@0: bool isUsed() const { return m_label.isUsed(); } michael@0: void used() { m_label.used(); } michael@0: bool isSet() const { return m_label.isValid(); } michael@0: private: michael@0: JmpDst m_label; michael@0: }; michael@0: michael@0: // DataLabelPtr: michael@0: // michael@0: // A DataLabelPtr is used to refer to a location in the code containing a pointer to be michael@0: // patched after the code has been generated. michael@0: class DataLabelPtr { michael@0: template michael@0: friend class AbstractMacroAssembler; michael@0: friend class LinkBuffer; michael@0: public: michael@0: DataLabelPtr() michael@0: { michael@0: } michael@0: michael@0: DataLabelPtr(AbstractMacroAssembler* masm) michael@0: : m_label(masm->m_assembler.label()) michael@0: { michael@0: } michael@0: michael@0: bool isSet() const { return m_label.isValid(); } michael@0: michael@0: private: michael@0: JmpDst m_label; michael@0: }; michael@0: michael@0: // DataLabel32: michael@0: // michael@0: // A DataLabel32 is used to refer to a location in the code containing a michael@0: // 32-bit constant to be patched after the code has been generated. michael@0: class DataLabel32 { michael@0: template michael@0: friend class AbstractMacroAssembler; michael@0: friend class LinkBuffer; michael@0: public: michael@0: DataLabel32() michael@0: { michael@0: } michael@0: michael@0: DataLabel32(AbstractMacroAssembler* masm) michael@0: : m_label(masm->m_assembler.label()) michael@0: { michael@0: } michael@0: michael@0: private: michael@0: JmpDst m_label; michael@0: }; michael@0: michael@0: // Call: michael@0: // michael@0: // A Call object is a reference to a call instruction that has been planted michael@0: // into the code buffer - it is typically used to link the call, setting the michael@0: // relative offset such that when executed it will call to the desired michael@0: // destination. michael@0: class Call { michael@0: template michael@0: friend class AbstractMacroAssembler; michael@0: michael@0: public: michael@0: enum Flags { michael@0: None = 0x0, michael@0: Linkable = 0x1, michael@0: Near = 0x2, michael@0: LinkableNear = 0x3 michael@0: }; michael@0: michael@0: Call() michael@0: : m_flags(None) michael@0: { michael@0: } michael@0: michael@0: Call(JmpSrc jmp, Flags flags) michael@0: : m_jmp(jmp) michael@0: , m_flags(flags) michael@0: { michael@0: } michael@0: michael@0: bool isFlagSet(Flags flag) michael@0: { michael@0: return !!(m_flags & flag); michael@0: } michael@0: michael@0: static Call fromTailJump(Jump jump) michael@0: { michael@0: return Call(jump.m_jmp, Linkable); michael@0: } michael@0: michael@0: JmpSrc m_jmp; michael@0: private: michael@0: Flags m_flags; michael@0: }; michael@0: michael@0: // Jump: michael@0: // michael@0: // A jump object is a reference to a jump instruction that has been planted michael@0: // into the code buffer - it is typically used to link the jump, setting the michael@0: // relative offset such that when executed it will jump to the desired michael@0: // destination. michael@0: class Jump { michael@0: template michael@0: friend class AbstractMacroAssembler; michael@0: friend class Call; michael@0: friend class LinkBuffer; michael@0: public: michael@0: Jump() michael@0: { michael@0: } michael@0: michael@0: Jump(JmpSrc jmp) michael@0: : m_jmp(jmp) michael@0: { michael@0: } michael@0: michael@0: void link(AbstractMacroAssembler* masm) const michael@0: { michael@0: masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label()); michael@0: } michael@0: michael@0: void linkTo(Label label, AbstractMacroAssembler* masm) const michael@0: { michael@0: masm->m_assembler.linkJump(m_jmp, label.m_label); michael@0: } michael@0: michael@0: bool isSet() const { return m_jmp.isSet(); } michael@0: michael@0: private: michael@0: JmpSrc m_jmp; michael@0: }; michael@0: michael@0: // JumpList: michael@0: // michael@0: // A JumpList is a set of Jump objects. michael@0: // All jumps in the set will be linked to the same destination. michael@0: class JumpList { michael@0: friend class LinkBuffer; michael@0: michael@0: public: michael@0: typedef js::Vector JumpVector; michael@0: michael@0: JumpList() {} michael@0: michael@0: JumpList(const JumpList &other) michael@0: { michael@0: m_jumps.appendAll(other.m_jumps); michael@0: } michael@0: michael@0: JumpList &operator=(const JumpList &other) michael@0: { michael@0: m_jumps.clear(); michael@0: m_jumps.append(other.m_jumps); michael@0: return *this; michael@0: } michael@0: michael@0: void link(AbstractMacroAssembler* masm) michael@0: { michael@0: size_t size = m_jumps.length(); michael@0: for (size_t i = 0; i < size; ++i) michael@0: m_jumps[i].link(masm); michael@0: m_jumps.clear(); michael@0: } michael@0: michael@0: void linkTo(Label label, AbstractMacroAssembler* masm) michael@0: { michael@0: size_t size = m_jumps.length(); michael@0: for (size_t i = 0; i < size; ++i) michael@0: m_jumps[i].linkTo(label, masm); michael@0: m_jumps.clear(); michael@0: } michael@0: michael@0: void append(Jump jump) michael@0: { michael@0: m_jumps.append(jump); michael@0: } michael@0: michael@0: void append(const JumpList& other) michael@0: { michael@0: m_jumps.append(other.m_jumps.begin(), other.m_jumps.length()); michael@0: } michael@0: michael@0: void clear() michael@0: { michael@0: m_jumps.clear(); michael@0: } michael@0: michael@0: bool empty() michael@0: { michael@0: return !m_jumps.length(); michael@0: } michael@0: michael@0: const JumpVector& jumps() const { return m_jumps; } michael@0: michael@0: private: michael@0: JumpVector m_jumps; michael@0: }; michael@0: michael@0: michael@0: // Section 3: Misc admin methods michael@0: michael@0: static CodePtr trampolineAt(CodeRef ref, Label label) michael@0: { michael@0: return CodePtr(AssemblerType::getRelocatedAddress(ref.m_code.dataLocation(), label.m_label)); michael@0: } michael@0: michael@0: size_t size() michael@0: { michael@0: return m_assembler.size(); michael@0: } michael@0: michael@0: unsigned char *buffer() michael@0: { michael@0: return m_assembler.buffer(); michael@0: } michael@0: michael@0: bool oom() michael@0: { michael@0: return m_assembler.oom(); michael@0: } michael@0: michael@0: void executableCopy(void* buffer) michael@0: { michael@0: ASSERT(!oom()); michael@0: m_assembler.executableCopy(buffer); michael@0: } michael@0: michael@0: Label label() michael@0: { michael@0: return Label(this); michael@0: } michael@0: michael@0: DataLabel32 dataLabel32() michael@0: { michael@0: return DataLabel32(this); michael@0: } michael@0: michael@0: Label align() michael@0: { michael@0: m_assembler.align(16); michael@0: return Label(this); michael@0: } michael@0: michael@0: ptrdiff_t differenceBetween(Label from, Jump to) michael@0: { michael@0: return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); michael@0: } michael@0: michael@0: ptrdiff_t differenceBetween(Label from, Call to) michael@0: { michael@0: return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); michael@0: } michael@0: michael@0: ptrdiff_t differenceBetween(Label from, Label to) michael@0: { michael@0: return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); michael@0: } michael@0: michael@0: ptrdiff_t differenceBetween(Label from, DataLabelPtr to) michael@0: { michael@0: return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); michael@0: } michael@0: michael@0: ptrdiff_t differenceBetween(Label from, DataLabel32 to) michael@0: { michael@0: return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); michael@0: } michael@0: michael@0: ptrdiff_t differenceBetween(DataLabel32 from, Label to) michael@0: { michael@0: return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); michael@0: } michael@0: michael@0: ptrdiff_t differenceBetween(DataLabelPtr from, Label to) michael@0: { michael@0: return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); michael@0: } michael@0: michael@0: ptrdiff_t differenceBetween(DataLabelPtr from, Jump to) michael@0: { michael@0: return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); michael@0: } michael@0: michael@0: ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to) michael@0: { michael@0: return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); michael@0: } michael@0: michael@0: ptrdiff_t differenceBetween(DataLabelPtr from, Call to) michael@0: { michael@0: return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); michael@0: } michael@0: michael@0: protected: michael@0: AssemblerType m_assembler; michael@0: michael@0: friend class LinkBuffer; michael@0: friend class RepatchBuffer; michael@0: michael@0: static void linkJump(void* code, Jump jump, CodeLocationLabel target) michael@0: { michael@0: AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation()); michael@0: } michael@0: michael@0: static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value) michael@0: { michael@0: AssemblerType::linkPointer(code, label, value); michael@0: } michael@0: michael@0: static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label) michael@0: { michael@0: return AssemblerType::getRelocatedAddress(code, label); michael@0: } michael@0: michael@0: static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label) michael@0: { michael@0: return AssemblerType::getRelocatedAddress(code, label); michael@0: } michael@0: michael@0: static unsigned getLinkerCallReturnOffset(Call call) michael@0: { michael@0: return AssemblerType::getCallReturnOffset(call.m_jmp); michael@0: } michael@0: michael@0: static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination) michael@0: { michael@0: AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation()); michael@0: } michael@0: michael@0: static bool canRepatchJump(CodeLocationJump jump, CodeLocationLabel destination) michael@0: { michael@0: return AssemblerType::canRelinkJump(jump.dataLocation(), destination.dataLocation()); michael@0: } michael@0: michael@0: static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination) michael@0: { michael@0: AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress()); michael@0: } michael@0: michael@0: static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value) michael@0: { michael@0: AssemblerType::repatchInt32(dataLabel32.dataLocation(), value); michael@0: } michael@0: michael@0: static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value) michael@0: { michael@0: AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value); michael@0: } michael@0: michael@0: static void repatchLoadPtrToLEA(CodeLocationInstruction instruction) michael@0: { michael@0: AssemblerType::repatchLoadPtrToLEA(instruction.dataLocation()); michael@0: } michael@0: michael@0: static void repatchLEAToLoadPtr(CodeLocationInstruction instruction) michael@0: { michael@0: AssemblerType::repatchLEAToLoadPtr(instruction.dataLocation()); michael@0: } michael@0: }; michael@0: michael@0: } // namespace JSC michael@0: michael@0: #endif // ENABLE(ASSEMBLER) michael@0: michael@0: #endif /* assembler_assembler_AbstractMacroAssembler_h */