]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - jit/JSInterfaceJIT.h
JavaScriptCore-1097.3.tar.gz
[apple/javascriptcore.git] / jit / JSInterfaceJIT.h
... / ...
CommitLineData
1/*
2 * Copyright (C) 2010 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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef JSInterfaceJIT_h
27#define JSInterfaceJIT_h
28
29#include "BytecodeConventions.h"
30#include "JITCode.h"
31#include "JITStubs.h"
32#include "JSString.h"
33#include "JSValue.h"
34#include "MacroAssembler.h"
35#include "RegisterFile.h"
36#include <wtf/AlwaysInline.h>
37#include <wtf/Vector.h>
38
39namespace JSC {
40 class JSInterfaceJIT : public MacroAssembler {
41 public:
42 // NOTES:
43 //
44 // regT0 has two special meanings. The return value from a stub
45 // call will always be in regT0, and by default (unless
46 // a register is specified) emitPutVirtualRegister() will store
47 // the value from regT0.
48 //
49 // regT3 is required to be callee-preserved.
50 //
51 // tempRegister2 is has no such dependencies. It is important that
52 // on x86/x86-64 it is ecx for performance reasons, since the
53 // MacroAssembler will need to plant register swaps if it is not -
54 // however the code will still function correctly.
55#if CPU(X86_64)
56 static const RegisterID returnValueRegister = X86Registers::eax;
57 static const RegisterID cachedResultRegister = X86Registers::eax;
58 static const RegisterID firstArgumentRegister = X86Registers::edi;
59
60#if ENABLE(VALUE_PROFILER)
61 static const RegisterID bucketCounterRegister = X86Registers::r10;
62#endif
63
64 static const RegisterID timeoutCheckRegister = X86Registers::r12;
65 static const RegisterID callFrameRegister = X86Registers::r13;
66 static const RegisterID tagTypeNumberRegister = X86Registers::r14;
67 static const RegisterID tagMaskRegister = X86Registers::r15;
68
69 static const RegisterID regT0 = X86Registers::eax;
70 static const RegisterID regT1 = X86Registers::edx;
71 static const RegisterID regT2 = X86Registers::ecx;
72 static const RegisterID regT3 = X86Registers::ebx;
73
74 static const FPRegisterID fpRegT0 = X86Registers::xmm0;
75 static const FPRegisterID fpRegT1 = X86Registers::xmm1;
76 static const FPRegisterID fpRegT2 = X86Registers::xmm2;
77 static const FPRegisterID fpRegT3 = X86Registers::xmm3;
78#elif CPU(X86)
79 static const RegisterID returnValueRegister = X86Registers::eax;
80 static const RegisterID cachedResultRegister = X86Registers::eax;
81 // On x86 we always use fastcall conventions = but on
82 // OS X if might make more sense to just use regparm.
83 static const RegisterID firstArgumentRegister = X86Registers::ecx;
84
85 static const RegisterID bucketCounterRegister = X86Registers::esi;
86 static const RegisterID callFrameRegister = X86Registers::edi;
87
88 static const RegisterID regT0 = X86Registers::eax;
89 static const RegisterID regT1 = X86Registers::edx;
90 static const RegisterID regT2 = X86Registers::ecx;
91 static const RegisterID regT3 = X86Registers::ebx;
92
93 static const FPRegisterID fpRegT0 = X86Registers::xmm0;
94 static const FPRegisterID fpRegT1 = X86Registers::xmm1;
95 static const FPRegisterID fpRegT2 = X86Registers::xmm2;
96 static const FPRegisterID fpRegT3 = X86Registers::xmm3;
97#elif CPU(ARM_THUMB2)
98 static const RegisterID returnValueRegister = ARMRegisters::r0;
99 static const RegisterID cachedResultRegister = ARMRegisters::r0;
100 static const RegisterID firstArgumentRegister = ARMRegisters::r0;
101
102#if ENABLE(VALUE_PROFILER)
103 static const RegisterID bucketCounterRegister = ARMRegisters::r7;
104#endif
105
106 static const RegisterID regT0 = ARMRegisters::r0;
107 static const RegisterID regT1 = ARMRegisters::r1;
108 static const RegisterID regT2 = ARMRegisters::r2;
109 static const RegisterID regT3 = ARMRegisters::r4;
110
111 static const RegisterID callFrameRegister = ARMRegisters::r5;
112 static const RegisterID timeoutCheckRegister = ARMRegisters::r6;
113
114 static const FPRegisterID fpRegT0 = ARMRegisters::d0;
115 static const FPRegisterID fpRegT1 = ARMRegisters::d1;
116 static const FPRegisterID fpRegT2 = ARMRegisters::d2;
117 static const FPRegisterID fpRegT3 = ARMRegisters::d3;
118#elif CPU(ARM_TRADITIONAL)
119 static const RegisterID returnValueRegister = ARMRegisters::r0;
120 static const RegisterID cachedResultRegister = ARMRegisters::r0;
121 static const RegisterID firstArgumentRegister = ARMRegisters::r0;
122
123 static const RegisterID timeoutCheckRegister = ARMRegisters::r5;
124 static const RegisterID callFrameRegister = ARMRegisters::r4;
125
126 static const RegisterID regT0 = ARMRegisters::r0;
127 static const RegisterID regT1 = ARMRegisters::r1;
128 static const RegisterID regT2 = ARMRegisters::r2;
129 // Callee preserved
130 static const RegisterID regT3 = ARMRegisters::r7;
131
132 static const RegisterID regS0 = ARMRegisters::S0;
133 // Callee preserved
134 static const RegisterID regS1 = ARMRegisters::S1;
135
136 static const RegisterID regStackPtr = ARMRegisters::sp;
137 static const RegisterID regLink = ARMRegisters::lr;
138
139 static const FPRegisterID fpRegT0 = ARMRegisters::d0;
140 static const FPRegisterID fpRegT1 = ARMRegisters::d1;
141 static const FPRegisterID fpRegT2 = ARMRegisters::d2;
142 static const FPRegisterID fpRegT3 = ARMRegisters::d3;
143#elif CPU(MIPS)
144 static const RegisterID returnValueRegister = MIPSRegisters::v0;
145 static const RegisterID cachedResultRegister = MIPSRegisters::v0;
146 static const RegisterID firstArgumentRegister = MIPSRegisters::a0;
147
148 // regT0 must be v0 for returning a 32-bit value.
149 static const RegisterID regT0 = MIPSRegisters::v0;
150
151 // regT1 must be v1 for returning a pair of 32-bit value.
152 static const RegisterID regT1 = MIPSRegisters::v1;
153
154 static const RegisterID regT2 = MIPSRegisters::t4;
155
156 // regT3 must be saved in the callee, so use an S register.
157 static const RegisterID regT3 = MIPSRegisters::s2;
158
159 static const RegisterID callFrameRegister = MIPSRegisters::s0;
160 static const RegisterID timeoutCheckRegister = MIPSRegisters::s1;
161
162 static const FPRegisterID fpRegT0 = MIPSRegisters::f4;
163 static const FPRegisterID fpRegT1 = MIPSRegisters::f6;
164 static const FPRegisterID fpRegT2 = MIPSRegisters::f8;
165 static const FPRegisterID fpRegT3 = MIPSRegisters::f10;
166#elif CPU(SH4)
167 static const RegisterID timeoutCheckRegister = SH4Registers::r8;
168 static const RegisterID callFrameRegister = SH4Registers::fp;
169
170 static const RegisterID regT0 = SH4Registers::r0;
171 static const RegisterID regT1 = SH4Registers::r1;
172 static const RegisterID regT2 = SH4Registers::r2;
173 static const RegisterID regT3 = SH4Registers::r10;
174 static const RegisterID regT4 = SH4Registers::r4;
175 static const RegisterID regT5 = SH4Registers::r5;
176 static const RegisterID regT6 = SH4Registers::r6;
177 static const RegisterID regT7 = SH4Registers::r7;
178 static const RegisterID firstArgumentRegister =regT4;
179
180 static const RegisterID returnValueRegister = SH4Registers::r0;
181 static const RegisterID cachedResultRegister = SH4Registers::r0;
182
183 static const FPRegisterID fpRegT0 = SH4Registers::fr0;
184 static const FPRegisterID fpRegT1 = SH4Registers::fr2;
185 static const FPRegisterID fpRegT2 = SH4Registers::fr4;
186 static const FPRegisterID fpRegT3 = SH4Registers::fr6;
187 static const FPRegisterID fpRegT4 = SH4Registers::fr8;
188 static const FPRegisterID fpRegT5 = SH4Registers::fr10;
189 static const FPRegisterID fpRegT6 = SH4Registers::fr12;
190 static const FPRegisterID fpRegT7 = SH4Registers::fr14;
191#else
192#error "JIT not supported on this platform."
193#endif
194
195#if USE(JSVALUE32_64)
196 // Can't just propogate JSValue::Int32Tag as visual studio doesn't like it
197 static const unsigned Int32Tag = 0xffffffff;
198 COMPILE_ASSERT(Int32Tag == JSValue::Int32Tag, Int32Tag_out_of_sync);
199#else
200 static const unsigned Int32Tag = TagTypeNumber >> 32;
201#endif
202 inline Jump emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload);
203 inline Jump emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst);
204 inline Jump emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch);
205
206#if USE(JSVALUE32_64)
207 inline Jump emitJumpIfNotJSCell(unsigned virtualRegisterIndex);
208 inline Address tagFor(int index, RegisterID base = callFrameRegister);
209#endif
210
211#if USE(JSVALUE64)
212 Jump emitJumpIfImmediateNumber(RegisterID reg);
213 Jump emitJumpIfNotImmediateNumber(RegisterID reg);
214 void emitFastArithImmToInt(RegisterID reg);
215#endif
216
217 inline Address payloadFor(int index, RegisterID base = callFrameRegister);
218 inline Address intPayloadFor(int index, RegisterID base = callFrameRegister);
219 inline Address intTagFor(int index, RegisterID base = callFrameRegister);
220 inline Address addressFor(int index, RegisterID base = callFrameRegister);
221 };
222
223 struct ThunkHelpers {
224 static unsigned stringImplFlagsOffset() { return StringImpl::flagsOffset(); }
225 static unsigned stringImpl8BitFlag() { return StringImpl::flagIs8Bit(); }
226 static unsigned stringImplDataOffset() { return StringImpl::dataOffset(); }
227 static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString, m_length); }
228 static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString, m_value); }
229 };
230
231#if USE(JSVALUE32_64)
232 inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload)
233 {
234 loadPtr(payloadFor(virtualRegisterIndex), payload);
235 return emitJumpIfNotJSCell(virtualRegisterIndex);
236 }
237
238 inline JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex)
239 {
240 ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
241 return branch32(NotEqual, tagFor(virtualRegisterIndex), TrustedImm32(JSValue::CellTag));
242 }
243
244 inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
245 {
246 ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
247 loadPtr(payloadFor(virtualRegisterIndex), dst);
248 return branch32(NotEqual, tagFor(static_cast<int>(virtualRegisterIndex)), TrustedImm32(JSValue::Int32Tag));
249 }
250
251 inline JSInterfaceJIT::Address JSInterfaceJIT::tagFor(int virtualRegisterIndex, RegisterID base)
252 {
253 ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
254 return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.tag));
255 }
256
257 inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base)
258 {
259 ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
260 return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.payload));
261 }
262
263 inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base)
264 {
265 return payloadFor(virtualRegisterIndex, base);
266 }
267
268 inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base)
269 {
270 return tagFor(virtualRegisterIndex, base);
271 }
272
273 inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
274 {
275 ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
276 loadPtr(tagFor(virtualRegisterIndex), scratch);
277 Jump isDouble = branch32(Below, scratch, TrustedImm32(JSValue::LowestTag));
278 Jump notInt = branch32(NotEqual, scratch, TrustedImm32(JSValue::Int32Tag));
279 loadPtr(payloadFor(virtualRegisterIndex), scratch);
280 convertInt32ToDouble(scratch, dst);
281 Jump done = jump();
282 isDouble.link(this);
283 loadDouble(addressFor(virtualRegisterIndex), dst);
284 done.link(this);
285 return notInt;
286 }
287
288#endif
289
290#if USE(JSVALUE64)
291 ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg)
292 {
293 return branchTestPtr(NonZero, reg, tagTypeNumberRegister);
294 }
295 ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg)
296 {
297 return branchTestPtr(Zero, reg, tagTypeNumberRegister);
298 }
299 inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID dst)
300 {
301 loadPtr(addressFor(virtualRegisterIndex), dst);
302 return branchTestPtr(NonZero, dst, tagMaskRegister);
303 }
304
305 inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
306 {
307 loadPtr(addressFor(virtualRegisterIndex), dst);
308 Jump result = branchPtr(Below, dst, tagTypeNumberRegister);
309 zeroExtend32ToPtr(dst, dst);
310 return result;
311 }
312
313 inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
314 {
315 loadPtr(addressFor(virtualRegisterIndex), scratch);
316 Jump notNumber = emitJumpIfNotImmediateNumber(scratch);
317 Jump notInt = branchPtr(Below, scratch, tagTypeNumberRegister);
318 convertInt32ToDouble(scratch, dst);
319 Jump done = jump();
320 notInt.link(this);
321 addPtr(tagTypeNumberRegister, scratch);
322 movePtrToDouble(scratch, dst);
323 done.link(this);
324 return notNumber;
325 }
326
327 ALWAYS_INLINE void JSInterfaceJIT::emitFastArithImmToInt(RegisterID)
328 {
329 }
330
331#endif
332
333#if USE(JSVALUE64)
334 inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base)
335 {
336 ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
337 return addressFor(virtualRegisterIndex, base);
338 }
339
340 inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base)
341 {
342 ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
343 return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
344 }
345 inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base)
346 {
347 ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
348 return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
349 }
350#endif
351
352 inline JSInterfaceJIT::Address JSInterfaceJIT::addressFor(int virtualRegisterIndex, RegisterID base)
353 {
354 ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
355 return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)));
356 }
357
358}
359
360#endif // JSInterfaceJIT_h