9c77118a8859c765c58cbf614aefa963e9306dd8
[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 "CCallHelpers.h"
31 #include "FPRInfo.h"
32 #include "GPRInfo.h"
33 #include "JITCode.h"
34 #include "JITOperations.h"
35 #include "JITStubs.h"
36 #include "JSCJSValue.h"
37 #include "JSStack.h"
38 #include "JSString.h"
39 #include "MacroAssembler.h"
40 #include <wtf/Vector.h>
41
42 #if ENABLE(JIT)
43
44 namespace JSC {
45     class JSInterfaceJIT : public CCallHelpers, public GPRInfo, public FPRInfo {
46     public:
47         JSInterfaceJIT(VM* vm, CodeBlock* codeBlock = 0)
48             : CCallHelpers(vm, codeBlock)
49         {
50         }
51
52 #if USE(JSVALUE32_64)
53         static const unsigned Int32Tag = static_cast<unsigned>(JSValue::Int32Tag);
54 #else
55         static const unsigned Int32Tag = static_cast<unsigned>(TagTypeNumber >> 32);
56 #endif
57         inline Jump emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload);
58         inline Jump emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst);
59         inline Jump emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch);
60
61 #if USE(JSVALUE32_64)
62         inline Jump emitJumpIfNotJSCell(unsigned virtualRegisterIndex);
63         inline Address tagFor(int index, RegisterID base = callFrameRegister);
64 #endif
65
66 #if USE(JSVALUE64)
67         Jump emitJumpIfNotJSCell(RegisterID);
68         Jump emitJumpIfImmediateNumber(RegisterID reg);
69         Jump emitJumpIfNotImmediateNumber(RegisterID reg);
70         void emitFastArithImmToInt(RegisterID reg);
71         void emitFastArithIntToImmNoCheck(RegisterID src, RegisterID dest);
72 #endif
73
74         Jump emitJumpIfNotType(RegisterID baseReg, JSType);
75
76         void emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry, RegisterID to, RegisterID from = callFrameRegister);
77         void emitPutToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry);
78         void emitPutImmediateToCallFrameHeader(void* value, JSStack::CallFrameHeaderEntry);
79         void emitPutCellToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry);
80
81         inline Address payloadFor(int index, RegisterID base = callFrameRegister);
82         inline Address intPayloadFor(int index, RegisterID base = callFrameRegister);
83         inline Address intTagFor(int index, RegisterID base = callFrameRegister);
84         inline Address addressFor(int index, RegisterID base = callFrameRegister);
85     };
86
87     struct ThunkHelpers {
88         static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString, m_length); }
89         static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString, m_value); }
90     };
91
92 #if USE(JSVALUE32_64)
93     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload)
94     {
95         loadPtr(payloadFor(virtualRegisterIndex), payload);
96         return emitJumpIfNotJSCell(virtualRegisterIndex);
97     }
98
99     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex)
100     {
101         ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
102         return branch32(NotEqual, tagFor(virtualRegisterIndex), TrustedImm32(JSValue::CellTag));
103     }
104     
105     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
106     {
107         ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
108         loadPtr(payloadFor(virtualRegisterIndex), dst);
109         return branch32(NotEqual, tagFor(static_cast<int>(virtualRegisterIndex)), TrustedImm32(JSValue::Int32Tag));
110     }
111     
112     inline JSInterfaceJIT::Address JSInterfaceJIT::tagFor(int virtualRegisterIndex, RegisterID base)
113     {
114         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
115         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.tag));
116     }
117     
118     inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base)
119     {
120         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
121         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.payload));
122     }
123
124     inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base)
125     {
126         return payloadFor(virtualRegisterIndex, base);
127     }
128
129     inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base)
130     {
131         return tagFor(virtualRegisterIndex, base);
132     }
133
134     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
135     {
136         ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
137         loadPtr(tagFor(virtualRegisterIndex), scratch);
138         Jump isDouble = branch32(Below, scratch, TrustedImm32(JSValue::LowestTag));
139         Jump notInt = branch32(NotEqual, scratch, TrustedImm32(JSValue::Int32Tag));
140         loadPtr(payloadFor(virtualRegisterIndex), scratch);
141         convertInt32ToDouble(scratch, dst);
142         Jump done = jump();
143         isDouble.link(this);
144         loadDouble(addressFor(virtualRegisterIndex), dst);
145         done.link(this);
146         return notInt;
147     }
148
149 #endif
150
151 #if USE(JSVALUE64)
152     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotJSCell(RegisterID reg)
153     {
154         return branchTest64(NonZero, reg, tagMaskRegister);
155     }
156
157     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg)
158     {
159         return branchTest64(NonZero, reg, tagTypeNumberRegister);
160     }
161     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg)
162     {
163         return branchTest64(Zero, reg, tagTypeNumberRegister);
164     }
165     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID dst)
166     {
167         load64(addressFor(virtualRegisterIndex), dst);
168         return branchTest64(NonZero, dst, tagMaskRegister);
169     }
170     
171     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
172     {
173         load64(addressFor(virtualRegisterIndex), dst);
174         Jump result = branch64(Below, dst, tagTypeNumberRegister);
175         zeroExtend32ToPtr(dst, dst);
176         return result;
177     }
178
179     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
180     {
181         load64(addressFor(virtualRegisterIndex), scratch);
182         Jump notNumber = emitJumpIfNotImmediateNumber(scratch);
183         Jump notInt = branch64(Below, scratch, tagTypeNumberRegister);
184         convertInt32ToDouble(scratch, dst);
185         Jump done = jump();
186         notInt.link(this);
187         add64(tagTypeNumberRegister, scratch);
188         move64ToDouble(scratch, dst);
189         done.link(this);
190         return notNumber;
191     }
192
193     ALWAYS_INLINE void JSInterfaceJIT::emitFastArithImmToInt(RegisterID)
194     {
195     }
196     
197     // operand is int32_t, must have been zero-extended if register is 64-bit.
198     ALWAYS_INLINE void JSInterfaceJIT::emitFastArithIntToImmNoCheck(RegisterID src, RegisterID dest)
199     {
200         if (src != dest)
201             move(src, dest);
202         or64(tagTypeNumberRegister, dest);
203     }
204 #endif
205
206 #if USE(JSVALUE64)
207     inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base)
208     {
209         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
210         return addressFor(virtualRegisterIndex, base);
211     }
212
213     inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base)
214     {
215         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
216         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
217     }
218     inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base)
219     {
220         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
221         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
222     }
223 #endif
224
225     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotType(RegisterID baseReg, JSType type)
226     {
227         return branch8(NotEqual, Address(baseReg, JSCell::typeInfoTypeOffset()), TrustedImm32(type));
228     }
229
230     ALWAYS_INLINE void JSInterfaceJIT::emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry, RegisterID to, RegisterID from)
231     {
232         loadPtr(Address(from, entry * sizeof(Register)), to);
233     }
234
235     ALWAYS_INLINE void JSInterfaceJIT::emitPutToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry)
236     {
237 #if USE(JSVALUE32_64)
238         storePtr(from, payloadFor(entry, callFrameRegister));
239 #else
240         store64(from, addressFor(entry, callFrameRegister));
241 #endif
242     }
243
244     ALWAYS_INLINE void JSInterfaceJIT::emitPutImmediateToCallFrameHeader(void* value, JSStack::CallFrameHeaderEntry entry)
245     {
246         storePtr(TrustedImmPtr(value), Address(callFrameRegister, entry * sizeof(Register)));
247     }
248
249     ALWAYS_INLINE void JSInterfaceJIT::emitPutCellToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry)
250     {
251 #if USE(JSVALUE32_64)
252         store32(TrustedImm32(JSValue::CellTag), tagFor(entry, callFrameRegister));
253         store32(from, payloadFor(entry, callFrameRegister));
254 #else
255         store64(from, addressFor(entry, callFrameRegister));
256 #endif
257     }
258
259     inline JSInterfaceJIT::Address JSInterfaceJIT::addressFor(int virtualRegisterIndex, RegisterID base)
260     {
261         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
262         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)));
263     }
264
265 } // namespace JSC
266
267 #endif // ENABLE(JIT)
268
269 #endif // JSInterfaceJIT_h