05d1ce5ad8cdaafc1891747821f33577ebf2a298
[WebKit-https.git] / Source / JavaScriptCore / jit / JSInterfaceJIT.h
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
39 namespace 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