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