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
44namespace JSC {
45
46class 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//
62class 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
81public:
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
289private:
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
367bool 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