Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / assembler / assembler / LinkBuffer.h
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     // Note: Initialization sequence is significant, since executablePool is a PassRefPtr.
66     //       First, executablePool is copied into m_executablePool, then the initialization of
67     //       m_code uses m_executablePool, *not* executablePool, since this is no longer valid.
68     LinkBuffer(MacroAssembler* masm, ExecutablePool* executablePool)
69         : m_executablePool(executablePool)
70         , m_code(executableCopy(*masm, executablePool))
71         , m_size(masm->m_assembler.size())
72 #ifndef NDEBUG
73         , m_completed(false)
74 #endif
75     {
76     }
77
78     LinkBuffer()
79         : m_executablePool(NULL)
80         , m_code(NULL)
81         , m_size(0)
82 #ifndef NDEBUG
83         , m_completed(false)
84 #endif
85     {
86     }
87
88     LinkBuffer(uint8* ncode, size_t size)
89         : m_executablePool(NULL)
90         , m_code(ncode)
91         , m_size(size)
92 #ifndef NDEBUG
93         , m_completed(false)
94 #endif
95     {
96     }
97
98     ~LinkBuffer()
99     {
100         ASSERT(!m_executablePool || m_completed);
101     }
102
103     // These methods are used to link or set values at code generation time.
104
105     void link(Call call, FunctionPtr function)
106     {
107         ASSERT(call.isFlagSet(Call::Linkable));
108         MacroAssembler::linkCall(code(), call, function);
109     }
110     
111     void link(Jump jump, CodeLocationLabel label)
112     {
113         MacroAssembler::linkJump(code(), jump, label);
114     }
115
116     void link(JumpList list, CodeLocationLabel label)
117     {
118         for (unsigned i = 0; i < list.m_jumps.length(); ++i)
119             MacroAssembler::linkJump(code(), list.m_jumps[i], label);
120     }
121
122     void patch(DataLabelPtr label, void* value)
123     {
124         MacroAssembler::linkPointer(code(), label.m_label, value);
125     }
126
127     void patch(DataLabelPtr label, CodeLocationLabel value)
128     {
129         MacroAssembler::linkPointer(code(), label.m_label, value.executableAddress());
130     }
131
132     // These methods are used to obtain handles to allow the code to be relinked / repatched later.
133
134     CodeLocationCall locationOf(Call call)
135     {
136         ASSERT(call.isFlagSet(Call::Linkable));
137         ASSERT(!call.isFlagSet(Call::Near));
138         return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp));
139     }
140
141     CodeLocationJump locationOf(Jump j)
142     {
143         return CodeLocationJump(MacroAssembler::getLinkerAddress(code(), j.m_jmp));
144     }
145
146     CodeLocationNearCall locationOfNearCall(Call call)
147     {
148         ASSERT(call.isFlagSet(Call::Linkable));
149         ASSERT(call.isFlagSet(Call::Near));
150         return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp));
151     }
152
153     CodeLocationLabel locationOf(Label label)
154     {
155         return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), label.m_label));
156     }
157
158     CodeLocationDataLabelPtr locationOf(DataLabelPtr label)
159     {
160         return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), label.m_label));
161     }
162
163     CodeLocationDataLabel32 locationOf(DataLabel32 label)
164     {
165         return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), label.m_label));
166     }
167
168     // This method obtains the return address of the call, given as an offset from
169     // the start of the code.
170     unsigned returnAddressOffset(Call call)
171     {
172         return MacroAssembler::getLinkerCallReturnOffset(call);
173     }
174
175     // Upon completion of all patching either 'finalizeCode()' or 'finalizeCodeAddendum()' should be called
176     // once to complete generation of the code.  'finalizeCode()' is suited to situations
177     // where the executable pool must also be retained, the lighter-weight 'finalizeCodeAddendum()' is
178     // suited to adding to an existing allocation.
179     CodeRef finalizeCode()
180     {
181         performFinalization();
182
183         return CodeRef(m_code, m_executablePool, m_size);
184     }
185     CodeLocationLabel finalizeCodeAddendum()
186     {
187         performFinalization();
188
189         return CodeLocationLabel(code());
190     }
191
192 protected:
193     // Keep this private! - the underlying code should only be obtained externally via 
194     // finalizeCode() or finalizeCodeAddendum().
195     void* code()
196     {
197         return m_code;
198     }
199
200     void *executableCopy(MacroAssembler &masm, ExecutablePool *pool)
201     {
202         return masm.m_assembler.executableCopy(pool);
203     }
204
205     void performFinalization()
206     {
207 #ifndef NDEBUG
208         ASSERT(!m_completed);
209         m_completed = true;
210 #endif
211
212         ExecutableAllocator::makeExecutable(code(), m_size);
213         ExecutableAllocator::cacheFlush(code(), m_size);
214     }
215
216     ExecutablePool* m_executablePool;
217     void* m_code;
218     size_t m_size;
219 #ifndef NDEBUG
220     bool m_completed;
221 #endif
222 };
223
224 } // namespace JSC
225
226 #endif // ENABLE(ASSEMBLER)
227
228 #endif // LinkBuffer_h