]> git.saurik.com Git - apple/javascriptcore.git/blob - assembler/LinkBuffer.h
47cac5ab63cc9ff952898df4c1dfa9b0ad974560
[apple/javascriptcore.git] / assembler / LinkBuffer.h
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