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