1/*
2 * Copyright (C) 2009, 2010, 2012, 2013, 2014 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#ifndef LinkBuffer_h
27#define LinkBuffer_h
28
29#if ENABLE(ASSEMBLER)
30
31#define DUMP_LINK_STATISTICS 0
32#define DUMP_CODE 0
33
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))
37
38#include "JITCompilationEffort.h"
39#include "MacroAssembler.h"
40#include <wtf/DataLog.h>
41#include <wtf/FastMalloc.h>
42#include <wtf/Noncopyable.h>
43
44namespace JSC {
45
46class CodeBlock;
47class VM;
48
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//
63class LinkBuffer {
64    WTF_MAKE_NONCOPYABLE(LinkBuffer); WTF_MAKE_FAST_ALLOCATED;
65
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;
80#endif
81
82public:
83    LinkBuffer(VM& vm, MacroAssembler& macroAssembler, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
84        : m_size(0)
85#if ENABLE(BRANCH_COMPACTION)
86        , m_initialSize(0)
87#endif
88        , m_didAllocate(false)
89        , m_code(0)
90        , m_vm(&vm)
91#ifndef NDEBUG
92        , m_completed(false)
93#endif
94    {
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);
111    }
112
113    ~LinkBuffer()
114    {
115    }
116
117    bool didFailToAllocate() const
118    {
119        return !m_didAllocate;
120    }
121
122    bool isValid() const
123    {
124        return !didFailToAllocate();
125    }
126
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));
132        call.m_label = applyOffset(call.m_label);
133        MacroAssembler::linkCall(code(), call, function);
134    }
135
136    void link(Call call, CodeLocationLabel label)
137    {
138        link(call, FunctionPtr(label.executableAddress()));
139    }
140
141    void link(Jump jump, CodeLocationLabel label)
142    {
143        jump.m_label = applyOffset(jump.m_label);
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)
150            link(list.m_jumps[i], label);
151    }
152
153    void patch(DataLabelPtr label, void* value)
154    {
155        AssemblerLabel target = applyOffset(label.m_label);
156        MacroAssembler::linkPointer(code(), target, value);
157    }
158
159    void patch(DataLabelPtr label, CodeLocationLabel value)
160    {
161        AssemblerLabel target = applyOffset(label.m_label);
162        MacroAssembler::linkPointer(code(), target, value.executableAddress());
163    }
164
165    // These methods are used to obtain handles to allow the code to be relinked / repatched later.
166
167    CodeLocationLabel entrypoint()
168    {
169        return CodeLocationLabel(code());
170    }
171
172    CodeLocationCall locationOf(Call call)
173    {
174        ASSERT(call.isFlagSet(Call::Linkable));
175        ASSERT(!call.isFlagSet(Call::Near));
176        return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_label)));
177    }
178
179    CodeLocationNearCall locationOfNearCall(Call call)
180    {
181        ASSERT(call.isFlagSet(Call::Linkable));
182        ASSERT(call.isFlagSet(Call::Near));
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)));
189    }
190
191    CodeLocationLabel locationOf(Label label)
192    {
193        return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
194    }
195
196    CodeLocationDataLabelPtr locationOf(DataLabelPtr label)
197    {
198        return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
199    }
200
201    CodeLocationDataLabel32 locationOf(DataLabel32 label)
202    {
203        return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
204    }
205
206    CodeLocationDataLabelCompact locationOf(DataLabelCompact label)
207    {
208        return CodeLocationDataLabelCompact(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
209    }
210
211    CodeLocationConvertibleLoad locationOf(ConvertibleLoadLabel label)
212    {
213        return CodeLocationConvertibleLoad(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
214    }
215
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    {
220        call.m_label = applyOffset(call.m_label);
221        return MacroAssembler::getLinkerCallReturnOffset(call);
222    }
223
224    uint32_t offsetOf(Label label)
225    {
226        return applyOffset(label.m_label).m_offset;
227    }
228
229    unsigned offsetOf(PatchableJump jump)
230    {
231        return applyOffset(jump.m_jump.m_label).m_offset;
232    }
233
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
239    JS_EXPORT_PRIVATE CodeRef finalizeCodeWithoutDisassembly();
240    JS_EXPORT_PRIVATE CodeRef finalizeCodeWithDisassembly(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
241
242    CodePtr trampolineAt(Label label)
243    {
244        return CodePtr(MacroAssembler::AssemblerType_T::getRelocatedAddress(code(), applyOffset(label.m_label)));
245    }
246
247    void* debugAddress()
248    {
249        return m_code;
250    }
251
252    // FIXME: this does not account for the AssemblerData size!
253    size_t size()
254    {
255        return m_size;
256    }
257
258private:
259#if ENABLE(BRANCH_COMPACTION)
260    int executableOffsetFor(int location)
261    {
262        if (!location)
263            return 0;
264        return bitwise_cast<int32_t*>(m_assemblerStorage.buffer())[location / sizeof(int32_t) - 1];
265    }
266#endif
267
268    template <typename T> T applyOffset(T src)
269    {
270#if ENABLE(BRANCH_COMPACTION)
271        src.m_offset -= executableOffsetFor(src.m_offset);
272#endif
273        return src;
274    }
275
276    // Keep this private! - the underlying code should only be obtained externally via finalizeCode().
277    void* code()
278    {
279        return m_code;
280    }
281
282    void allocate(size_t initialSize, void* ownerUID, JITCompilationEffort);
283    void shrink(size_t newSize);
284
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);
289#endif
290
291    void performFinalization();
292
293#if DUMP_LINK_STATISTICS
294    static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize);
295#endif
296
297#if DUMP_CODE
298    static void dumpCode(void* code, size_t);
299#endif
300
301    RefPtr<ExecutableMemoryHandle> m_executableMemory;
302    size_t m_size;
303#if ENABLE(BRANCH_COMPACTION)
304    size_t m_initialSize;
305    AssemblerData m_assemblerStorage;
306#endif
307    bool m_didAllocate;
308    void* m_code;
309    VM* m_vm;
310#ifndef NDEBUG
311    bool m_completed;
312#endif
313};
314
315#define FINALIZE_CODE_IF(condition, linkBufferReference, dataLogFArgumentsForHeading)  \
316    (UNLIKELY((condition))                                              \
317     ? ((linkBufferReference).finalizeCodeWithDisassembly dataLogFArgumentsForHeading) \
318     : (linkBufferReference).finalizeCodeWithoutDisassembly())
319
320bool shouldShowDisassemblyFor(CodeBlock*);
321
322#define FINALIZE_CODE_FOR(codeBlock, linkBufferReference, dataLogFArgumentsForHeading)  \
323    FINALIZE_CODE_IF(shouldShowDisassemblyFor(codeBlock), linkBufferReference, dataLogFArgumentsForHeading)
324
325// Use this to finalize code, like so:
326//
327// CodeRef code = FINALIZE_CODE(linkBuffer, ("my super thingy number %d", number));
328//
329// Which, in disassembly mode, will print:
330//
331// Generated JIT code for my super thingy number 42:
332//     Code at [0x123456, 0x234567]:
333//         0x123456: mov $0, 0
334//         0x12345a: ret
335//
336// ... and so on.
337//
338// Note that the dataLogFArgumentsForHeading are only evaluated when showDisassembly
339// is true, so you can hide expensive disassembly-only computations inside there.
340
341#define FINALIZE_CODE(linkBufferReference, dataLogFArgumentsForHeading)  \
342    FINALIZE_CODE_IF(JSC::Options::showDisassembly(), linkBufferReference, dataLogFArgumentsForHeading)
343
344#define FINALIZE_DFG_CODE(linkBufferReference, dataLogFArgumentsForHeading)  \
345    FINALIZE_CODE_IF((JSC::Options::showDisassembly() || Options::showDFGDisassembly()), linkBufferReference, dataLogFArgumentsForHeading)
346
347} // namespace JSC
348
349#endif // ENABLE(ASSEMBLER)
350
351#endif // LinkBuffer_h
352