Home | History | Annotate | Download | only in assembler
      1 /*
      2  * Copyright (C) 2009 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 LinkBuffer_h
     27 #define LinkBuffer_h
     28 
     29 #include <wtf/Platform.h>
     30 
     31 #if ENABLE(ASSEMBLER)
     32 
     33 #include <MacroAssembler.h>
     34 #include <wtf/Noncopyable.h>
     35 
     36 namespace JSC {
     37 
     38 // LinkBuffer:
     39 //
     40 // This class assists in linking code generated by the macro assembler, once code generation
     41 // has been completed, and the code has been copied to is final location in memory.  At this
     42 // time pointers to labels within the code may be resolved, and relative offsets to external
     43 // addresses may be fixed.
     44 //
     45 // Specifically:
     46 //   * Jump objects may be linked to external targets,
     47 //   * The address of Jump objects may taken, such that it can later be relinked.
     48 //   * The return address of a Call may be acquired.
     49 //   * The address of a Label pointing into the code may be resolved.
     50 //   * The value referenced by a DataLabel may be set.
     51 //
     52 class LinkBuffer : public Noncopyable {
     53     typedef MacroAssemblerCodeRef CodeRef;
     54     typedef MacroAssembler::Label Label;
     55     typedef MacroAssembler::Jump Jump;
     56     typedef MacroAssembler::JumpList JumpList;
     57     typedef MacroAssembler::Call Call;
     58     typedef MacroAssembler::DataLabel32 DataLabel32;
     59     typedef MacroAssembler::DataLabelPtr DataLabelPtr;
     60 
     61 public:
     62     // Note: Initialization sequence is significant, since executablePool is a PassRefPtr.
     63     //       First, executablePool is copied into m_executablePool, then the initialization of
     64     //       m_code uses m_executablePool, *not* executablePool, since this is no longer valid.
     65     LinkBuffer(MacroAssembler* masm, PassRefPtr<ExecutablePool> executablePool)
     66         : m_executablePool(executablePool)
     67         , m_code(masm->m_assembler.executableCopy(m_executablePool.get()))
     68         , m_size(masm->m_assembler.size())
     69 #ifndef NDEBUG
     70         , m_completed(false)
     71 #endif
     72     {
     73     }
     74 
     75     ~LinkBuffer()
     76     {
     77         ASSERT(m_completed);
     78     }
     79 
     80     // These methods are used to link or set values at code generation time.
     81 
     82     void link(Call call, FunctionPtr function)
     83     {
     84         ASSERT(call.isFlagSet(Call::Linkable));
     85         MacroAssembler::linkCall(code(), call, function);
     86     }
     87 
     88     void link(Jump jump, CodeLocationLabel label)
     89     {
     90         MacroAssembler::linkJump(code(), jump, label);
     91     }
     92 
     93     void link(JumpList list, CodeLocationLabel label)
     94     {
     95         for (unsigned i = 0; i < list.m_jumps.size(); ++i)
     96             MacroAssembler::linkJump(code(), list.m_jumps[i], label);
     97     }
     98 
     99     void patch(DataLabelPtr label, void* value)
    100     {
    101         MacroAssembler::linkPointer(code(), label.m_label, value);
    102     }
    103 
    104     void patch(DataLabelPtr label, CodeLocationLabel value)
    105     {
    106         MacroAssembler::linkPointer(code(), label.m_label, value.executableAddress());
    107     }
    108 
    109     // These methods are used to obtain handles to allow the code to be relinked / repatched later.
    110 
    111     CodeLocationCall locationOf(Call call)
    112     {
    113         ASSERT(call.isFlagSet(Call::Linkable));
    114         ASSERT(!call.isFlagSet(Call::Near));
    115         return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp));
    116     }
    117 
    118     CodeLocationNearCall locationOfNearCall(Call call)
    119     {
    120         ASSERT(call.isFlagSet(Call::Linkable));
    121         ASSERT(call.isFlagSet(Call::Near));
    122         return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp));
    123     }
    124 
    125     CodeLocationLabel locationOf(Label label)
    126     {
    127         return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), label.m_label));
    128     }
    129 
    130     CodeLocationDataLabelPtr locationOf(DataLabelPtr label)
    131     {
    132         return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), label.m_label));
    133     }
    134 
    135     CodeLocationDataLabel32 locationOf(DataLabel32 label)
    136     {
    137         return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), label.m_label));
    138     }
    139 
    140     // This method obtains the return address of the call, given as an offset from
    141     // the start of the code.
    142     unsigned returnAddressOffset(Call call)
    143     {
    144         return MacroAssembler::getLinkerCallReturnOffset(call);
    145     }
    146 
    147     // Upon completion of all patching either 'finalizeCode()' or 'finalizeCodeAddendum()' should be called
    148     // once to complete generation of the code.  'finalizeCode()' is suited to situations
    149     // where the executable pool must also be retained, the lighter-weight 'finalizeCodeAddendum()' is
    150     // suited to adding to an existing allocation.
    151     CodeRef finalizeCode()
    152     {
    153         performFinalization();
    154 
    155         return CodeRef(m_code, m_executablePool, m_size);
    156     }
    157     CodeLocationLabel finalizeCodeAddendum()
    158     {
    159         performFinalization();
    160 
    161         return CodeLocationLabel(code());
    162     }
    163 
    164 private:
    165     // Keep this private! - the underlying code should only be obtained externally via
    166     // finalizeCode() or finalizeCodeAddendum().
    167     void* code()
    168     {
    169         return m_code;
    170     }
    171 
    172     void performFinalization()
    173     {
    174 #ifndef NDEBUG
    175         ASSERT(!m_completed);
    176         m_completed = true;
    177 #endif
    178 
    179         ExecutableAllocator::makeExecutable(code(), m_size);
    180         ExecutableAllocator::cacheFlush(code(), m_size);
    181     }
    182 
    183     RefPtr<ExecutablePool> m_executablePool;
    184     void* m_code;
    185     size_t m_size;
    186 #ifndef NDEBUG
    187     bool m_completed;
    188 #endif
    189 };
    190 
    191 } // namespace JSC
    192 
    193 #endif // ENABLE(ASSEMBLER)
    194 
    195 #endif // LinkBuffer_h
    196