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 block Executed by:
| 1161222 | ||||||
98 | - | |||||||
99 | ~LinkBufferBase() | - | ||||||
100 | { | - | ||||||
101 | ASSERT(m_completed || (!m_executableMemory && m_effort == JITCompilationCanFail)); | - | ||||||
102 | } executed 1164529 times by 153 tests: end of block Executed 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 block Executed 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 block Executed 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 block Executed 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 block Executed 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 |