/* * Copyright (C) 2008, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef AbstractMacroAssembler_h #define AbstractMacroAssembler_h #include "AssemblerBuffer.h" #include "CodeLocation.h" #include "MacroAssemblerCodeRef.h" #include #include #include #if ENABLE(ASSEMBLER) #if PLATFORM(QT) #define ENABLE_JIT_CONSTANT_BLINDING 0 #endif #ifndef ENABLE_JIT_CONSTANT_BLINDING #define ENABLE_JIT_CONSTANT_BLINDING 1 #endif namespace JSC { class JumpReplacementWatchpoint; template class> class LinkBufferBase; template class BranchCompactingLinkBuffer; class RepatchBuffer; class Watchpoint; namespace DFG { struct OSRExit; } template class AbstractMacroAssembler { public: friend class JITWriteBarrierBase; typedef AssemblerType AssemblerType_T; typedef MacroAssemblerCodePtr CodePtr; typedef MacroAssemblerCodeRef CodeRef; #if !CPU(ARM_THUMB2) && !CPU(ARM64) && !defined(V4_BOOTSTRAP) class Jump; #endif typedef typename AssemblerType::RegisterID RegisterID; typedef typename AssemblerType::FPRegisterID FPRegisterID; // Section 1: MacroAssembler operand types // // The following types are used as operands to MacroAssembler operations, // describing immediate and memory operands to the instructions to be planted. enum Scale { TimesOne, TimesTwo, TimesFour, TimesEight, }; // Address: // // Describes a simple base-offset address. struct Address { explicit Address(RegisterID base, int32_t offset = 0) : base(base) , offset(offset) { } RegisterID base; int32_t offset; }; struct ExtendedAddress { explicit ExtendedAddress(RegisterID base, intptr_t offset = 0) : base(base) , offset(offset) { } RegisterID base; intptr_t offset; }; // ImplicitAddress: // // This class is used for explicit 'load' and 'store' operations // (as opposed to situations in which a memory operand is provided // to a generic operation, such as an integer arithmetic instruction). // // In the case of a load (or store) operation we want to permit // addresses to be implicitly constructed, e.g. the two calls: // // load32(Address(addrReg), destReg); // load32(addrReg, destReg); // // Are equivalent, and the explicit wrapping of the Address in the former // is unnecessary. struct ImplicitAddress { ImplicitAddress(RegisterID base) : base(base) , offset(0) { } ImplicitAddress(Address address) : base(address.base) , offset(address.offset) { } RegisterID base; int32_t offset; }; // BaseIndex: // // Describes a complex addressing mode. 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; }; // AbsoluteAddress: // // Describes an memory operand given by a pointer. For regular load & store // operations an unwrapped void* will be used, rather than using this. struct AbsoluteAddress { explicit AbsoluteAddress(const void* ptr) : m_ptr(ptr) { } const void* m_ptr; }; // TrustedImmPtr: // // A pointer sized immediate operand to an instruction - this is wrapped // in a class requiring explicit construction in order to differentiate // from pointers used as absolute addresses to memory operations struct TrustedImmPtr { TrustedImmPtr() { } explicit TrustedImmPtr(const void* value) : m_value(value) { } // This is only here so that TrustedImmPtr(0) does not confuse the C++ // overload handling rules. explicit TrustedImmPtr(int value) : m_value(0) { ASSERT_UNUSED(value, !value); } explicit TrustedImmPtr(size_t value) : m_value(reinterpret_cast(value)) { } intptr_t asIntptr() { return reinterpret_cast(m_value); } const void* m_value; }; struct ImmPtr : #if ENABLE(JIT_CONSTANT_BLINDING) private TrustedImmPtr #else public TrustedImmPtr #endif { explicit ImmPtr(const void* value) : TrustedImmPtr(value) { } TrustedImmPtr asTrustedImmPtr() { return *this; } }; // TrustedImm32: // // A 32bit immediate operand to an instruction - this is wrapped in a // class requiring explicit construction in order to prevent RegisterIDs // (which are implemented as an enum) from accidentally being passed as // immediate values. struct TrustedImm32 { TrustedImm32() { } explicit TrustedImm32(int32_t value) : m_value(value) { } #if !CPU(X86_64) explicit TrustedImm32(TrustedImmPtr ptr) : m_value(ptr.asIntptr()) { } #endif int32_t m_value; }; struct Imm32 : #if ENABLE(JIT_CONSTANT_BLINDING) private TrustedImm32 #else public TrustedImm32 #endif { explicit Imm32(int32_t value) : TrustedImm32(value) { } #if !CPU(X86_64) explicit Imm32(TrustedImmPtr ptr) : TrustedImm32(ptr) { } #endif const TrustedImm32& asTrustedImm32() const { return *this; } }; // TrustedImm64: // // A 64bit immediate operand to an instruction - this is wrapped in a // class requiring explicit construction in order to prevent RegisterIDs // (which are implemented as an enum) from accidentally being passed as // immediate values. struct TrustedImm64 { TrustedImm64() { } explicit TrustedImm64(int64_t value) : m_value(value) { } #if CPU(X86_64) || CPU(ARM64) explicit TrustedImm64(TrustedImmPtr ptr) : m_value(ptr.asIntptr()) { } #endif int64_t m_value; }; struct Imm64 : #if ENABLE(JIT_CONSTANT_BLINDING) private TrustedImm64 #else public TrustedImm64 #endif { explicit Imm64(int64_t value) : TrustedImm64(value) { } #if CPU(X86_64) || CPU(ARM64) explicit Imm64(TrustedImmPtr ptr) : TrustedImm64(ptr) { } #endif const TrustedImm64& asTrustedImm64() const { return *this; } }; // Section 2: MacroAssembler code buffer handles // // The following types are used to reference items in the code buffer // during JIT code generation. For example, the type Jump is used to // track the location of a jump instruction so that it may later be // linked to a label marking its destination. // Label: // // A Label records a point in the generated instruction stream, typically such that // it may be used as a destination for a jump. class Label { template friend class AbstractMacroAssembler; friend struct DFG::OSRExit; friend class Jump; friend class JumpReplacementWatchpoint; friend class MacroAssemblerCodeRef; template class> friend class LinkBufferBase; friend class Watchpoint; public: Label() { } Label(AbstractMacroAssembler* masm) : m_label(masm->m_assembler.label()) { } bool isSet() const { return m_label.isSet(); } const AssemblerLabel &label() const { return m_label; } private: AssemblerLabel m_label; }; // ConvertibleLoadLabel: // // A ConvertibleLoadLabel records a loadPtr instruction that can be patched to an addPtr // so that: // // loadPtr(Address(a, i), b) // // becomes: // // addPtr(TrustedImmPtr(i), a, b) class ConvertibleLoadLabel { template friend class AbstractMacroAssembler; template class> friend class LinkBufferBase; public: ConvertibleLoadLabel() { } ConvertibleLoadLabel(AbstractMacroAssembler* masm) : m_label(masm->m_assembler.labelIgnoringWatchpoints()) { } bool isSet() const { return m_label.isSet(); } private: AssemblerLabel m_label; }; // DataLabelPtr: // // A DataLabelPtr is used to refer to a location in the code containing a pointer to be // patched after the code has been generated. class DataLabelPtr { template friend class AbstractMacroAssembler; template class> friend class LinkBufferBase; public: DataLabelPtr() { } DataLabelPtr(AbstractMacroAssembler* masm) : m_label(masm->m_assembler.label()) { } bool isSet() const { return m_label.isSet(); } private: AssemblerLabel m_label; }; // DataLabel32: // // A DataLabelPtr is used to refer to a location in the code containing a pointer to be // patched after the code has been generated. class DataLabel32 { template friend class AbstractMacroAssembler; template class> friend class LinkBufferBase; public: DataLabel32() { } DataLabel32(AbstractMacroAssembler* masm) : m_label(masm->m_assembler.label()) { } AssemblerLabel label() const { return m_label; } private: AssemblerLabel m_label; }; // DataLabelCompact: // // A DataLabelCompact is used to refer to a location in the code containing a // compact immediate to be patched after the code has been generated. class DataLabelCompact { template friend class AbstractMacroAssembler; template class> friend class LinkBufferBase; public: DataLabelCompact() { } DataLabelCompact(AbstractMacroAssembler* masm) : m_label(masm->m_assembler.label()) { } DataLabelCompact(AssemblerLabel label) : m_label(label) { } private: AssemblerLabel m_label; }; #if CPU(ARM_THUMB2) || CPU(ARM64) || defined(V4_BOOTSTRAP) using Jump = typename AssemblerType::template Jump