| Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/qtdeclarative/src/qtdeclarative/src/3rdparty/masm/assembler/LinkBuffer.h |
| Source code | Switch to Preprocessed file |
| Line | Source | Count | ||||||
|---|---|---|---|---|---|---|---|---|
| 1 | /* | - | ||||||
| 2 | * Copyright (C) 2009, 2010, 2012 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 | #if ENABLE(ASSEMBLER) | - | ||||||
| 30 | - | |||||||
| 31 | #define DUMP_LINK_STATISTICS 0 | - | ||||||
| 32 | #define DUMP_CODE 0 | - | ||||||
| 33 | - | |||||||
| 34 | #define GLOBAL_THUNK_ID reinterpret_cast<void*>(static_cast<intptr_t>(-1)) | - | ||||||
| 35 | #define REGEXP_CODE_ID reinterpret_cast<void*>(static_cast<intptr_t>(-2)) | - | ||||||
| 36 | - | |||||||
| 37 | #include "JITCompilationEffort.h" | - | ||||||
| 38 | #include "MacroAssembler.h" | - | ||||||
| 39 | #include "Options.h" | - | ||||||
| 40 | #include <wtf/DataLog.h> | - | ||||||
| 41 | #include <wtf/Noncopyable.h> | - | ||||||
| 42 | - | |||||||
| 43 | namespace JSC { | - | ||||||
| 44 | - | |||||||
| 45 | class JSGlobalData; | - | ||||||
| 46 | - | |||||||
| 47 | template <typename T> | - | ||||||
| 48 | struct DefaultExecutableOffsetCalculator { | - | ||||||
| 49 | template <typename Assembler> | - | ||||||
| 50 | static T applyOffset(Assembler *, T src) { return src; } executed 1224 times by 10 tests: return src;Executed by:
| 1224 | ||||||
| 51 | }; | - | ||||||
| 52 | - | |||||||
| 53 | // LinkBuffer: | - | ||||||
| 54 | // | - | ||||||
| 55 | // This class assists in linking code generated by the macro assembler, once code generation | - | ||||||
| 56 | // has been completed, and the code has been copied to is final location in memory. At this | - | ||||||
| 57 | // time pointers to labels within the code may be resolved, and relative offsets to external | - | ||||||
| 58 | // addresses may be fixed. | - | ||||||
| 59 | // | - | ||||||
| 60 | // Specifically: | - | ||||||
| 61 | // * Jump objects may be linked to external targets, | - | ||||||
| 62 | // * The address of Jump objects may taken, such that it can later be relinked. | - | ||||||
| 63 | // * The return address of a Call may be acquired. | - | ||||||
| 64 | // * The address of a Label pointing into the code may be resolved. | - | ||||||
| 65 | // * The value referenced by a DataLabel may be set. | - | ||||||
| 66 | // | - | ||||||
| 67 | template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator> | - | ||||||
| 68 | class LinkBufferBase { | - | ||||||
| 69 | WTF_MAKE_NONCOPYABLE(LinkBufferBase); | - | ||||||
| 70 | typedef MacroAssemblerCodeRef CodeRef; | - | ||||||
| 71 | typedef MacroAssemblerCodePtr CodePtr; | - | ||||||
| 72 | typedef typename MacroAssembler::Label Label; | - | ||||||
| 73 | typedef typename MacroAssembler::Jump Jump; | - | ||||||
| 74 | typedef typename MacroAssembler::PatchableJump PatchableJump; | - | ||||||
| 75 | typedef typename MacroAssembler::JumpList JumpList; | - | ||||||
| 76 | typedef typename MacroAssembler::Call Call; | - | ||||||
| 77 | typedef typename MacroAssembler::DataLabelCompact DataLabelCompact; | - | ||||||
| 78 | typedef typename MacroAssembler::DataLabel32 DataLabel32; | - | ||||||
| 79 | typedef typename MacroAssembler::DataLabelPtr DataLabelPtr; | - | ||||||
| 80 | typedef typename MacroAssembler::ConvertibleLoadLabel ConvertibleLoadLabel; | - | ||||||
| 81 | - | |||||||
| 82 | public: | - | ||||||
| 83 | LinkBufferBase(JSGlobalData& globalData, MacroAssembler* masm, JITCompilationEffort effort = JITCompilationMustSucceed) | - | ||||||
| 84 | : m_size(0) | - | ||||||
| 85 | , m_code(0) | - | ||||||
| 86 | , m_assembler(masm) | - | ||||||
| 87 | , m_globalData(&globalData) | - | ||||||
| 88 | #ifndef NDEBUG | - | ||||||
| 89 | , m_completed(false) | - | ||||||
| 90 | , m_effort(effort) | - | ||||||
| 91 | #endif | - | ||||||
| 92 | { | - | ||||||
| 93 | #ifdef NDEBUG | - | ||||||
| 94 | UNUSED_PARAM(effort) | - | ||||||
| 95 | #endif | - | ||||||
| 96 | // Simon: Moved this to the sub-classes linkCode(ownerUID, effort); | - | ||||||
| 97 | } executed 1161222 times by 153 tests: end of blockExecuted by:
| 1161222 | ||||||
| 98 | - | |||||||
| 99 | ~LinkBufferBase() | - | ||||||
| 100 | { | - | ||||||
| 101 | ASSERT(m_completed || (!m_executableMemory && m_effort == JITCompilationCanFail)); | - | ||||||
| 102 | } executed 1164529 times by 153 tests: end of blockExecuted by:
| 1164529 | ||||||
| 103 | - | |||||||
| 104 | bool didFailToAllocate() const | - | ||||||
| 105 | { | - | ||||||
| 106 | return !m_executableMemory; executed 1163931 times by 153 tests: return !m_executableMemory;Executed by:
| 1163931 | ||||||
| 107 | } | - | ||||||
| 108 | - | |||||||
| 109 | bool isValid() const | - | ||||||
| 110 | { | - | ||||||
| 111 | return !didFailToAllocate(); executed 1163921 times by 153 tests: return !didFailToAllocate();Executed by:
| 1163921 | ||||||
| 112 | } | - | ||||||
| 113 | - | |||||||
| 114 | // These methods are used to link or set values at code generation time. | - | ||||||
| 115 | - | |||||||
| 116 | void link(Call call, FunctionPtr function) | - | ||||||
| 117 | { | - | ||||||
| 118 | ASSERT(call.isFlagSet(Call::Linkable)); | - | ||||||
| 119 | call.m_label = applyOffset(call.m_label); | - | ||||||
| 120 | MacroAssembler::linkCall(code(), call, function); | - | ||||||
| 121 | } never executed: end of block | 0 | ||||||
| 122 | - | |||||||
| 123 | void link(Jump jump, CodeLocationLabel label) | - | ||||||
| 124 | { | - | ||||||
| 125 | jump.m_label = applyOffset(jump.m_label); | - | ||||||
| 126 | MacroAssembler::linkJump(code(), jump, label); | - | ||||||
| 127 | } never executed: end of block | 0 | ||||||
| 128 | - | |||||||
| 129 | void link(JumpList list, CodeLocationLabel label) | - | ||||||
| 130 | { | - | ||||||
| 131 | for (unsigned i = 0; i < list.m_jumps.size(); ++i)
| 0 | ||||||
| 132 | link(list.m_jumps[i], label); never executed: link(list.m_jumps[i], label); | 0 | ||||||
| 133 | } never executed: end of block | 0 | ||||||
| 134 | - | |||||||
| 135 | void patch(DataLabelPtr label, void* value) | - | ||||||
| 136 | { | - | ||||||
| 137 | AssemblerLabel target = applyOffset(label.m_label); | - | ||||||
| 138 | MacroAssembler::linkPointer(code(), target, value); | - | ||||||
| 139 | } never executed: end of block | 0 | ||||||
| 140 | - | |||||||
| 141 | void patch(DataLabelPtr label, CodeLocationLabel value) | - | ||||||
| 142 | { | - | ||||||
| 143 | AssemblerLabel target = applyOffset(label.m_label); | - | ||||||
| 144 | MacroAssembler::linkPointer(code(), target, value.executableAddress()); | - | ||||||
| 145 | } executed 612 times by 10 tests: end of blockExecuted by:
| 612 | ||||||
| 146 | - | |||||||
| 147 | // These methods are used to obtain handles to allow the code to be relinked / repatched later. | - | ||||||
| 148 | - | |||||||
| 149 | CodeLocationCall locationOf(Call call) | - | ||||||
| 150 | { | - | ||||||
| 151 | ASSERT(call.isFlagSet(Call::Linkable)); | - | ||||||
| 152 | ASSERT(!call.isFlagSet(Call::Near)); | - | ||||||
| 153 | return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_label))); never executed: return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_label))); | 0 | ||||||
| 154 | } | - | ||||||
| 155 | - | |||||||
| 156 | CodeLocationNearCall locationOfNearCall(Call call) | - | ||||||
| 157 | { | - | ||||||
| 158 | ASSERT(call.isFlagSet(Call::Linkable)); | - | ||||||
| 159 | ASSERT(call.isFlagSet(Call::Near)); | - | ||||||
| 160 | return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_label))); never executed: return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_label))); | 0 | ||||||
| 161 | } | - | ||||||
| 162 | - | |||||||
| 163 | CodeLocationLabel locationOf(PatchableJump jump) | - | ||||||
| 164 | { | - | ||||||
| 165 | return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(jump.m_jump.m_label))); never executed: return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(jump.m_jump.m_label))); | 0 | ||||||
| 166 | } | - | ||||||
| 167 | - | |||||||
| 168 | CodeLocationLabel locationOf(Label label) | - | ||||||
| 169 | { | - | ||||||
| 170 | return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); executed 612 times by 10 tests: return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));Executed by:
| 612 | ||||||
| 171 | } | - | ||||||
| 172 | - | |||||||
| 173 | CodeLocationDataLabelPtr locationOf(DataLabelPtr label) | - | ||||||
| 174 | { | - | ||||||
| 175 | return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); never executed: return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); | 0 | ||||||
| 176 | } | - | ||||||
| 177 | - | |||||||
| 178 | CodeLocationDataLabel32 locationOf(DataLabel32 label) | - | ||||||
| 179 | { | - | ||||||
| 180 | return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); never executed: return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); | 0 | ||||||
| 181 | } | - | ||||||
| 182 | - | |||||||
| 183 | CodeLocationDataLabelCompact locationOf(DataLabelCompact label) | - | ||||||
| 184 | { | - | ||||||
| 185 | return CodeLocationDataLabelCompact(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); never executed: return CodeLocationDataLabelCompact(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); | 0 | ||||||
| 186 | } | - | ||||||
| 187 | - | |||||||
| 188 | CodeLocationConvertibleLoad locationOf(ConvertibleLoadLabel label) | - | ||||||
| 189 | { | - | ||||||
| 190 | return CodeLocationConvertibleLoad(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); never executed: return CodeLocationConvertibleLoad(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); | 0 | ||||||
| 191 | } | - | ||||||
| 192 | - | |||||||
| 193 | // This method obtains the return address of the call, given as an offset from | - | ||||||
| 194 | // the start of the code. | - | ||||||
| 195 | unsigned returnAddressOffset(Call call) | - | ||||||
| 196 | { | - | ||||||
| 197 | call.m_label = applyOffset(call.m_label); | - | ||||||
| 198 | return MacroAssembler::getLinkerCallReturnOffset(call); never executed: return MacroAssembler::getLinkerCallReturnOffset(call); | 0 | ||||||
| 199 | } | - | ||||||
| 200 | - | |||||||
| 201 | uint32_t offsetOf(Label label) | - | ||||||
| 202 | { | - | ||||||
| 203 | return applyOffset(label.m_label).m_offset; never executed: return applyOffset(label.m_label).m_offset; | 0 | ||||||
| 204 | } | - | ||||||
| 205 | - | |||||||
| 206 | // Upon completion of all patching 'FINALIZE_CODE()' should be called once to | - | ||||||
| 207 | // complete generation of the code. Alternatively, call | - | ||||||
| 208 | // finalizeCodeWithoutDisassembly() directly if you have your own way of | - | ||||||
| 209 | // displaying disassembly. | - | ||||||
| 210 | - | |||||||
| 211 | inline CodeRef finalizeCodeWithoutDisassembly(); | - | ||||||
| 212 | inline CodeRef finalizeCodeWithDisassembly(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3); | - | ||||||
| 213 | - | |||||||
| 214 | CodePtr trampolineAt(Label label) | - | ||||||
| 215 | { | - | ||||||
| 216 | return CodePtr(MacroAssembler::AssemblerType_T::getRelocatedAddress(code(), applyOffset(label.m_label))); never executed: return CodePtr(MacroAssembler::AssemblerType_T::getRelocatedAddress(code(), applyOffset(label.m_label))); | 0 | ||||||
| 217 | } | - | ||||||
| 218 | - | |||||||
| 219 | void* debugAddress() | - | ||||||
| 220 | { | - | ||||||
| 221 | return m_code; never executed: return m_code; | 0 | ||||||
| 222 | } | - | ||||||
| 223 | - | |||||||
| 224 | size_t debugSize() | - | ||||||
| 225 | { | - | ||||||
| 226 | return m_size; never executed: return m_size; | 0 | ||||||
| 227 | } | - | ||||||
| 228 | - | |||||||
| 229 | private: | - | ||||||
| 230 | template <typename T> T applyOffset(T src) | - | ||||||
| 231 | { | - | ||||||
| 232 | return ExecutableOffsetCalculator<T>::applyOffset(m_assembler, src); executed 1224 times by 10 tests: return ExecutableOffsetCalculator<T>::applyOffset(m_assembler, src);Executed by:
| 1224 | ||||||
| 233 | } | - | ||||||
| 234 | - | |||||||
| 235 | protected: | - | ||||||
| 236 | // Keep this private! - the underlying code should only be obtained externally via finalizeCode(). | - | ||||||
| 237 | void* code() | - | ||||||
| 238 | { | - | ||||||
| 239 | return m_code; executed 2329074 times by 153 tests: return m_code;Executed by:
| 2329074 | ||||||
| 240 | } | - | ||||||
| 241 | - | |||||||
| 242 | inline void linkCode(void* ownerUID, JITCompilationEffort); | - | ||||||
| 243 | - | |||||||
| 244 | inline void performFinalization(); | - | ||||||
| 245 | - | |||||||
| 246 | #if DUMP_LINK_STATISTICS | - | ||||||
| 247 | static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize); | - | ||||||
| 248 | #endif | - | ||||||
| 249 | - | |||||||
| 250 | #if DUMP_CODE | - | ||||||
| 251 | static void dumpCode(void* code, size_t); | - | ||||||
| 252 | #endif | - | ||||||
| 253 | - | |||||||
| 254 | RefPtr<ExecutableMemoryHandle> m_executableMemory; | - | ||||||
| 255 | size_t m_size; | - | ||||||
| 256 | void* m_code; | - | ||||||
| 257 | MacroAssembler* m_assembler; | - | ||||||
| 258 | JSGlobalData* m_globalData; | - | ||||||
| 259 | protected: | - | ||||||
| 260 | #ifndef NDEBUG | - | ||||||
| 261 | bool m_completed; | - | ||||||
| 262 | JITCompilationEffort m_effort; | - | ||||||
| 263 | #endif | - | ||||||
| 264 | }; | - | ||||||
| 265 | - | |||||||
| 266 | #define FINALIZE_CODE_IF(condition, linkBufferReference, dataLogFArgumentsForHeading) \ | - | ||||||
| 267 | (UNLIKELY((condition)) \ | - | ||||||
| 268 | ? ((linkBufferReference).finalizeCodeWithDisassembly dataLogFArgumentsForHeading) \ | - | ||||||
| 269 | : (linkBufferReference).finalizeCodeWithoutDisassembly()) | - | ||||||
| 270 | - | |||||||
| 271 | // Use this to finalize code, like so: | - | ||||||
| 272 | // | - | ||||||
| 273 | // CodeRef code = FINALIZE_CODE(linkBuffer, ("my super thingy number %d", number)); | - | ||||||
| 274 | // | - | ||||||
| 275 | // Which, in disassembly mode, will print: | - | ||||||
| 276 | // | - | ||||||
| 277 | // Generated JIT code for my super thingy number 42: | - | ||||||
| 278 | // Code at [0x123456, 0x234567]: | - | ||||||
| 279 | // 0x123456: mov $0, 0 | - | ||||||
| 280 | // 0x12345a: ret | - | ||||||
| 281 | // | - | ||||||
| 282 | // ... and so on. | - | ||||||
| 283 | // | - | ||||||
| 284 | // Note that the dataLogFArgumentsForHeading are only evaluated when showDisassembly | - | ||||||
| 285 | // is true, so you can hide expensive disassembly-only computations inside there. | - | ||||||
| 286 | - | |||||||
| 287 | #define FINALIZE_CODE(linkBufferReference, dataLogFArgumentsForHeading) \ | - | ||||||
| 288 | FINALIZE_CODE_IF(Options::showDisassembly(), linkBufferReference, dataLogFArgumentsForHeading) | - | ||||||
| 289 | - | |||||||
| 290 | #define FINALIZE_DFG_CODE(linkBufferReference, dataLogFArgumentsForHeading) \ | - | ||||||
| 291 | FINALIZE_CODE_IF((Options::showDisassembly() || Options::showDFGDisassembly()), linkBufferReference, dataLogFArgumentsForHeading) | - | ||||||
| 292 | - | |||||||
| 293 | - | |||||||
| 294 | template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator> | - | ||||||
| 295 | inline typename LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::CodeRef LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::finalizeCodeWithoutDisassembly() | - | ||||||
| 296 | { | - | ||||||
| 297 | performFinalization(); | - | ||||||
| 298 | - | |||||||
| 299 | return CodeRef(m_executableMemory); executed 1164557 times by 153 tests: return CodeRef(m_executableMemory);Executed by:
| 1164557 | ||||||
| 300 | } | - | ||||||
| 301 | - | |||||||
| 302 | template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator> | - | ||||||
| 303 | inline typename LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::CodeRef LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::finalizeCodeWithDisassembly(const char* format, ...) | - | ||||||
| 304 | { | - | ||||||
| 305 | ASSERT(Options::showDisassembly() || Options::showDFGDisassembly()); | - | ||||||
| 306 | - | |||||||
| 307 | CodeRef result = finalizeCodeWithoutDisassembly(); | - | ||||||
| 308 | - | |||||||
| 309 | dataLogF("Generated JIT code for "); | - | ||||||
| 310 | va_list argList; | - | ||||||
| 311 | va_start(argList, format); | - | ||||||
| 312 | WTF::dataLogFV(format, argList); | - | ||||||
| 313 | va_end(argList); | - | ||||||
| 314 | dataLogF(":\n"); | - | ||||||
| 315 | - | |||||||
| 316 | dataLogF( | - | ||||||
| 317 | #if OS(WINDOWS) | - | ||||||
| 318 | " Code at [0x%p, 0x%p):\n", | - | ||||||
| 319 | #else | - | ||||||
| 320 | " Code at [%p, %p):\n", | - | ||||||
| 321 | #endif | - | ||||||
| 322 | result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size()); | - | ||||||
| 323 | disassemble(result.code(), m_size, " ", WTF::dataFile()); | - | ||||||
| 324 | - | |||||||
| 325 | return result; never executed: return result; | 0 | ||||||
| 326 | } | - | ||||||
| 327 | - | |||||||
| 328 | template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator> | - | ||||||
| 329 | inline void LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::linkCode(void* ownerUID, JITCompilationEffort effort) | - | ||||||
| 330 | { | - | ||||||
| 331 | UNUSED_PARAM(ownerUID) | - | ||||||
| 332 | UNUSED_PARAM(effort) | - | ||||||
| 333 | ASSERT(!m_code); | - | ||||||
| 334 | m_executableMemory = m_assembler->m_assembler.executableCopy(*m_globalData, ownerUID, effort); | - | ||||||
| 335 | if (!m_executableMemory)
| 0-1163911 | ||||||
| 336 | return; never executed: return; | 0 | ||||||
| 337 | m_code = m_executableMemory->start(); | - | ||||||
| 338 | m_size = m_assembler->m_assembler.codeSize(); | - | ||||||
| 339 | ASSERT(m_code); | - | ||||||
| 340 | } executed 1163909 times by 153 tests: end of blockExecuted by:
| 1163909 | ||||||
| 341 | - | |||||||
| 342 | template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator> | - | ||||||
| 343 | inline void LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::performFinalization() | - | ||||||
| 344 | { | - | ||||||
| 345 | // NOTE: This function is specialized in LinkBuffer<MacroAssemblerARMv7> | - | ||||||
| 346 | #ifndef NDEBUG | - | ||||||
| 347 | ASSERT(!m_completed); | - | ||||||
| 348 | ASSERT(isValid()); | - | ||||||
| 349 | m_completed = true; | - | ||||||
| 350 | #endif | - | ||||||
| 351 | - | |||||||
| 352 | ASSERT(m_size <= INT_MAX); | - | ||||||
| 353 | MacroAssembler::cacheFlush(code(), m_size); | - | ||||||
| 354 | ExecutableAllocator::makeExecutable(code(), static_cast<int>(m_size)); | - | ||||||
| 355 | } executed 1164580 times by 153 tests: end of blockExecuted by:
| 1164580 | ||||||
| 356 | - | |||||||
| 357 | template <typename MacroAssembler> | - | ||||||
| 358 | class LinkBuffer : public LinkBufferBase<MacroAssembler, DefaultExecutableOffsetCalculator> | - | ||||||
| 359 | { | - | ||||||
| 360 | public: | - | ||||||
| 361 | LinkBuffer(JSGlobalData& globalData, MacroAssembler* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed) | - | ||||||
| 362 | : LinkBufferBase<MacroAssembler, DefaultExecutableOffsetCalculator>(globalData, masm, effort) | - | ||||||
| 363 | { | - | ||||||
| 364 | this->linkCode(ownerUID, effort); | - | ||||||
| 365 | } executed 1163976 times by 153 tests: end of blockExecuted by:
| 1163976 | ||||||
| 366 | }; | - | ||||||
| 367 | - | |||||||
| 368 | #if CPU(ARM_THUMB2) || CPU(ARM64) || defined(V4_BOOTSTRAP) | - | ||||||
| 369 | - | |||||||
| 370 | template <typename T> | - | ||||||
| 371 | struct BranchCompactingExecutableOffsetCalculator { | - | ||||||
| 372 | template <typename Assembler> | - | ||||||
| 373 | static T applyOffset(Assembler *as, T src) { | - | ||||||
| 374 | src.m_offset -= as->executableOffsetFor(src.m_offset); | - | ||||||
| 375 | return src; | - | ||||||
| 376 | } | - | ||||||
| 377 | }; | - | ||||||
| 378 | - | |||||||
| 379 | template <typename MacroAssembler> | - | ||||||
| 380 | class BranchCompactingLinkBuffer : public LinkBufferBase<MacroAssembler, BranchCompactingExecutableOffsetCalculator> | - | ||||||
| 381 | { | - | ||||||
| 382 | public: | - | ||||||
| 383 | BranchCompactingLinkBuffer(JSGlobalData& globalData, MacroAssembler* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed) | - | ||||||
| 384 | : LinkBufferBase<MacroAssembler, BranchCompactingExecutableOffsetCalculator>(globalData, masm, effort) | - | ||||||
| 385 | { | - | ||||||
| 386 | linkCode(ownerUID, effort); | - | ||||||
| 387 | } | - | ||||||
| 388 | - | |||||||
| 389 | inline void performFinalization(); | - | ||||||
| 390 | - | |||||||
| 391 | inline void linkCode(void* ownerUID, JITCompilationEffort); | - | ||||||
| 392 | - | |||||||
| 393 | private: | - | ||||||
| 394 | using Base = LinkBufferBase<MacroAssembler, BranchCompactingExecutableOffsetCalculator>; | - | ||||||
| 395 | #ifndef NDEBUG | - | ||||||
| 396 | using Base::m_completed; | - | ||||||
| 397 | #endif | - | ||||||
| 398 | using Base::isValid; | - | ||||||
| 399 | using Base::code; | - | ||||||
| 400 | using Base::m_code; | - | ||||||
| 401 | using Base::m_size; | - | ||||||
| 402 | using Base::m_assembler; | - | ||||||
| 403 | using Base::m_executableMemory; | - | ||||||
| 404 | using Base::m_globalData; | - | ||||||
| 405 | - | |||||||
| 406 | using LinkRecord = typename MacroAssembler::LinkRecord; | - | ||||||
| 407 | using JumpLinkType = typename MacroAssembler::JumpLinkType; | - | ||||||
| 408 | - | |||||||
| 409 | size_t m_initialSize = 0; | - | ||||||
| 410 | }; | - | ||||||
| 411 | - | |||||||
| 412 | template <typename MacroAssembler> | - | ||||||
| 413 | inline void BranchCompactingLinkBuffer<MacroAssembler>::performFinalization() | - | ||||||
| 414 | { | - | ||||||
| 415 | #ifndef NDEBUG | - | ||||||
| 416 | ASSERT(!m_completed); | - | ||||||
| 417 | ASSERT(isValid()); | - | ||||||
| 418 | this->m_completed = true; | - | ||||||
| 419 | #endif | - | ||||||
| 420 | - | |||||||
| 421 | MacroAssembler::cacheFlush(code(), m_size); | - | ||||||
| 422 | ExecutableAllocator::makeExecutable(code(), m_initialSize); | - | ||||||
| 423 | } | - | ||||||
| 424 | - | |||||||
| 425 | template <typename MacroAssembler> | - | ||||||
| 426 | inline void BranchCompactingLinkBuffer<MacroAssembler>::linkCode(void* ownerUID, JITCompilationEffort effort) | - | ||||||
| 427 | { | - | ||||||
| 428 | UNUSED_PARAM(ownerUID) | - | ||||||
| 429 | UNUSED_PARAM(effort) | - | ||||||
| 430 | ASSERT(!m_code); | - | ||||||
| 431 | m_initialSize = m_assembler->m_assembler.codeSize(); | - | ||||||
| 432 | m_executableMemory = m_globalData->executableAllocator.allocate(*m_globalData, m_initialSize, ownerUID, effort); | - | ||||||
| 433 | if (!m_executableMemory) | - | ||||||
| 434 | return; | - | ||||||
| 435 | m_code = (uint8_t*)m_executableMemory->start(); | - | ||||||
| 436 | ASSERT(m_code); | - | ||||||
| 437 | ExecutableAllocator::makeWritable(m_code, m_initialSize); | - | ||||||
| 438 | uint8_t* inData = (uint8_t*)m_assembler->unlinkedCode(); | - | ||||||
| 439 | uint8_t* outData = reinterpret_cast<uint8_t*>(m_code); | - | ||||||
| 440 | int readPtr = 0; | - | ||||||
| 441 | int writePtr = 0; | - | ||||||
| 442 | Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink = m_assembler->jumpsToLink(); | - | ||||||
| 443 | unsigned jumpCount = unsigned(jumpsToLink.size()); | - | ||||||
| 444 | for (unsigned i = 0; i < jumpCount; ++i) { | - | ||||||
| 445 | int offset = readPtr - writePtr; | - | ||||||
| 446 | ASSERT(!(offset & 1)); | - | ||||||
| 447 | - | |||||||
| 448 | // Copy the instructions from the last jump to the current one. | - | ||||||
| 449 | unsigned regionSize = unsigned(jumpsToLink[i].from() - readPtr); | - | ||||||
| 450 | uint16_t* copySource = reinterpret_cast_ptr<uint16_t*>(inData + readPtr); | - | ||||||
| 451 | uint16_t* copyEnd = reinterpret_cast_ptr<uint16_t*>(inData + readPtr + regionSize); | - | ||||||
| 452 | uint16_t* copyDst = reinterpret_cast_ptr<uint16_t*>(outData + writePtr); | - | ||||||
| 453 | ASSERT(!(regionSize % 2)); | - | ||||||
| 454 | ASSERT(!(readPtr % 2)); | - | ||||||
| 455 | ASSERT(!(writePtr % 2)); | - | ||||||
| 456 | while (copySource != copyEnd) | - | ||||||
| 457 | *copyDst++ = *copySource++; | - | ||||||
| 458 | m_assembler->recordLinkOffsets(readPtr, jumpsToLink[i].from(), offset); | - | ||||||
| 459 | readPtr += regionSize; | - | ||||||
| 460 | writePtr += regionSize; | - | ||||||
| 461 | - | |||||||
| 462 | // Calculate absolute address of the jump target, in the case of backwards | - | ||||||
| 463 | // branches we need to be precise, forward branches we are pessimistic | - | ||||||
| 464 | const uint8_t* target; | - | ||||||
| 465 | if (jumpsToLink[i].to() >= jumpsToLink[i].from()) | - | ||||||
| 466 | target = outData + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far | - | ||||||
| 467 | else | - | ||||||
| 468 | target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to()); | - | ||||||
| 469 | - | |||||||
| 470 | JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], outData + writePtr, target); | - | ||||||
| 471 | // Compact branch if we can... | - | ||||||
| 472 | if (m_assembler->canCompact(jumpsToLink[i].type())) { | - | ||||||
| 473 | // Step back in the write stream | - | ||||||
| 474 | int32_t delta = m_assembler->jumpSizeDelta(jumpsToLink[i].type(), jumpLinkType); | - | ||||||
| 475 | if (delta) { | - | ||||||
| 476 | writePtr -= delta; | - | ||||||
| 477 | m_assembler->recordLinkOffsets(jumpsToLink[i].from() - delta, readPtr, readPtr - writePtr); | - | ||||||
| 478 | } | - | ||||||
| 479 | } | - | ||||||
| 480 | jumpsToLink[i].setFrom(writePtr); | - | ||||||
| 481 | } | - | ||||||
| 482 | // Copy everything after the last jump | - | ||||||
| 483 | memcpy(outData + writePtr, inData + readPtr, m_initialSize - readPtr); | - | ||||||
| 484 | m_assembler->recordLinkOffsets(readPtr, unsigned(m_initialSize), readPtr - writePtr); | - | ||||||
| 485 | - | |||||||
| 486 | for (unsigned i = 0; i < jumpCount; ++i) { | - | ||||||
| 487 | uint8_t* location = outData + jumpsToLink[i].from(); | - | ||||||
| 488 | uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to()); | - | ||||||
| 489 | m_assembler->link(jumpsToLink[i], location, target); | - | ||||||
| 490 | } | - | ||||||
| 491 | - | |||||||
| 492 | jumpsToLink.clear(); | - | ||||||
| 493 | m_size = writePtr + m_initialSize - readPtr; | - | ||||||
| 494 | m_executableMemory->shrink(m_size); | - | ||||||
| 495 | } | - | ||||||
| 496 | - | |||||||
| 497 | #if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP) | - | ||||||
| 498 | template <> | - | ||||||
| 499 | class LinkBuffer<JSC::MacroAssembler<MacroAssemblerARMv7>> : public BranchCompactingLinkBuffer<JSC::MacroAssembler<MacroAssemblerARMv7>> | - | ||||||
| 500 | { | - | ||||||
| 501 | public: | - | ||||||
| 502 | LinkBuffer(JSGlobalData& globalData, JSC::MacroAssembler<MacroAssemblerARMv7>* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed) | - | ||||||
| 503 | : BranchCompactingLinkBuffer<JSC::MacroAssembler<MacroAssemblerARMv7>>(globalData, masm, ownerUID, effort) | - | ||||||
| 504 | {} | - | ||||||
| 505 | }; | - | ||||||
| 506 | #endif | - | ||||||
| 507 | - | |||||||
| 508 | #if CPU(ARM64) || defined(V4_BOOTSTRAP) | - | ||||||
| 509 | template <> | - | ||||||
| 510 | class LinkBuffer<JSC::MacroAssembler<MacroAssemblerARM64>> : public BranchCompactingLinkBuffer<JSC::MacroAssembler<MacroAssemblerARM64>> | - | ||||||
| 511 | { | - | ||||||
| 512 | public: | - | ||||||
| 513 | LinkBuffer(JSGlobalData& globalData, JSC::MacroAssembler<MacroAssemblerARM64>* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed) | - | ||||||
| 514 | : BranchCompactingLinkBuffer<JSC::MacroAssembler<JSC::MacroAssemblerARM64>>(globalData, masm, ownerUID, effort) | - | ||||||
| 515 | {} | - | ||||||
| 516 | }; | - | ||||||
| 517 | #endif | - | ||||||
| 518 | - | |||||||
| 519 | #endif | - | ||||||
| 520 | - | |||||||
| 521 | } // namespace JSC | - | ||||||
| 522 | - | |||||||
| 523 | #endif // ENABLE(ASSEMBLER) | - | ||||||
| 524 | - | |||||||
| 525 | #endif // LinkBuffer_h | - | ||||||
| Source code | Switch to Preprocessed file |