]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGAssemblyHelpers.h
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / dfg / DFGAssemblyHelpers.h
1 /*
2 * Copyright (C) 2011 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 DFGAssemblyHelpers_h
27 #define DFGAssemblyHelpers_h
28
29 #include <wtf/Platform.h>
30
31 #if ENABLE(DFG_JIT)
32
33 #include "CodeBlock.h"
34 #include "DFGFPRInfo.h"
35 #include "DFGGPRInfo.h"
36 #include "DFGNode.h"
37 #include "JSGlobalData.h"
38 #include "MacroAssembler.h"
39
40 namespace JSC { namespace DFG {
41
42 typedef void (*V_DFGDebugOperation_EP)(ExecState*, void*);
43
44 class AssemblyHelpers : public MacroAssembler {
45 public:
46 AssemblyHelpers(JSGlobalData* globalData, CodeBlock* codeBlock)
47 : m_globalData(globalData)
48 , m_codeBlock(codeBlock)
49 , m_baselineCodeBlock(codeBlock->baselineVersion())
50 {
51 ASSERT(m_codeBlock);
52 ASSERT(m_baselineCodeBlock);
53 ASSERT(!m_baselineCodeBlock->alternative());
54 ASSERT(m_baselineCodeBlock->getJITType() == JITCode::BaselineJIT);
55 }
56
57 CodeBlock* codeBlock() { return m_codeBlock; }
58 JSGlobalData* globalData() { return m_globalData; }
59 AssemblerType_T& assembler() { return m_assembler; }
60
61 #if CPU(X86_64) || CPU(X86)
62 void preserveReturnAddressAfterCall(GPRReg reg)
63 {
64 pop(reg);
65 }
66
67 void restoreReturnAddressBeforeReturn(GPRReg reg)
68 {
69 push(reg);
70 }
71
72 void restoreReturnAddressBeforeReturn(Address address)
73 {
74 push(address);
75 }
76 #endif // CPU(X86_64) || CPU(X86)
77
78 #if CPU(ARM)
79 ALWAYS_INLINE void preserveReturnAddressAfterCall(RegisterID reg)
80 {
81 move(linkRegister, reg);
82 }
83
84 ALWAYS_INLINE void restoreReturnAddressBeforeReturn(RegisterID reg)
85 {
86 move(reg, linkRegister);
87 }
88
89 ALWAYS_INLINE void restoreReturnAddressBeforeReturn(Address address)
90 {
91 loadPtr(address, linkRegister);
92 }
93 #endif
94
95 void emitGetFromCallFrameHeaderPtr(RegisterFile::CallFrameHeaderEntry entry, GPRReg to)
96 {
97 loadPtr(Address(GPRInfo::callFrameRegister, entry * sizeof(Register)), to);
98 }
99 void emitPutToCallFrameHeader(GPRReg from, RegisterFile::CallFrameHeaderEntry entry)
100 {
101 storePtr(from, Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
102 }
103
104 void emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry)
105 {
106 storePtr(TrustedImmPtr(value), Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
107 }
108
109 Jump branchIfNotCell(GPRReg reg)
110 {
111 #if USE(JSVALUE64)
112 return branchTestPtr(MacroAssembler::NonZero, reg, GPRInfo::tagMaskRegister);
113 #else
114 return branch32(MacroAssembler::NotEqual, reg, TrustedImm32(JSValue::CellTag));
115 #endif
116 }
117
118 static Address addressForGlobalVar(GPRReg global, int32_t varNumber)
119 {
120 return Address(global, varNumber * sizeof(Register));
121 }
122
123 static Address tagForGlobalVar(GPRReg global, int32_t varNumber)
124 {
125 return Address(global, varNumber * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
126 }
127
128 static Address payloadForGlobalVar(GPRReg global, int32_t varNumber)
129 {
130 return Address(global, varNumber * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
131 }
132
133 static Address addressFor(VirtualRegister virtualRegister)
134 {
135 return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register));
136 }
137
138 static Address tagFor(VirtualRegister virtualRegister)
139 {
140 return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
141 }
142
143 static Address payloadFor(VirtualRegister virtualRegister)
144 {
145 return Address(GPRInfo::callFrameRegister, virtualRegister * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
146 }
147
148 Jump branchIfNotObject(GPRReg structureReg)
149 {
150 return branch8(Below, Address(structureReg, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
151 }
152
153 static GPRReg selectScratchGPR(GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg, GPRReg preserve4 = InvalidGPRReg)
154 {
155 if (preserve1 != GPRInfo::regT0 && preserve2 != GPRInfo::regT0 && preserve3 != GPRInfo::regT0 && preserve4 != GPRInfo::regT0)
156 return GPRInfo::regT0;
157
158 if (preserve1 != GPRInfo::regT1 && preserve2 != GPRInfo::regT1 && preserve3 != GPRInfo::regT1 && preserve4 != GPRInfo::regT1)
159 return GPRInfo::regT1;
160
161 if (preserve1 != GPRInfo::regT2 && preserve2 != GPRInfo::regT2 && preserve3 != GPRInfo::regT2 && preserve4 != GPRInfo::regT2)
162 return GPRInfo::regT2;
163
164 if (preserve1 != GPRInfo::regT3 && preserve2 != GPRInfo::regT3 && preserve3 != GPRInfo::regT3 && preserve4 != GPRInfo::regT3)
165 return GPRInfo::regT3;
166
167 return GPRInfo::regT4;
168 }
169
170 // Add a debug call. This call has no effect on JIT code execution state.
171 void debugCall(V_DFGDebugOperation_EP function, void* argument)
172 {
173 size_t scratchSize = sizeof(EncodedJSValue) * (GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters);
174 ScratchBuffer* scratchBuffer = m_globalData->scratchBufferForSize(scratchSize);
175 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
176
177 for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i)
178 storePtr(GPRInfo::toRegister(i), buffer + i);
179 for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
180 move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
181 storeDouble(FPRInfo::toRegister(i), GPRInfo::regT0);
182 }
183
184 // Tell GC mark phase how much of the scratch buffer is active during call.
185 move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
186 storePtr(TrustedImmPtr(scratchSize), GPRInfo::regT0);
187
188 #if CPU(X86_64) || CPU(ARM_THUMB2)
189 move(TrustedImmPtr(argument), GPRInfo::argumentGPR1);
190 move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
191 GPRReg scratch = selectScratchGPR(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1);
192 #elif CPU(X86)
193 poke(GPRInfo::callFrameRegister, 0);
194 poke(TrustedImmPtr(argument), 1);
195 GPRReg scratch = GPRInfo::regT0;
196 #else
197 #error "DFG JIT not supported on this platform."
198 #endif
199 move(TrustedImmPtr(reinterpret_cast<void*>(function)), scratch);
200 call(scratch);
201
202 move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
203 storePtr(TrustedImmPtr(0), GPRInfo::regT0);
204
205 for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
206 move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
207 loadDouble(GPRInfo::regT0, FPRInfo::toRegister(i));
208 }
209 for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i)
210 loadPtr(buffer + i, GPRInfo::toRegister(i));
211 }
212
213 // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs.
214 #if DFG_ENABLE(JIT_ASSERT)
215 void jitAssertIsInt32(GPRReg);
216 void jitAssertIsJSInt32(GPRReg);
217 void jitAssertIsJSNumber(GPRReg);
218 void jitAssertIsJSDouble(GPRReg);
219 void jitAssertIsCell(GPRReg);
220 void jitAssertHasValidCallFrame();
221 #else
222 void jitAssertIsInt32(GPRReg) { }
223 void jitAssertIsJSInt32(GPRReg) { }
224 void jitAssertIsJSNumber(GPRReg) { }
225 void jitAssertIsJSDouble(GPRReg) { }
226 void jitAssertIsCell(GPRReg) { }
227 void jitAssertHasValidCallFrame() { }
228 #endif
229
230 // These methods convert between doubles, and doubles boxed and JSValues.
231 #if USE(JSVALUE64)
232 GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
233 {
234 moveDoubleToPtr(fpr, gpr);
235 subPtr(GPRInfo::tagTypeNumberRegister, gpr);
236 jitAssertIsJSDouble(gpr);
237 return gpr;
238 }
239 FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
240 {
241 jitAssertIsJSDouble(gpr);
242 addPtr(GPRInfo::tagTypeNumberRegister, gpr);
243 movePtrToDouble(gpr, fpr);
244 return fpr;
245 }
246 #endif
247
248 #if USE(JSVALUE32_64) && CPU(X86)
249 void boxDouble(FPRReg fpr, GPRReg tagGPR, GPRReg payloadGPR)
250 {
251 movePackedToInt32(fpr, payloadGPR);
252 rshiftPacked(TrustedImm32(32), fpr);
253 movePackedToInt32(fpr, tagGPR);
254 }
255 void unboxDouble(GPRReg tagGPR, GPRReg payloadGPR, FPRReg fpr, FPRReg scratchFPR)
256 {
257 jitAssertIsJSDouble(tagGPR);
258 moveInt32ToPacked(payloadGPR, fpr);
259 moveInt32ToPacked(tagGPR, scratchFPR);
260 lshiftPacked(TrustedImm32(32), scratchFPR);
261 orPacked(scratchFPR, fpr);
262 }
263 #endif
264
265 #if USE(JSVALUE32_64) && CPU(ARM)
266 void boxDouble(FPRReg fpr, GPRReg tagGPR, GPRReg payloadGPR)
267 {
268 m_assembler.vmov(payloadGPR, tagGPR, fpr);
269 }
270 void unboxDouble(GPRReg tagGPR, GPRReg payloadGPR, FPRReg fpr, FPRReg scratchFPR)
271 {
272 jitAssertIsJSDouble(tagGPR);
273 UNUSED_PARAM(scratchFPR);
274 m_assembler.vmov(fpr, payloadGPR, tagGPR);
275 }
276 #endif
277
278 enum ExceptionCheckKind { NormalExceptionCheck, InvertedExceptionCheck };
279 Jump emitExceptionCheck(ExceptionCheckKind kind = NormalExceptionCheck)
280 {
281 #if USE(JSVALUE64)
282 return branchTestPtr(kind == NormalExceptionCheck ? NonZero : Zero, AbsoluteAddress(&globalData()->exception));
283 #elif USE(JSVALUE32_64)
284 return branch32(kind == NormalExceptionCheck ? NotEqual : Equal, AbsoluteAddress(reinterpret_cast<char*>(&globalData()->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
285 #endif
286 }
287
288 #if ENABLE(SAMPLING_COUNTERS)
289 static void emitCount(MacroAssembler& jit, AbstractSamplingCounter& counter, int32_t increment = 1)
290 {
291 jit.add64(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
292 }
293 void emitCount(AbstractSamplingCounter& counter, int32_t increment = 1)
294 {
295 add64(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
296 }
297 #endif
298
299 #if ENABLE(SAMPLING_FLAGS)
300 void setSamplingFlag(int32_t);
301 void clearSamplingFlag(int32_t flag);
302 #endif
303
304 JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin)
305 {
306 return codeBlock()->globalObjectFor(codeOrigin);
307 }
308
309 JSObject* globalThisObjectFor(CodeOrigin codeOrigin)
310 {
311 JSGlobalObject* object = globalObjectFor(codeOrigin);
312 return object->methodTable()->toThisObject(object, 0);
313 }
314
315 bool strictModeFor(CodeOrigin codeOrigin)
316 {
317 if (!codeOrigin.inlineCallFrame)
318 return codeBlock()->isStrictMode();
319 return codeOrigin.inlineCallFrame->callee->jsExecutable()->isStrictMode();
320 }
321
322 CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin)
323 {
324 return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, baselineCodeBlock());
325 }
326
327 CodeBlock* baselineCodeBlock()
328 {
329 return m_baselineCodeBlock;
330 }
331
332 Vector<BytecodeAndMachineOffset>& decodedCodeMapFor(CodeBlock*);
333
334 static const double twoToThe32;
335
336 protected:
337 JSGlobalData* m_globalData;
338 CodeBlock* m_codeBlock;
339 CodeBlock* m_baselineCodeBlock;
340
341 HashMap<CodeBlock*, Vector<BytecodeAndMachineOffset> > m_decodedCodeMaps;
342 };
343
344 } } // namespace JSC::DFG
345
346 #endif // ENABLE(DFG_JIT)
347
348 #endif // DFGAssemblyHelpers_h
349