Home | History | Annotate | Download | only in assembler
      1 /*
      2  * Copyright (C) 2008 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #ifndef AbstractMacroAssembler_h
     27 #define AbstractMacroAssembler_h
     28 
     29 #include "CodeLocation.h"
     30 #include "MacroAssemblerCodeRef.h"
     31 #include <wtf/Noncopyable.h>
     32 #include <wtf/UnusedParam.h>
     33 
     34 #if ENABLE(ASSEMBLER)
     35 
     36 namespace JSC {
     37 
     38 class LinkBuffer;
     39 class RepatchBuffer;
     40 
     41 template <class AssemblerType>
     42 class AbstractMacroAssembler {
     43 public:
     44     typedef AssemblerType AssemblerType_T;
     45 
     46     typedef MacroAssemblerCodePtr CodePtr;
     47     typedef MacroAssemblerCodeRef CodeRef;
     48 
     49     class Jump;
     50 
     51     typedef typename AssemblerType::RegisterID RegisterID;
     52     typedef typename AssemblerType::JmpSrc JmpSrc;
     53     typedef typename AssemblerType::JmpDst JmpDst;
     54 
     55 
     56     // Section 1: MacroAssembler operand types
     57     //
     58     // The following types are used as operands to MacroAssembler operations,
     59     // describing immediate  and memory operands to the instructions to be planted.
     60 
     61 
     62     enum Scale {
     63         TimesOne,
     64         TimesTwo,
     65         TimesFour,
     66         TimesEight,
     67     };
     68 
     69     // Address:
     70     //
     71     // Describes a simple base-offset address.
     72     struct Address {
     73         explicit Address(RegisterID base, int32_t offset = 0)
     74             : base(base)
     75             , offset(offset)
     76         {
     77         }
     78 
     79         RegisterID base;
     80         int32_t offset;
     81     };
     82 
     83     struct ExtendedAddress {
     84         explicit ExtendedAddress(RegisterID base, intptr_t offset = 0)
     85             : base(base)
     86             , offset(offset)
     87         {
     88         }
     89 
     90         RegisterID base;
     91         intptr_t offset;
     92     };
     93 
     94     // ImplicitAddress:
     95     //
     96     // This class is used for explicit 'load' and 'store' operations
     97     // (as opposed to situations in which a memory operand is provided
     98     // to a generic operation, such as an integer arithmetic instruction).
     99     //
    100     // In the case of a load (or store) operation we want to permit
    101     // addresses to be implicitly constructed, e.g. the two calls:
    102     //
    103     //     load32(Address(addrReg), destReg);
    104     //     load32(addrReg, destReg);
    105     //
    106     // Are equivalent, and the explicit wrapping of the Address in the former
    107     // is unnecessary.
    108     struct ImplicitAddress {
    109         ImplicitAddress(RegisterID base)
    110             : base(base)
    111             , offset(0)
    112         {
    113         }
    114 
    115         ImplicitAddress(Address address)
    116             : base(address.base)
    117             , offset(address.offset)
    118         {
    119         }
    120 
    121         RegisterID base;
    122         int32_t offset;
    123     };
    124 
    125     // BaseIndex:
    126     //
    127     // Describes a complex addressing mode.
    128     struct BaseIndex {
    129         BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
    130             : base(base)
    131             , index(index)
    132             , scale(scale)
    133             , offset(offset)
    134         {
    135         }
    136 
    137         RegisterID base;
    138         RegisterID index;
    139         Scale scale;
    140         int32_t offset;
    141     };
    142 
    143     // AbsoluteAddress:
    144     //
    145     // Describes an memory operand given by a pointer.  For regular load & store
    146     // operations an unwrapped void* will be used, rather than using this.
    147     struct AbsoluteAddress {
    148         explicit AbsoluteAddress(const void* ptr)
    149             : m_ptr(ptr)
    150         {
    151         }
    152 
    153         const void* m_ptr;
    154     };
    155 
    156     // TrustedImmPtr:
    157     //
    158     // A pointer sized immediate operand to an instruction - this is wrapped
    159     // in a class requiring explicit construction in order to differentiate
    160     // from pointers used as absolute addresses to memory operations
    161     struct TrustedImmPtr {
    162         explicit TrustedImmPtr(const void* value)
    163             : m_value(value)
    164         {
    165         }
    166 
    167         intptr_t asIntptr()
    168         {
    169             return reinterpret_cast<intptr_t>(m_value);
    170         }
    171 
    172         const void* m_value;
    173     };
    174 
    175     struct ImmPtr : public TrustedImmPtr {
    176         explicit ImmPtr(const void* value)
    177             : TrustedImmPtr(value)
    178         {
    179         }
    180     };
    181 
    182     // TrustedImm32:
    183     //
    184     // A 32bit immediate operand to an instruction - this is wrapped in a
    185     // class requiring explicit construction in order to prevent RegisterIDs
    186     // (which are implemented as an enum) from accidentally being passed as
    187     // immediate values.
    188     struct TrustedImm32 {
    189         explicit TrustedImm32(int32_t value)
    190             : m_value(value)
    191 #if CPU(ARM) || CPU(MIPS)
    192             , m_isPointer(false)
    193 #endif
    194         {
    195         }
    196 
    197 #if !CPU(X86_64)
    198         explicit TrustedImm32(TrustedImmPtr ptr)
    199             : m_value(ptr.asIntptr())
    200 #if CPU(ARM) || CPU(MIPS)
    201             , m_isPointer(true)
    202 #endif
    203         {
    204         }
    205 #endif
    206 
    207         int32_t m_value;
    208 #if CPU(ARM) || CPU(MIPS)
    209         // We rely on being able to regenerate code to recover exception handling
    210         // information.  Since ARMv7 supports 16-bit immediates there is a danger
    211         // that if pointer values change the layout of the generated code will change.
    212         // To avoid this problem, always generate pointers (and thus Imm32s constructed
    213         // from ImmPtrs) with a code sequence that is able  to represent  any pointer
    214         // value - don't use a more compact form in these cases.
    215         // Same for MIPS.
    216         bool m_isPointer;
    217 #endif
    218     };
    219 
    220 
    221     struct Imm32 : public TrustedImm32 {
    222         explicit Imm32(int32_t value)
    223             : TrustedImm32(value)
    224         {
    225         }
    226 #if !CPU(X86_64)
    227         explicit Imm32(TrustedImmPtr ptr)
    228             : TrustedImm32(ptr)
    229         {
    230         }
    231 #endif
    232     };
    233 
    234     // Section 2: MacroAssembler code buffer handles
    235     //
    236     // The following types are used to reference items in the code buffer
    237     // during JIT code generation.  For example, the type Jump is used to
    238     // track the location of a jump instruction so that it may later be
    239     // linked to a label marking its destination.
    240 
    241 
    242     // Label:
    243     //
    244     // A Label records a point in the generated instruction stream, typically such that
    245     // it may be used as a destination for a jump.
    246     class Label {
    247         template<class TemplateAssemblerType>
    248         friend class AbstractMacroAssembler;
    249         friend class Jump;
    250         friend class MacroAssemblerCodeRef;
    251         friend class LinkBuffer;
    252 
    253     public:
    254         Label()
    255         {
    256         }
    257 
    258         Label(AbstractMacroAssembler<AssemblerType>* masm)
    259             : m_label(masm->m_assembler.label())
    260         {
    261         }
    262 
    263         bool isUsed() const { return m_label.isUsed(); }
    264         bool isSet() const { return m_label.isSet(); }
    265         void used() { m_label.used(); }
    266     private:
    267         JmpDst m_label;
    268     };
    269 
    270     // DataLabelPtr:
    271     //
    272     // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
    273     // patched after the code has been generated.
    274     class DataLabelPtr {
    275         template<class TemplateAssemblerType>
    276         friend class AbstractMacroAssembler;
    277         friend class LinkBuffer;
    278     public:
    279         DataLabelPtr()
    280         {
    281         }
    282 
    283         DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
    284             : m_label(masm->m_assembler.label())
    285         {
    286         }
    287 
    288         bool isSet() const { return m_label.isSet(); }
    289 
    290     private:
    291         JmpDst m_label;
    292     };
    293 
    294     // DataLabel32:
    295     //
    296     // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
    297     // patched after the code has been generated.
    298     class DataLabel32 {
    299         template<class TemplateAssemblerType>
    300         friend class AbstractMacroAssembler;
    301         friend class LinkBuffer;
    302     public:
    303         DataLabel32()
    304         {
    305         }
    306 
    307         DataLabel32(AbstractMacroAssembler<AssemblerType>* masm)
    308             : m_label(masm->m_assembler.label())
    309         {
    310         }
    311 
    312     private:
    313         JmpDst m_label;
    314     };
    315 
    316     // Call:
    317     //
    318     // A Call object is a reference to a call instruction that has been planted
    319     // into the code buffer - it is typically used to link the call, setting the
    320     // relative offset such that when executed it will call to the desired
    321     // destination.
    322     class Call {
    323         template<class TemplateAssemblerType>
    324         friend class AbstractMacroAssembler;
    325 
    326     public:
    327         enum Flags {
    328             None = 0x0,
    329             Linkable = 0x1,
    330             Near = 0x2,
    331             LinkableNear = 0x3,
    332         };
    333 
    334         Call()
    335             : m_flags(None)
    336         {
    337         }
    338 
    339         Call(JmpSrc jmp, Flags flags)
    340             : m_jmp(jmp)
    341             , m_flags(flags)
    342         {
    343         }
    344 
    345         bool isFlagSet(Flags flag)
    346         {
    347             return m_flags & flag;
    348         }
    349 
    350         static Call fromTailJump(Jump jump)
    351         {
    352             return Call(jump.m_jmp, Linkable);
    353         }
    354 
    355         JmpSrc m_jmp;
    356     private:
    357         Flags m_flags;
    358     };
    359 
    360     // Jump:
    361     //
    362     // A jump object is a reference to a jump instruction that has been planted
    363     // into the code buffer - it is typically used to link the jump, setting the
    364     // relative offset such that when executed it will jump to the desired
    365     // destination.
    366     class Jump {
    367         template<class TemplateAssemblerType>
    368         friend class AbstractMacroAssembler;
    369         friend class Call;
    370         friend class LinkBuffer;
    371     public:
    372         Jump()
    373         {
    374         }
    375 
    376         Jump(JmpSrc jmp)
    377             : m_jmp(jmp)
    378         {
    379         }
    380 
    381         void link(AbstractMacroAssembler<AssemblerType>* masm) const
    382         {
    383             masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label());
    384         }
    385 
    386         void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) const
    387         {
    388             masm->m_assembler.linkJump(m_jmp, label.m_label);
    389         }
    390 
    391         bool isSet() const { return m_jmp.isSet(); }
    392 
    393     private:
    394         JmpSrc m_jmp;
    395     };
    396 
    397     // JumpList:
    398     //
    399     // A JumpList is a set of Jump objects.
    400     // All jumps in the set will be linked to the same destination.
    401     class JumpList {
    402         friend class LinkBuffer;
    403 
    404     public:
    405         typedef Vector<Jump, 16> JumpVector;
    406 
    407         void link(AbstractMacroAssembler<AssemblerType>* masm)
    408         {
    409             size_t size = m_jumps.size();
    410             for (size_t i = 0; i < size; ++i)
    411                 m_jumps[i].link(masm);
    412             m_jumps.clear();
    413         }
    414 
    415         void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
    416         {
    417             size_t size = m_jumps.size();
    418             for (size_t i = 0; i < size; ++i)
    419                 m_jumps[i].linkTo(label, masm);
    420             m_jumps.clear();
    421         }
    422 
    423         void append(Jump jump)
    424         {
    425             m_jumps.append(jump);
    426         }
    427 
    428         void append(JumpList& other)
    429         {
    430             m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
    431         }
    432 
    433         bool empty()
    434         {
    435             return !m_jumps.size();
    436         }
    437 
    438         void clear()
    439         {
    440             m_jumps.clear();
    441         }
    442 
    443         const JumpVector& jumps() { return m_jumps; }
    444 
    445     private:
    446         JumpVector m_jumps;
    447     };
    448 
    449 
    450     // Section 3: Misc admin methods
    451     size_t size()
    452     {
    453         return m_assembler.size();
    454     }
    455 
    456     Label label()
    457     {
    458         return Label(this);
    459     }
    460 
    461     Label align()
    462     {
    463         m_assembler.align(16);
    464         return Label(this);
    465     }
    466 
    467     ptrdiff_t differenceBetween(Label from, Jump to)
    468     {
    469         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
    470     }
    471 
    472     ptrdiff_t differenceBetween(Label from, Call to)
    473     {
    474         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
    475     }
    476 
    477     ptrdiff_t differenceBetween(Label from, Label to)
    478     {
    479         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
    480     }
    481 
    482     ptrdiff_t differenceBetween(Label from, DataLabelPtr to)
    483     {
    484         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
    485     }
    486 
    487     ptrdiff_t differenceBetween(Label from, DataLabel32 to)
    488     {
    489         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
    490     }
    491 
    492     ptrdiff_t differenceBetween(DataLabelPtr from, Jump to)
    493     {
    494         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
    495     }
    496 
    497     ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to)
    498     {
    499         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
    500     }
    501 
    502     ptrdiff_t differenceBetween(DataLabelPtr from, Call to)
    503     {
    504         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
    505     }
    506 
    507     // Temporary interface; likely to be removed, since may be hard to port to all architectures.
    508 #if CPU(X86) || CPU(X86_64)
    509     void rewindToLabel(Label rewindTo) { m_assembler.rewindToLabel(rewindTo.m_label); }
    510 #endif
    511 
    512     void beginUninterruptedSequence() { }
    513     void endUninterruptedSequence() { }
    514 
    515 #ifndef NDEBUG
    516     unsigned debugOffset() { return m_assembler.debugOffset(); }
    517 #endif
    518 
    519 protected:
    520     AssemblerType m_assembler;
    521 
    522     friend class LinkBuffer;
    523     friend class RepatchBuffer;
    524 
    525     static void linkJump(void* code, Jump jump, CodeLocationLabel target)
    526     {
    527         AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation());
    528     }
    529 
    530     static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value)
    531     {
    532         AssemblerType::linkPointer(code, label, value);
    533     }
    534 
    535     static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label)
    536     {
    537         return AssemblerType::getRelocatedAddress(code, label);
    538     }
    539 
    540     static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label)
    541     {
    542         return AssemblerType::getRelocatedAddress(code, label);
    543     }
    544 
    545     static unsigned getLinkerCallReturnOffset(Call call)
    546     {
    547         return AssemblerType::getCallReturnOffset(call.m_jmp);
    548     }
    549 
    550     static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination)
    551     {
    552         AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation());
    553     }
    554 
    555     static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination)
    556     {
    557         AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
    558     }
    559 
    560     static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value)
    561     {
    562         AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
    563     }
    564 
    565     static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value)
    566     {
    567         AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
    568     }
    569 };
    570 
    571 } // namespace JSC
    572 
    573 #endif // ENABLE(ASSEMBLER)
    574 
    575 #endif // AbstractMacroAssembler_h
    576