|
1 /* |
|
2 * Copyright (C) 2009 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 #include <MacroAssembler.h> |
|
32 #include <wtf/Noncopyable.h> |
|
33 |
|
34 namespace JSC { |
|
35 |
|
36 // LinkBuffer: |
|
37 // |
|
38 // This class assists in linking code generated by the macro assembler, once code generation |
|
39 // has been completed, and the code has been copied to is final location in memory. At this |
|
40 // time pointers to labels within the code may be resolved, and relative offsets to external |
|
41 // addresses may be fixed. |
|
42 // |
|
43 // Specifically: |
|
44 // * Jump objects may be linked to external targets, |
|
45 // * The address of Jump objects may taken, such that it can later be relinked. |
|
46 // * The return address of a Call may be acquired. |
|
47 // * The address of a Label pointing into the code may be resolved. |
|
48 // * The value referenced by a DataLabel may be set. |
|
49 // |
|
50 class LinkBuffer : public Noncopyable { |
|
51 typedef MacroAssemblerCodeRef CodeRef; |
|
52 typedef MacroAssembler::Label Label; |
|
53 typedef MacroAssembler::Jump Jump; |
|
54 typedef MacroAssembler::JumpList JumpList; |
|
55 typedef MacroAssembler::Call Call; |
|
56 typedef MacroAssembler::DataLabel32 DataLabel32; |
|
57 typedef MacroAssembler::DataLabelPtr DataLabelPtr; |
|
58 |
|
59 public: |
|
60 // Note: Initialization sequence is significant, since executablePool is a PassRefPtr. |
|
61 // First, executablePool is copied into m_executablePool, then the initialization of |
|
62 // m_code uses m_executablePool, *not* executablePool, since this is no longer valid. |
|
63 LinkBuffer(MacroAssembler* masm, PassRefPtr<ExecutablePool> executablePool) |
|
64 : m_executablePool(executablePool) |
|
65 , m_code(masm->m_assembler.executableCopy(m_executablePool.get())) |
|
66 , m_size(masm->m_assembler.size()) |
|
67 #ifndef NDEBUG |
|
68 , m_completed(false) |
|
69 #endif |
|
70 { |
|
71 } |
|
72 |
|
73 ~LinkBuffer() |
|
74 { |
|
75 ASSERT(m_completed); |
|
76 } |
|
77 |
|
78 // These methods are used to link or set values at code generation time. |
|
79 |
|
80 void link(Call call, FunctionPtr function) |
|
81 { |
|
82 ASSERT(call.isFlagSet(Call::Linkable)); |
|
83 MacroAssembler::linkCall(code(), call, function); |
|
84 } |
|
85 |
|
86 void link(Jump jump, CodeLocationLabel label) |
|
87 { |
|
88 MacroAssembler::linkJump(code(), jump, label); |
|
89 } |
|
90 |
|
91 void link(JumpList list, CodeLocationLabel label) |
|
92 { |
|
93 for (unsigned i = 0; i < list.m_jumps.size(); ++i) |
|
94 MacroAssembler::linkJump(code(), list.m_jumps[i], label); |
|
95 } |
|
96 |
|
97 void patch(DataLabelPtr label, void* value) |
|
98 { |
|
99 MacroAssembler::linkPointer(code(), label.m_label, value); |
|
100 } |
|
101 |
|
102 void patch(DataLabelPtr label, CodeLocationLabel value) |
|
103 { |
|
104 MacroAssembler::linkPointer(code(), label.m_label, value.executableAddress()); |
|
105 } |
|
106 |
|
107 // These methods are used to obtain handles to allow the code to be relinked / repatched later. |
|
108 |
|
109 CodeLocationCall locationOf(Call call) |
|
110 { |
|
111 ASSERT(call.isFlagSet(Call::Linkable)); |
|
112 ASSERT(!call.isFlagSet(Call::Near)); |
|
113 return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp)); |
|
114 } |
|
115 |
|
116 CodeLocationNearCall locationOfNearCall(Call call) |
|
117 { |
|
118 ASSERT(call.isFlagSet(Call::Linkable)); |
|
119 ASSERT(call.isFlagSet(Call::Near)); |
|
120 return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp)); |
|
121 } |
|
122 |
|
123 CodeLocationLabel locationOf(Label label) |
|
124 { |
|
125 return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), label.m_label)); |
|
126 } |
|
127 |
|
128 CodeLocationDataLabelPtr locationOf(DataLabelPtr label) |
|
129 { |
|
130 return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), label.m_label)); |
|
131 } |
|
132 |
|
133 CodeLocationDataLabel32 locationOf(DataLabel32 label) |
|
134 { |
|
135 return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), label.m_label)); |
|
136 } |
|
137 |
|
138 // This method obtains the return address of the call, given as an offset from |
|
139 // the start of the code. |
|
140 unsigned returnAddressOffset(Call call) |
|
141 { |
|
142 return MacroAssembler::getLinkerCallReturnOffset(call); |
|
143 } |
|
144 |
|
145 // Upon completion of all patching either 'finalizeCode()' or 'finalizeCodeAddendum()' should be called |
|
146 // once to complete generation of the code. 'finalizeCode()' is suited to situations |
|
147 // where the executable pool must also be retained, the lighter-weight 'finalizeCodeAddendum()' is |
|
148 // suited to adding to an existing allocation. |
|
149 CodeRef finalizeCode() |
|
150 { |
|
151 performFinalization(); |
|
152 |
|
153 return CodeRef(m_code, m_executablePool, m_size); |
|
154 } |
|
155 CodeLocationLabel finalizeCodeAddendum() |
|
156 { |
|
157 performFinalization(); |
|
158 |
|
159 return CodeLocationLabel(code()); |
|
160 } |
|
161 |
|
162 private: |
|
163 // Keep this private! - the underlying code should only be obtained externally via |
|
164 // finalizeCode() or finalizeCodeAddendum(). |
|
165 void* code() |
|
166 { |
|
167 return m_code; |
|
168 } |
|
169 |
|
170 void performFinalization() |
|
171 { |
|
172 #ifndef NDEBUG |
|
173 ASSERT(!m_completed); |
|
174 m_completed = true; |
|
175 #endif |
|
176 |
|
177 ExecutableAllocator::makeExecutable(code(), m_size); |
|
178 ExecutableAllocator::cacheFlush(code(), m_size); |
|
179 } |
|
180 |
|
181 RefPtr<ExecutablePool> m_executablePool; |
|
182 void* m_code; |
|
183 size_t m_size; |
|
184 #ifndef NDEBUG |
|
185 bool m_completed; |
|
186 #endif |
|
187 }; |
|
188 |
|
189 } // namespace JSC |
|
190 |
|
191 #endif // ENABLE(ASSEMBLER) |
|
192 |
|
193 #endif // LinkBuffer_h |