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