1 | /* |
2 | * Copyright (C) 2009-2018 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 | #pragma once |
27 | |
28 | #if ENABLE(ASSEMBLER) |
29 | |
30 | #define DUMP_LINK_STATISTICS 0 |
31 | #define DUMP_CODE 0 |
32 | |
33 | #define GLOBAL_THUNK_ID reinterpret_cast<void*>(static_cast<intptr_t>(-1)) |
34 | #define REGEXP_CODE_ID reinterpret_cast<void*>(static_cast<intptr_t>(-2)) |
35 | #define CSS_CODE_ID reinterpret_cast<void*>(static_cast<intptr_t>(-3)) |
36 | |
37 | #include "JITCompilationEffort.h" |
38 | #include "MacroAssembler.h" |
39 | #include "MacroAssemblerCodeRef.h" |
40 | #include <wtf/DataLog.h> |
41 | #include <wtf/FastMalloc.h> |
42 | #include <wtf/Noncopyable.h> |
43 | |
44 | namespace JSC { |
45 | |
46 | class CodeBlock; |
47 | |
48 | // LinkBuffer: |
49 | // |
50 | // This class assists in linking code generated by the macro assembler, once code generation |
51 | // has been completed, and the code has been copied to is final location in memory. At this |
52 | // time pointers to labels within the code may be resolved, and relative offsets to external |
53 | // addresses may be fixed. |
54 | // |
55 | // Specifically: |
56 | // * Jump objects may be linked to external targets, |
57 | // * The address of Jump objects may taken, such that it can later be relinked. |
58 | // * The return address of a Call may be acquired. |
59 | // * The address of a Label pointing into the code may be resolved. |
60 | // * The value referenced by a DataLabel may be set. |
61 | // |
62 | class LinkBuffer { |
63 | WTF_MAKE_NONCOPYABLE(LinkBuffer); WTF_MAKE_FAST_ALLOCATED; |
64 | |
65 | template<PtrTag tag> using CodePtr = MacroAssemblerCodePtr<tag>; |
66 | template<PtrTag tag> using CodeRef = MacroAssemblerCodeRef<tag>; |
67 | typedef MacroAssembler::Label Label; |
68 | typedef MacroAssembler::Jump Jump; |
69 | typedef MacroAssembler::PatchableJump PatchableJump; |
70 | typedef MacroAssembler::JumpList JumpList; |
71 | typedef MacroAssembler::Call Call; |
72 | typedef MacroAssembler::DataLabelCompact DataLabelCompact; |
73 | typedef MacroAssembler::DataLabel32 DataLabel32; |
74 | typedef MacroAssembler::DataLabelPtr DataLabelPtr; |
75 | typedef MacroAssembler::ConvertibleLoadLabel ConvertibleLoadLabel; |
76 | #if ENABLE(BRANCH_COMPACTION) |
77 | typedef MacroAssembler::LinkRecord LinkRecord; |
78 | typedef MacroAssembler::JumpLinkType JumpLinkType; |
79 | #endif |
80 | |
81 | public: |
82 | LinkBuffer(MacroAssembler& macroAssembler, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed) |
83 | : m_size(0) |
84 | , m_didAllocate(false) |
85 | #ifndef NDEBUG |
86 | , m_completed(false) |
87 | #endif |
88 | { |
89 | linkCode(macroAssembler, ownerUID, effort); |
90 | } |
91 | |
92 | template<PtrTag tag> |
93 | LinkBuffer(MacroAssembler& macroAssembler, MacroAssemblerCodePtr<tag> code, size_t size, JITCompilationEffort effort = JITCompilationMustSucceed, bool shouldPerformBranchCompaction = true) |
94 | : m_size(size) |
95 | , m_didAllocate(false) |
96 | #ifndef NDEBUG |
97 | , m_completed(false) |
98 | #endif |
99 | , m_code(code.template retagged<LinkBufferPtrTag>()) |
100 | { |
101 | #if ENABLE(BRANCH_COMPACTION) |
102 | m_shouldPerformBranchCompaction = shouldPerformBranchCompaction; |
103 | #else |
104 | UNUSED_PARAM(shouldPerformBranchCompaction); |
105 | #endif |
106 | linkCode(macroAssembler, 0, effort); |
107 | } |
108 | |
109 | ~LinkBuffer() |
110 | { |
111 | } |
112 | |
113 | bool didFailToAllocate() const |
114 | { |
115 | return !m_didAllocate; |
116 | } |
117 | |
118 | bool isValid() const |
119 | { |
120 | return !didFailToAllocate(); |
121 | } |
122 | |
123 | // These methods are used to link or set values at code generation time. |
124 | |
125 | template<PtrTag tag, typename Func, typename = std::enable_if_t<std::is_function<typename std::remove_pointer<Func>::type>::value>> |
126 | void link(Call call, Func funcName) |
127 | { |
128 | FunctionPtr<tag> function(funcName); |
129 | link(call, function); |
130 | } |
131 | |
132 | template<PtrTag tag> |
133 | void link(Call call, FunctionPtr<tag> function) |
134 | { |
135 | ASSERT(call.isFlagSet(Call::Linkable)); |
136 | call.m_label = applyOffset(call.m_label); |
137 | MacroAssembler::linkCall(code(), call, function); |
138 | } |
139 | |
140 | template<PtrTag tag> |
141 | void link(Call call, CodeLocationLabel<tag> label) |
142 | { |
143 | link(call, FunctionPtr<tag>(label)); |
144 | } |
145 | |
146 | template<PtrTag tag> |
147 | void link(Jump jump, CodeLocationLabel<tag> label) |
148 | { |
149 | jump.m_label = applyOffset(jump.m_label); |
150 | MacroAssembler::linkJump(code(), jump, label); |
151 | } |
152 | |
153 | template<PtrTag tag> |
154 | void link(const JumpList& list, CodeLocationLabel<tag> label) |
155 | { |
156 | for (const Jump& jump : list.jumps()) |
157 | link(jump, label); |
158 | } |
159 | |
160 | void patch(DataLabelPtr label, void* value) |
161 | { |
162 | AssemblerLabel target = applyOffset(label.m_label); |
163 | MacroAssembler::linkPointer(code(), target, value); |
164 | } |
165 | |
166 | template<PtrTag tag> |
167 | void patch(DataLabelPtr label, CodeLocationLabel<tag> value) |
168 | { |
169 | AssemblerLabel target = applyOffset(label.m_label); |
170 | MacroAssembler::linkPointer(code(), target, value); |
171 | } |
172 | |
173 | // These methods are used to obtain handles to allow the code to be relinked / repatched later. |
174 | |
175 | template<PtrTag tag> |
176 | CodeLocationLabel<tag> entrypoint() |
177 | { |
178 | return CodeLocationLabel<tag>(tagCodePtr<tag>(code())); |
179 | } |
180 | |
181 | template<PtrTag tag> |
182 | CodeLocationCall<tag> locationOf(Call call) |
183 | { |
184 | ASSERT(call.isFlagSet(Call::Linkable)); |
185 | ASSERT(!call.isFlagSet(Call::Near)); |
186 | return CodeLocationCall<tag>(MacroAssembler::getLinkerAddress<tag>(code(), applyOffset(call.m_label))); |
187 | } |
188 | |
189 | template<PtrTag tag> |
190 | CodeLocationNearCall<tag> locationOfNearCall(Call call) |
191 | { |
192 | ASSERT(call.isFlagSet(Call::Linkable)); |
193 | ASSERT(call.isFlagSet(Call::Near)); |
194 | return CodeLocationNearCall<tag>(MacroAssembler::getLinkerAddress<tag>(code(), applyOffset(call.m_label)), |
195 | call.isFlagSet(Call::Tail) ? NearCallMode::Tail : NearCallMode::Regular); |
196 | } |
197 | |
198 | template<PtrTag tag> |
199 | CodeLocationLabel<tag> locationOf(PatchableJump jump) |
200 | { |
201 | return CodeLocationLabel<tag>(MacroAssembler::getLinkerAddress<tag>(code(), applyOffset(jump.m_jump.m_label))); |
202 | } |
203 | |
204 | template<PtrTag tag> |
205 | CodeLocationLabel<tag> locationOf(Label label) |
206 | { |
207 | return CodeLocationLabel<tag>(MacroAssembler::getLinkerAddress<tag>(code(), applyOffset(label.m_label))); |
208 | } |
209 | |
210 | template<PtrTag tag> |
211 | CodeLocationDataLabelPtr<tag> locationOf(DataLabelPtr label) |
212 | { |
213 | return CodeLocationDataLabelPtr<tag>(MacroAssembler::getLinkerAddress<tag>(code(), applyOffset(label.m_label))); |
214 | } |
215 | |
216 | template<PtrTag tag> |
217 | CodeLocationDataLabel32<tag> locationOf(DataLabel32 label) |
218 | { |
219 | return CodeLocationDataLabel32<tag>(MacroAssembler::getLinkerAddress<tag>(code(), applyOffset(label.m_label))); |
220 | } |
221 | |
222 | template<PtrTag tag> |
223 | CodeLocationDataLabelCompact<tag> locationOf(DataLabelCompact label) |
224 | { |
225 | return CodeLocationDataLabelCompact<tag>(MacroAssembler::getLinkerAddress<tag>(code(), applyOffset(label.m_label))); |
226 | } |
227 | |
228 | template<PtrTag tag> |
229 | CodeLocationConvertibleLoad<tag> locationOf(ConvertibleLoadLabel label) |
230 | { |
231 | return CodeLocationConvertibleLoad<tag>(MacroAssembler::getLinkerAddress<tag>(code(), applyOffset(label.m_label))); |
232 | } |
233 | |
234 | // This method obtains the return address of the call, given as an offset from |
235 | // the start of the code. |
236 | unsigned returnAddressOffset(Call call) |
237 | { |
238 | call.m_label = applyOffset(call.m_label); |
239 | return MacroAssembler::getLinkerCallReturnOffset(call); |
240 | } |
241 | |
242 | uint32_t offsetOf(Label label) |
243 | { |
244 | return applyOffset(label.m_label).m_offset; |
245 | } |
246 | |
247 | unsigned offsetOf(PatchableJump jump) |
248 | { |
249 | return applyOffset(jump.m_jump.m_label).m_offset; |
250 | } |
251 | |
252 | // Upon completion of all patching 'FINALIZE_CODE()' should be called once to |
253 | // complete generation of the code. Alternatively, call |
254 | // finalizeCodeWithoutDisassembly() directly if you have your own way of |
255 | // displaying disassembly. |
256 | |
257 | template<PtrTag tag> |
258 | CodeRef<tag> finalizeCodeWithoutDisassembly() |
259 | { |
260 | return finalizeCodeWithoutDisassemblyImpl().template retagged<tag>(); |
261 | } |
262 | |
263 | template<PtrTag tag, typename... Args> |
264 | CodeRef<tag> finalizeCodeWithDisassembly(bool dumpDisassembly, const char* format, Args... args) |
265 | { |
266 | ALLOW_NONLITERAL_FORMAT_BEGIN |
267 | IGNORE_WARNINGS_BEGIN("format-security" ) |
268 | return finalizeCodeWithDisassemblyImpl(dumpDisassembly, format, args...).template retagged<tag>(); |
269 | IGNORE_WARNINGS_END |
270 | ALLOW_NONLITERAL_FORMAT_END |
271 | } |
272 | |
273 | template<PtrTag tag> |
274 | CodePtr<tag> trampolineAt(Label label) |
275 | { |
276 | return CodePtr<tag>(MacroAssembler::AssemblerType_T::getRelocatedAddress(code(), applyOffset(label.m_label))); |
277 | } |
278 | |
279 | void* debugAddress() |
280 | { |
281 | return m_code.dataLocation(); |
282 | } |
283 | |
284 | size_t size() const { return m_size; } |
285 | |
286 | bool wasAlreadyDisassembled() const { return m_alreadyDisassembled; } |
287 | void didAlreadyDisassemble() { m_alreadyDisassembled = true; } |
288 | |
289 | private: |
290 | JS_EXPORT_PRIVATE CodeRef<LinkBufferPtrTag> finalizeCodeWithoutDisassemblyImpl(); |
291 | JS_EXPORT_PRIVATE CodeRef<LinkBufferPtrTag> finalizeCodeWithDisassemblyImpl(bool dumpDisassembly, const char* format, ...) WTF_ATTRIBUTE_PRINTF(3, 4); |
292 | |
293 | #if ENABLE(BRANCH_COMPACTION) |
294 | int executableOffsetFor(int location) |
295 | { |
296 | // Returning 0 in this case works because at location < |
297 | // sizeof(int32_t), no compaction could have happened before this |
298 | // point as the assembler could not have placed a branch instruction |
299 | // within this space that required compaction. |
300 | if (location < static_cast<int>(sizeof(int32_t))) |
301 | return 0; |
302 | return bitwise_cast<int32_t*>(m_assemblerStorage.buffer())[location / sizeof(int32_t) - 1]; |
303 | } |
304 | #endif |
305 | |
306 | template <typename T> T applyOffset(T src) |
307 | { |
308 | #if ENABLE(BRANCH_COMPACTION) |
309 | src.m_offset -= executableOffsetFor(src.m_offset); |
310 | #endif |
311 | return src; |
312 | } |
313 | |
314 | // Keep this private! - the underlying code should only be obtained externally via finalizeCode(). |
315 | void* code() |
316 | { |
317 | return m_code.dataLocation(); |
318 | } |
319 | |
320 | void allocate(MacroAssembler&, void* ownerUID, JITCompilationEffort); |
321 | |
322 | JS_EXPORT_PRIVATE void linkCode(MacroAssembler&, void* ownerUID, JITCompilationEffort); |
323 | #if ENABLE(BRANCH_COMPACTION) |
324 | template <typename InstructionType> |
325 | void copyCompactAndLinkCode(MacroAssembler&, void* ownerUID, JITCompilationEffort); |
326 | #endif |
327 | |
328 | void performFinalization(); |
329 | |
330 | #if DUMP_LINK_STATISTICS |
331 | static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize); |
332 | #endif |
333 | |
334 | #if DUMP_CODE |
335 | static void dumpCode(void* code, size_t); |
336 | #endif |
337 | |
338 | RefPtr<ExecutableMemoryHandle> m_executableMemory; |
339 | size_t m_size; |
340 | #if ENABLE(BRANCH_COMPACTION) |
341 | AssemblerData m_assemblerStorage; |
342 | bool m_shouldPerformBranchCompaction { true }; |
343 | #endif |
344 | bool m_didAllocate; |
345 | #ifndef NDEBUG |
346 | bool m_completed; |
347 | #endif |
348 | bool m_alreadyDisassembled { false }; |
349 | MacroAssemblerCodePtr<LinkBufferPtrTag> m_code; |
350 | Vector<RefPtr<SharedTask<void(LinkBuffer&)>>> m_linkTasks; |
351 | }; |
352 | |
353 | #if OS(LINUX) |
354 | #define FINALIZE_CODE_IF(condition, linkBufferReference, resultPtrTag, ...) \ |
355 | (UNLIKELY((condition)) \ |
356 | ? (linkBufferReference).finalizeCodeWithDisassembly<resultPtrTag>(true, __VA_ARGS__) \ |
357 | : (UNLIKELY(JSC::Options::logJITCodeForPerf()) \ |
358 | ? (linkBufferReference).finalizeCodeWithDisassembly<resultPtrTag>(false, __VA_ARGS__) \ |
359 | : (linkBufferReference).finalizeCodeWithoutDisassembly<resultPtrTag>())) |
360 | #else |
361 | #define FINALIZE_CODE_IF(condition, linkBufferReference, resultPtrTag, ...) \ |
362 | (UNLIKELY((condition)) \ |
363 | ? (linkBufferReference).finalizeCodeWithDisassembly<resultPtrTag>(true, __VA_ARGS__) \ |
364 | : (linkBufferReference).finalizeCodeWithoutDisassembly<resultPtrTag>()) |
365 | #endif |
366 | |
367 | bool shouldDumpDisassemblyFor(CodeBlock*); |
368 | |
369 | #define FINALIZE_CODE_FOR(codeBlock, linkBufferReference, resultPtrTag, ...) \ |
370 | FINALIZE_CODE_IF((shouldDumpDisassemblyFor(codeBlock) || Options::asyncDisassembly()), linkBufferReference, resultPtrTag, __VA_ARGS__) |
371 | |
372 | // Use this to finalize code, like so: |
373 | // |
374 | // CodeRef code = FINALIZE_CODE(linkBuffer, tag, "my super thingy number %d", number); |
375 | // |
376 | // Which, in disassembly mode, will print: |
377 | // |
378 | // Generated JIT code for my super thingy number 42: |
379 | // Code at [0x123456, 0x234567]: |
380 | // 0x123456: mov $0, 0 |
381 | // 0x12345a: ret |
382 | // |
383 | // ... and so on. |
384 | // |
385 | // Note that the format string and print arguments are only evaluated when dumpDisassembly |
386 | // is true, so you can hide expensive disassembly-only computations inside there. |
387 | |
388 | #define FINALIZE_CODE(linkBufferReference, resultPtrTag, ...) \ |
389 | FINALIZE_CODE_IF((JSC::Options::asyncDisassembly() || JSC::Options::dumpDisassembly()), linkBufferReference, resultPtrTag, __VA_ARGS__) |
390 | |
391 | #define FINALIZE_DFG_CODE(linkBufferReference, resultPtrTag, ...) \ |
392 | FINALIZE_CODE_IF((JSC::Options::asyncDisassembly() || JSC::Options::dumpDisassembly() || Options::dumpDFGDisassembly()), linkBufferReference, resultPtrTag, __VA_ARGS__) |
393 | |
394 | #define FINALIZE_REGEXP_CODE(linkBufferReference, resultPtrTag, dataLogFArgumentsForHeading) \ |
395 | FINALIZE_CODE_IF(JSC::Options::asyncDisassembly() || JSC::Options::dumpDisassembly() || Options::dumpRegExpDisassembly(), linkBufferReference, resultPtrTag, dataLogFArgumentsForHeading) |
396 | |
397 | } // namespace JSC |
398 | |
399 | #endif // ENABLE(ASSEMBLER) |
400 | |