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