| 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(allocator: 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: code(), call, function); | 
| 86 |     } | 
| 87 |      | 
| 88 |     void link(Jump jump, CodeLocationLabel label) | 
| 89 |     { | 
| 90 |         MacroAssembler::linkJump(code: code(), jump, target: 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: code(), jump: list.m_jumps[i], target: label); | 
| 97 |     } | 
| 98 |  | 
| 99 |     void patch(DataLabelPtr label, void* value) | 
| 100 |     { | 
| 101 |         MacroAssembler::linkPointer(code: code(), label: label.m_label, value); | 
| 102 |     } | 
| 103 |  | 
| 104 |     void patch(DataLabelPtr label, CodeLocationLabel value) | 
| 105 |     { | 
| 106 |         MacroAssembler::linkPointer(code: code(), label: label.m_label, value: 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: code(), label: 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: code(), label: call.m_jmp)); | 
| 123 |     } | 
| 124 |  | 
| 125 |     CodeLocationLabel locationOf(Label label) | 
| 126 |     { | 
| 127 |         return CodeLocationLabel(MacroAssembler::getLinkerAddress(code: code(), label: label.m_label)); | 
| 128 |     } | 
| 129 |  | 
| 130 |     CodeLocationDataLabelPtr locationOf(DataLabelPtr label) | 
| 131 |     { | 
| 132 |         return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code: code(), label: label.m_label)); | 
| 133 |     } | 
| 134 |  | 
| 135 |     CodeLocationDataLabel32 locationOf(DataLabel32 label) | 
| 136 |     { | 
| 137 |         return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code: code(), label: 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 |  |