JavaScriptCore/assembler/AbstractMacroAssembler.h
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 <MacroAssemblerCodeRef.h>
       
    30 #include <CodeLocation.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(void* ptr)
       
   149             : m_ptr(ptr)
       
   150         {
       
   151         }
       
   152 
       
   153         void* m_ptr;
       
   154     };
       
   155 
       
   156     // ImmPtr:
       
   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 ImmPtr {
       
   162         explicit ImmPtr(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     // Imm32:
       
   176     //
       
   177     // A 32bit immediate operand to an instruction - this is wrapped in a
       
   178     // class requiring explicit construction in order to prevent RegisterIDs
       
   179     // (which are implemented as an enum) from accidentally being passed as
       
   180     // immediate values.
       
   181     struct Imm32 {
       
   182         explicit Imm32(int32_t value)
       
   183             : m_value(value)
       
   184 #if CPU(ARM) || CPU(MIPS)
       
   185             , m_isPointer(false)
       
   186 #endif
       
   187         {
       
   188         }
       
   189 
       
   190 #if !CPU(X86_64)
       
   191         explicit Imm32(ImmPtr ptr)
       
   192             : m_value(ptr.asIntptr())
       
   193 #if CPU(ARM) || CPU(MIPS)
       
   194             , m_isPointer(true)
       
   195 #endif
       
   196         {
       
   197         }
       
   198 #endif
       
   199 
       
   200         int32_t m_value;
       
   201 #if CPU(ARM) || CPU(MIPS)
       
   202         // We rely on being able to regenerate code to recover exception handling
       
   203         // information.  Since ARMv7 supports 16-bit immediates there is a danger
       
   204         // that if pointer values change the layout of the generated code will change.
       
   205         // To avoid this problem, always generate pointers (and thus Imm32s constructed
       
   206         // from ImmPtrs) with a code sequence that is able  to represent  any pointer
       
   207         // value - don't use a more compact form in these cases.
       
   208         // Same for MIPS.
       
   209         bool m_isPointer;
       
   210 #endif
       
   211     };
       
   212 
       
   213 
       
   214     // Section 2: MacroAssembler code buffer handles
       
   215     //
       
   216     // The following types are used to reference items in the code buffer
       
   217     // during JIT code generation.  For example, the type Jump is used to
       
   218     // track the location of a jump instruction so that it may later be
       
   219     // linked to a label marking its destination.
       
   220 
       
   221 
       
   222     // Label:
       
   223     //
       
   224     // A Label records a point in the generated instruction stream, typically such that
       
   225     // it may be used as a destination for a jump.
       
   226     class Label {
       
   227         template<class TemplateAssemblerType>
       
   228         friend class AbstractMacroAssembler;
       
   229         friend class Jump;
       
   230         friend class MacroAssemblerCodeRef;
       
   231         friend class LinkBuffer;
       
   232 
       
   233     public:
       
   234         Label()
       
   235         {
       
   236         }
       
   237 
       
   238         Label(AbstractMacroAssembler<AssemblerType>* masm)
       
   239             : m_label(masm->m_assembler.label())
       
   240         {
       
   241         }
       
   242         
       
   243         bool isUsed() const { return m_label.isUsed(); }
       
   244         void used() { m_label.used(); }
       
   245     private:
       
   246         JmpDst m_label;
       
   247     };
       
   248 
       
   249     // DataLabelPtr:
       
   250     //
       
   251     // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
       
   252     // patched after the code has been generated.
       
   253     class DataLabelPtr {
       
   254         template<class TemplateAssemblerType>
       
   255         friend class AbstractMacroAssembler;
       
   256         friend class LinkBuffer;
       
   257     public:
       
   258         DataLabelPtr()
       
   259         {
       
   260         }
       
   261 
       
   262         DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
       
   263             : m_label(masm->m_assembler.label())
       
   264         {
       
   265         }
       
   266         
       
   267     private:
       
   268         JmpDst m_label;
       
   269     };
       
   270 
       
   271     // DataLabel32:
       
   272     //
       
   273     // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
       
   274     // patched after the code has been generated.
       
   275     class DataLabel32 {
       
   276         template<class TemplateAssemblerType>
       
   277         friend class AbstractMacroAssembler;
       
   278         friend class LinkBuffer;
       
   279     public:
       
   280         DataLabel32()
       
   281         {
       
   282         }
       
   283 
       
   284         DataLabel32(AbstractMacroAssembler<AssemblerType>* masm)
       
   285             : m_label(masm->m_assembler.label())
       
   286         {
       
   287         }
       
   288 
       
   289     private:
       
   290         JmpDst m_label;
       
   291     };
       
   292 
       
   293     // Call:
       
   294     //
       
   295     // A Call object is a reference to a call instruction that has been planted
       
   296     // into the code buffer - it is typically used to link the call, setting the
       
   297     // relative offset such that when executed it will call to the desired
       
   298     // destination.
       
   299     class Call {
       
   300         template<class TemplateAssemblerType>
       
   301         friend class AbstractMacroAssembler;
       
   302 
       
   303     public:
       
   304         enum Flags {
       
   305             None = 0x0,
       
   306             Linkable = 0x1,
       
   307             Near = 0x2,
       
   308             LinkableNear = 0x3,
       
   309         };
       
   310 
       
   311         Call()
       
   312             : m_flags(None)
       
   313         {
       
   314         }
       
   315         
       
   316         Call(JmpSrc jmp, Flags flags)
       
   317             : m_jmp(jmp)
       
   318             , m_flags(flags)
       
   319         {
       
   320         }
       
   321 
       
   322         bool isFlagSet(Flags flag)
       
   323         {
       
   324             return m_flags & flag;
       
   325         }
       
   326 
       
   327         static Call fromTailJump(Jump jump)
       
   328         {
       
   329             return Call(jump.m_jmp, Linkable);
       
   330         }
       
   331 
       
   332         JmpSrc m_jmp;
       
   333     private:
       
   334         Flags m_flags;
       
   335     };
       
   336 
       
   337     // Jump:
       
   338     //
       
   339     // A jump object is a reference to a jump instruction that has been planted
       
   340     // into the code buffer - it is typically used to link the jump, setting the
       
   341     // relative offset such that when executed it will jump to the desired
       
   342     // destination.
       
   343     class Jump {
       
   344         template<class TemplateAssemblerType>
       
   345         friend class AbstractMacroAssembler;
       
   346         friend class Call;
       
   347         friend class LinkBuffer;
       
   348     public:
       
   349         Jump()
       
   350         {
       
   351         }
       
   352         
       
   353         Jump(JmpSrc jmp)    
       
   354             : m_jmp(jmp)
       
   355         {
       
   356         }
       
   357         
       
   358         void link(AbstractMacroAssembler<AssemblerType>* masm)
       
   359         {
       
   360             masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label());
       
   361         }
       
   362         
       
   363         void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
       
   364         {
       
   365             masm->m_assembler.linkJump(m_jmp, label.m_label);
       
   366         }
       
   367 
       
   368     private:
       
   369         JmpSrc m_jmp;
       
   370     };
       
   371 
       
   372     // JumpList:
       
   373     //
       
   374     // A JumpList is a set of Jump objects.
       
   375     // All jumps in the set will be linked to the same destination.
       
   376     class JumpList {
       
   377         friend class LinkBuffer;
       
   378 
       
   379     public:
       
   380         typedef Vector<Jump, 16> JumpVector;
       
   381 
       
   382         void link(AbstractMacroAssembler<AssemblerType>* masm)
       
   383         {
       
   384             size_t size = m_jumps.size();
       
   385             for (size_t i = 0; i < size; ++i)
       
   386                 m_jumps[i].link(masm);
       
   387             m_jumps.clear();
       
   388         }
       
   389         
       
   390         void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
       
   391         {
       
   392             size_t size = m_jumps.size();
       
   393             for (size_t i = 0; i < size; ++i)
       
   394                 m_jumps[i].linkTo(label, masm);
       
   395             m_jumps.clear();
       
   396         }
       
   397         
       
   398         void append(Jump jump)
       
   399         {
       
   400             m_jumps.append(jump);
       
   401         }
       
   402         
       
   403         void append(JumpList& other)
       
   404         {
       
   405             m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
       
   406         }
       
   407 
       
   408         bool empty()
       
   409         {
       
   410             return !m_jumps.size();
       
   411         }
       
   412         
       
   413         const JumpVector& jumps() { return m_jumps; }
       
   414 
       
   415     private:
       
   416         JumpVector m_jumps;
       
   417     };
       
   418 
       
   419 
       
   420     // Section 3: Misc admin methods
       
   421 
       
   422     static CodePtr trampolineAt(CodeRef ref, Label label)
       
   423     {
       
   424         return CodePtr(AssemblerType::getRelocatedAddress(ref.m_code.dataLocation(), label.m_label));
       
   425     }
       
   426 
       
   427     size_t size()
       
   428     {
       
   429         return m_assembler.size();
       
   430     }
       
   431 
       
   432     Label label()
       
   433     {
       
   434         return Label(this);
       
   435     }
       
   436     
       
   437     Label align()
       
   438     {
       
   439         m_assembler.align(16);
       
   440         return Label(this);
       
   441     }
       
   442 
       
   443     ptrdiff_t differenceBetween(Label from, Jump to)
       
   444     {
       
   445         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
       
   446     }
       
   447 
       
   448     ptrdiff_t differenceBetween(Label from, Call to)
       
   449     {
       
   450         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
       
   451     }
       
   452 
       
   453     ptrdiff_t differenceBetween(Label from, Label to)
       
   454     {
       
   455         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
       
   456     }
       
   457 
       
   458     ptrdiff_t differenceBetween(Label from, DataLabelPtr to)
       
   459     {
       
   460         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
       
   461     }
       
   462 
       
   463     ptrdiff_t differenceBetween(Label from, DataLabel32 to)
       
   464     {
       
   465         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
       
   466     }
       
   467 
       
   468     ptrdiff_t differenceBetween(DataLabelPtr from, Jump to)
       
   469     {
       
   470         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
       
   471     }
       
   472 
       
   473     ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to)
       
   474     {
       
   475         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
       
   476     }
       
   477 
       
   478     ptrdiff_t differenceBetween(DataLabelPtr from, Call to)
       
   479     {
       
   480         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
       
   481     }
       
   482 
       
   483 protected:
       
   484     AssemblerType m_assembler;
       
   485 
       
   486     friend class LinkBuffer;
       
   487     friend class RepatchBuffer;
       
   488 
       
   489     static void linkJump(void* code, Jump jump, CodeLocationLabel target)
       
   490     {
       
   491         AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation());
       
   492     }
       
   493 
       
   494     static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value)
       
   495     {
       
   496         AssemblerType::linkPointer(code, label, value);
       
   497     }
       
   498 
       
   499     static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label)
       
   500     {
       
   501         return AssemblerType::getRelocatedAddress(code, label);
       
   502     }
       
   503 
       
   504     static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label)
       
   505     {
       
   506         return AssemblerType::getRelocatedAddress(code, label);
       
   507     }
       
   508 
       
   509     static unsigned getLinkerCallReturnOffset(Call call)
       
   510     {
       
   511         return AssemblerType::getCallReturnOffset(call.m_jmp);
       
   512     }
       
   513 
       
   514     static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination)
       
   515     {
       
   516         AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation());
       
   517     }
       
   518 
       
   519     static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination)
       
   520     {
       
   521         AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
       
   522     }
       
   523 
       
   524     static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value)
       
   525     {
       
   526         AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
       
   527     }
       
   528 
       
   529     static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value)
       
   530     {
       
   531         AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
       
   532     }
       
   533 
       
   534     static void repatchLoadPtrToLEA(CodeLocationInstruction instruction)
       
   535     {
       
   536         AssemblerType::repatchLoadPtrToLEA(instruction.dataLocation());
       
   537     }
       
   538 };
       
   539 
       
   540 } // namespace JSC
       
   541 
       
   542 #endif // ENABLE(ASSEMBLER)
       
   543 
       
   544 #endif // AbstractMacroAssembler_h