1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=79:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Copyright (C) 2009 Apple Inc. All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : *
16 : * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
17 : * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
20 : * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 : * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : *
28 : * ***** END LICENSE BLOCK ***** */
29 :
30 : #ifndef LinkBuffer_h
31 : #define LinkBuffer_h
32 :
33 : #include "assembler/wtf/Platform.h"
34 :
35 : #if ENABLE_ASSEMBLER
36 :
37 : #include <assembler/MacroAssembler.h>
38 :
39 : namespace JSC {
40 :
41 : // LinkBuffer:
42 : //
43 : // This class assists in linking code generated by the macro assembler, once code generation
44 : // has been completed, and the code has been copied to is final location in memory. At this
45 : // time pointers to labels within the code may be resolved, and relative offsets to external
46 : // addresses may be fixed.
47 : //
48 : // Specifically:
49 : // * Jump objects may be linked to external targets,
50 : // * The address of Jump objects may taken, such that it can later be relinked.
51 : // * The return address of a Call may be acquired.
52 : // * The address of a Label pointing into the code may be resolved.
53 : // * The value referenced by a DataLabel may be set.
54 : //
55 : class LinkBuffer {
56 : typedef MacroAssemblerCodeRef CodeRef;
57 : typedef MacroAssembler::Label Label;
58 : typedef MacroAssembler::Jump Jump;
59 : typedef MacroAssembler::JumpList JumpList;
60 : typedef MacroAssembler::Call Call;
61 : typedef MacroAssembler::DataLabel32 DataLabel32;
62 : typedef MacroAssembler::DataLabelPtr DataLabelPtr;
63 :
64 : public:
65 : // 'ok' should be checked after this constructor is called; it's false if OOM occurred.
66 67095 : LinkBuffer(MacroAssembler* masm, ExecutableAllocator* executableAllocator,
67 : ExecutablePool** poolp, bool* ok, CodeKind codeKind)
68 : {
69 67095 : m_codeKind = codeKind;
70 67095 : m_code = executableAllocAndCopy(*masm, executableAllocator, poolp);
71 67095 : m_executablePool = *poolp;
72 67095 : m_size = masm->m_assembler.size(); // must come after call to executableAllocAndCopy()!
73 : #ifndef NDEBUG
74 67095 : m_completed = false;
75 : #endif
76 67095 : *ok = !!m_code;
77 67095 : }
78 :
79 306058 : LinkBuffer(CodeKind kind)
80 : : m_executablePool(NULL)
81 : , m_code(NULL)
82 : , m_size(0)
83 : , m_codeKind(kind)
84 : #ifndef NDEBUG
85 306058 : , m_completed(false)
86 : #endif
87 : {
88 306058 : }
89 :
90 515389 : LinkBuffer(uint8_t* ncode, size_t size, CodeKind kind)
91 : : m_executablePool(NULL)
92 : , m_code(ncode)
93 : , m_size(size)
94 : , m_codeKind(kind)
95 : #ifndef NDEBUG
96 515389 : , m_completed(false)
97 : #endif
98 : {
99 515389 : }
100 :
101 888542 : ~LinkBuffer()
102 : {
103 888542 : ASSERT(!m_executablePool || m_completed);
104 888542 : }
105 :
106 : // These methods are used to link or set values at code generation time.
107 :
108 4905105 : void link(Call call, FunctionPtr function)
109 : {
110 4905105 : ASSERT(call.isFlagSet(Call::Linkable));
111 4905105 : MacroAssembler::linkCall(code(), call, function);
112 4905105 : }
113 :
114 9954223 : void link(Jump jump, CodeLocationLabel label)
115 : {
116 9954223 : MacroAssembler::linkJump(code(), jump, label);
117 9954223 : }
118 :
119 : void link(JumpList list, CodeLocationLabel label)
120 : {
121 : for (unsigned i = 0; i < list.m_jumps.length(); ++i)
122 : MacroAssembler::linkJump(code(), list.m_jumps[i], label);
123 : }
124 :
125 1879984 : void patch(DataLabelPtr label, void* value)
126 : {
127 1879984 : MacroAssembler::linkPointer(code(), label.m_label, value);
128 1879984 : }
129 :
130 445049 : void patch(DataLabelPtr label, CodeLocationLabel value)
131 : {
132 445049 : MacroAssembler::linkPointer(code(), label.m_label, value.executableAddress());
133 445049 : }
134 :
135 : // These methods are used to obtain handles to allow the code to be relinked / repatched later.
136 :
137 1419654 : CodeLocationCall locationOf(Call call)
138 : {
139 1419654 : ASSERT(call.isFlagSet(Call::Linkable));
140 1419654 : ASSERT(!call.isFlagSet(Call::Near));
141 1419654 : return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp));
142 : }
143 :
144 617666 : CodeLocationJump locationOf(Jump j)
145 : {
146 617666 : return CodeLocationJump(MacroAssembler::getLinkerAddress(code(), j.m_jmp));
147 : }
148 :
149 : CodeLocationNearCall locationOfNearCall(Call call)
150 : {
151 : ASSERT(call.isFlagSet(Call::Linkable));
152 : ASSERT(call.isFlagSet(Call::Near));
153 : return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp));
154 : }
155 :
156 14959196 : CodeLocationLabel locationOf(Label label)
157 : {
158 14959196 : return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), label.m_label));
159 : }
160 :
161 998224 : CodeLocationDataLabelPtr locationOf(DataLabelPtr label)
162 : {
163 998224 : return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), label.m_label));
164 : }
165 :
166 30761 : CodeLocationDataLabel32 locationOf(DataLabel32 label)
167 : {
168 30761 : return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), label.m_label));
169 : }
170 :
171 : // This method obtains the return address of the call, given as an offset from
172 : // the start of the code.
173 : unsigned returnAddressOffset(Call call)
174 : {
175 : return MacroAssembler::getLinkerCallReturnOffset(call);
176 : }
177 :
178 : // Upon completion of all patching either 'finalizeCode()' or 'finalizeCodeAddendum()' should be called
179 : // once to complete generation of the code. 'finalizeCode()' is suited to situations
180 : // where the executable pool must also be retained, the lighter-weight 'finalizeCodeAddendum()' is
181 : // suited to adding to an existing allocation.
182 55269 : CodeRef finalizeCode()
183 : {
184 55269 : performFinalization();
185 :
186 55269 : return CodeRef(m_code, m_executablePool, m_size);
187 : }
188 317884 : CodeLocationLabel finalizeCodeAddendum()
189 : {
190 317884 : performFinalization();
191 :
192 317884 : return CodeLocationLabel(code());
193 : }
194 :
195 : protected:
196 : // Keep this private! - the underlying code should only be obtained externally via
197 : // finalizeCode() or finalizeCodeAddendum().
198 36274052 : void* code()
199 : {
200 36274052 : return m_code;
201 : }
202 :
203 373153 : void *executableAllocAndCopy(MacroAssembler &masm, ExecutableAllocator *allocator,
204 : ExecutablePool **poolp)
205 : {
206 373153 : return masm.m_assembler.executableAllocAndCopy(allocator, poolp, m_codeKind);
207 : }
208 :
209 373153 : void performFinalization()
210 : {
211 : #ifndef NDEBUG
212 373153 : ASSERT(!m_completed);
213 373153 : m_completed = true;
214 : #endif
215 :
216 373153 : ExecutableAllocator::makeExecutable(code(), m_size);
217 373153 : ExecutableAllocator::cacheFlush(code(), m_size);
218 373153 : }
219 :
220 : ExecutablePool* m_executablePool;
221 : void* m_code;
222 : size_t m_size;
223 : CodeKind m_codeKind;
224 : #ifndef NDEBUG
225 : bool m_completed;
226 : #endif
227 : };
228 :
229 : } // namespace JSC
230 :
231 : #endif // ENABLE(ASSEMBLER)
232 :
233 : #endif // LinkBuffer_h
|