2 * Copyright (C) 2009, 2010, 2012, 2013, 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
31 #define DUMP_LINK_STATISTICS 0
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 #define CSS_CODE_ID reinterpret_cast<void*>(static_cast<intptr_t>(-3))
38 #include "JITCompilationEffort.h"
39 #include "MacroAssembler.h"
40 #include <wtf/DataLog.h>
41 #include <wtf/FastMalloc.h>
42 #include <wtf/Noncopyable.h>
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.
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.
64 WTF_MAKE_NONCOPYABLE(LinkBuffer
); WTF_MAKE_FAST_ALLOCATED
;
66 typedef MacroAssemblerCodeRef CodeRef
;
67 typedef MacroAssemblerCodePtr CodePtr
;
68 typedef MacroAssembler::Label Label
;
69 typedef MacroAssembler::Jump Jump
;
70 typedef MacroAssembler::PatchableJump PatchableJump
;
71 typedef MacroAssembler::JumpList JumpList
;
72 typedef MacroAssembler::Call Call
;
73 typedef MacroAssembler::DataLabelCompact DataLabelCompact
;
74 typedef MacroAssembler::DataLabel32 DataLabel32
;
75 typedef MacroAssembler::DataLabelPtr DataLabelPtr
;
76 typedef MacroAssembler::ConvertibleLoadLabel ConvertibleLoadLabel
;
77 #if ENABLE(BRANCH_COMPACTION)
78 typedef MacroAssembler::LinkRecord LinkRecord
;
79 typedef MacroAssembler::JumpLinkType JumpLinkType
;
83 LinkBuffer(VM
& vm
, MacroAssembler
& macroAssembler
, void* ownerUID
, JITCompilationEffort effort
= JITCompilationMustSucceed
)
85 #if ENABLE(BRANCH_COMPACTION)
88 , m_didAllocate(false)
95 linkCode(macroAssembler
, ownerUID
, effort
);
98 LinkBuffer(VM
& vm
, MacroAssembler
& macroAssembler
, void* code
, size_t size
)
100 #if ENABLE(BRANCH_COMPACTION)
103 , m_didAllocate(false)
110 linkCode(macroAssembler
, 0, JITCompilationCanFail
);
117 bool didFailToAllocate() const
119 return !m_didAllocate
;
124 return !didFailToAllocate();
127 // These methods are used to link or set values at code generation time.
129 void link(Call call
, FunctionPtr function
)
131 ASSERT(call
.isFlagSet(Call::Linkable
));
132 call
.m_label
= applyOffset(call
.m_label
);
133 MacroAssembler::linkCall(code(), call
, function
);
136 void link(Call call
, CodeLocationLabel label
)
138 link(call
, FunctionPtr(label
.executableAddress()));
141 void link(Jump jump
, CodeLocationLabel label
)
143 jump
.m_label
= applyOffset(jump
.m_label
);
144 MacroAssembler::linkJump(code(), jump
, label
);
147 void link(JumpList list
, CodeLocationLabel label
)
149 for (unsigned i
= 0; i
< list
.m_jumps
.size(); ++i
)
150 link(list
.m_jumps
[i
], label
);
153 void patch(DataLabelPtr label
, void* value
)
155 AssemblerLabel target
= applyOffset(label
.m_label
);
156 MacroAssembler::linkPointer(code(), target
, value
);
159 void patch(DataLabelPtr label
, CodeLocationLabel value
)
161 AssemblerLabel target
= applyOffset(label
.m_label
);
162 MacroAssembler::linkPointer(code(), target
, value
.executableAddress());
165 // These methods are used to obtain handles to allow the code to be relinked / repatched later.
167 CodeLocationLabel
entrypoint()
169 return CodeLocationLabel(code());
172 CodeLocationCall
locationOf(Call call
)
174 ASSERT(call
.isFlagSet(Call::Linkable
));
175 ASSERT(!call
.isFlagSet(Call::Near
));
176 return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call
.m_label
)));
179 CodeLocationNearCall
locationOfNearCall(Call call
)
181 ASSERT(call
.isFlagSet(Call::Linkable
));
182 ASSERT(call
.isFlagSet(Call::Near
));
183 return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call
.m_label
)));
186 CodeLocationLabel
locationOf(PatchableJump jump
)
188 return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(jump
.m_jump
.m_label
)));
191 CodeLocationLabel
locationOf(Label label
)
193 return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(label
.m_label
)));
196 CodeLocationDataLabelPtr
locationOf(DataLabelPtr label
)
198 return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), applyOffset(label
.m_label
)));
201 CodeLocationDataLabel32
locationOf(DataLabel32 label
)
203 return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), applyOffset(label
.m_label
)));
206 CodeLocationDataLabelCompact
locationOf(DataLabelCompact label
)
208 return CodeLocationDataLabelCompact(MacroAssembler::getLinkerAddress(code(), applyOffset(label
.m_label
)));
211 CodeLocationConvertibleLoad
locationOf(ConvertibleLoadLabel label
)
213 return CodeLocationConvertibleLoad(MacroAssembler::getLinkerAddress(code(), applyOffset(label
.m_label
)));
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
)
220 call
.m_label
= applyOffset(call
.m_label
);
221 return MacroAssembler::getLinkerCallReturnOffset(call
);
224 uint32_t offsetOf(Label label
)
226 return applyOffset(label
.m_label
).m_offset
;
229 unsigned offsetOf(PatchableJump jump
)
231 return applyOffset(jump
.m_jump
.m_label
).m_offset
;
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.
239 JS_EXPORT_PRIVATE CodeRef
finalizeCodeWithoutDisassembly();
240 JS_EXPORT_PRIVATE CodeRef
finalizeCodeWithDisassembly(const char* format
, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
242 CodePtr
trampolineAt(Label label
)
244 return CodePtr(MacroAssembler::AssemblerType_T::getRelocatedAddress(code(), applyOffset(label
.m_label
)));
252 // FIXME: this does not account for the AssemblerData size!
259 #if ENABLE(BRANCH_COMPACTION)
260 int executableOffsetFor(int location
)
264 return bitwise_cast
<int32_t*>(m_assemblerStorage
.buffer())[location
/ sizeof(int32_t) - 1];
268 template <typename T
> T
applyOffset(T src
)
270 #if ENABLE(BRANCH_COMPACTION)
271 src
.m_offset
-= executableOffsetFor(src
.m_offset
);
276 // Keep this private! - the underlying code should only be obtained externally via finalizeCode().
282 void allocate(size_t initialSize
, void* ownerUID
, JITCompilationEffort
);
283 void shrink(size_t newSize
);
285 JS_EXPORT_PRIVATE
void linkCode(MacroAssembler
&, void* ownerUID
, JITCompilationEffort
);
286 #if ENABLE(BRANCH_COMPACTION)
287 template <typename InstructionType
>
288 void copyCompactAndLinkCode(MacroAssembler
&, void* ownerUID
, JITCompilationEffort
);
291 void performFinalization();
293 #if DUMP_LINK_STATISTICS
294 static void dumpLinkStatistics(void* code
, size_t initialSize
, size_t finalSize
);
298 static void dumpCode(void* code
, size_t);
301 RefPtr
<ExecutableMemoryHandle
> m_executableMemory
;
303 #if ENABLE(BRANCH_COMPACTION)
304 size_t m_initialSize
;
305 AssemblerData m_assemblerStorage
;
315 #define FINALIZE_CODE_IF(condition, linkBufferReference, dataLogFArgumentsForHeading) \
316 (UNLIKELY((condition)) \
317 ? ((linkBufferReference).finalizeCodeWithDisassembly dataLogFArgumentsForHeading) \
318 : (linkBufferReference).finalizeCodeWithoutDisassembly())
320 bool shouldShowDisassemblyFor(CodeBlock
*);
322 #define FINALIZE_CODE_FOR(codeBlock, linkBufferReference, dataLogFArgumentsForHeading) \
323 FINALIZE_CODE_IF(shouldShowDisassemblyFor(codeBlock), linkBufferReference, dataLogFArgumentsForHeading)
325 // Use this to finalize code, like so:
327 // CodeRef code = FINALIZE_CODE(linkBuffer, ("my super thingy number %d", number));
329 // Which, in disassembly mode, will print:
331 // Generated JIT code for my super thingy number 42:
332 // Code at [0x123456, 0x234567]:
333 // 0x123456: mov $0, 0
338 // Note that the dataLogFArgumentsForHeading are only evaluated when showDisassembly
339 // is true, so you can hide expensive disassembly-only computations inside there.
341 #define FINALIZE_CODE(linkBufferReference, dataLogFArgumentsForHeading) \
342 FINALIZE_CODE_IF(JSC::Options::showDisassembly(), linkBufferReference, dataLogFArgumentsForHeading)
344 #define FINALIZE_DFG_CODE(linkBufferReference, dataLogFArgumentsForHeading) \
345 FINALIZE_CODE_IF((JSC::Options::showDisassembly() || Options::showDFGDisassembly()), linkBufferReference, dataLogFArgumentsForHeading)
349 #endif // ENABLE(ASSEMBLER)
351 #endif // LinkBuffer_h