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