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