]>
Commit | Line | Data |
---|---|---|
4e4e5a6f A |
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 | ||
6fe7ccc8 | 29 | #include "BytecodeConventions.h" |
4e4e5a6f A |
30 | #include "JITCode.h" |
31 | #include "JITStubs.h" | |
93a37866 A |
32 | #include "JSCJSValue.h" |
33 | #include "JSStack.h" | |
6fe7ccc8 | 34 | #include "JSString.h" |
4e4e5a6f | 35 | #include "MacroAssembler.h" |
4e4e5a6f A |
36 | #include <wtf/Vector.h> |
37 | ||
93a37866 A |
38 | #if ENABLE(JIT) |
39 | ||
4e4e5a6f A |
40 | namespace JSC { |
41 | class JSInterfaceJIT : public MacroAssembler { | |
42 | public: | |
43 | // NOTES: | |
44 | // | |
45 | // regT0 has two special meanings. The return value from a stub | |
46 | // call will always be in regT0, and by default (unless | |
47 | // a register is specified) emitPutVirtualRegister() will store | |
48 | // the value from regT0. | |
49 | // | |
50 | // regT3 is required to be callee-preserved. | |
51 | // | |
52 | // tempRegister2 is has no such dependencies. It is important that | |
53 | // on x86/x86-64 it is ecx for performance reasons, since the | |
54 | // MacroAssembler will need to plant register swaps if it is not - | |
55 | // however the code will still function correctly. | |
56 | #if CPU(X86_64) | |
57 | static const RegisterID returnValueRegister = X86Registers::eax; | |
58 | static const RegisterID cachedResultRegister = X86Registers::eax; | |
93a37866 | 59 | #if !OS(WINDOWS) |
4e4e5a6f | 60 | static const RegisterID firstArgumentRegister = X86Registers::edi; |
93a37866 A |
61 | #else |
62 | static const RegisterID firstArgumentRegister = X86Registers::ecx; | |
63 | #endif | |
64 | ||
6fe7ccc8 A |
65 | #if ENABLE(VALUE_PROFILER) |
66 | static const RegisterID bucketCounterRegister = X86Registers::r10; | |
67 | #endif | |
93a37866 | 68 | |
4e4e5a6f A |
69 | static const RegisterID callFrameRegister = X86Registers::r13; |
70 | static const RegisterID tagTypeNumberRegister = X86Registers::r14; | |
71 | static const RegisterID tagMaskRegister = X86Registers::r15; | |
93a37866 | 72 | |
4e4e5a6f A |
73 | static const RegisterID regT0 = X86Registers::eax; |
74 | static const RegisterID regT1 = X86Registers::edx; | |
75 | static const RegisterID regT2 = X86Registers::ecx; | |
76 | static const RegisterID regT3 = X86Registers::ebx; | |
93a37866 | 77 | |
4e4e5a6f A |
78 | static const FPRegisterID fpRegT0 = X86Registers::xmm0; |
79 | static const FPRegisterID fpRegT1 = X86Registers::xmm1; | |
80 | static const FPRegisterID fpRegT2 = X86Registers::xmm2; | |
81 | static const FPRegisterID fpRegT3 = X86Registers::xmm3; | |
93a37866 A |
82 | |
83 | static const RegisterID nonArgGPR1 = X86Registers::eax; // regT0 | |
4e4e5a6f A |
84 | #elif CPU(X86) |
85 | static const RegisterID returnValueRegister = X86Registers::eax; | |
86 | static const RegisterID cachedResultRegister = X86Registers::eax; | |
87 | // On x86 we always use fastcall conventions = but on | |
88 | // OS X if might make more sense to just use regparm. | |
89 | static const RegisterID firstArgumentRegister = X86Registers::ecx; | |
90 | ||
6fe7ccc8 | 91 | static const RegisterID bucketCounterRegister = X86Registers::esi; |
4e4e5a6f A |
92 | static const RegisterID callFrameRegister = X86Registers::edi; |
93 | ||
94 | static const RegisterID regT0 = X86Registers::eax; | |
95 | static const RegisterID regT1 = X86Registers::edx; | |
96 | static const RegisterID regT2 = X86Registers::ecx; | |
97 | static const RegisterID regT3 = X86Registers::ebx; | |
98 | ||
99 | static const FPRegisterID fpRegT0 = X86Registers::xmm0; | |
100 | static const FPRegisterID fpRegT1 = X86Registers::xmm1; | |
101 | static const FPRegisterID fpRegT2 = X86Registers::xmm2; | |
102 | static const FPRegisterID fpRegT3 = X86Registers::xmm3; | |
93a37866 | 103 | #elif CPU(ARM) |
4e4e5a6f A |
104 | static const RegisterID returnValueRegister = ARMRegisters::r0; |
105 | static const RegisterID cachedResultRegister = ARMRegisters::r0; | |
106 | static const RegisterID firstArgumentRegister = ARMRegisters::r0; | |
6fe7ccc8 A |
107 | |
108 | #if ENABLE(VALUE_PROFILER) | |
109 | static const RegisterID bucketCounterRegister = ARMRegisters::r7; | |
110 | #endif | |
111 | ||
4e4e5a6f A |
112 | static const RegisterID regT0 = ARMRegisters::r0; |
113 | static const RegisterID regT1 = ARMRegisters::r1; | |
114 | static const RegisterID regT2 = ARMRegisters::r2; | |
115 | static const RegisterID regT3 = ARMRegisters::r4; | |
93a37866 A |
116 | |
117 | // Update ctiTrampoline in JITStubs.cpp if these values are changed! | |
4e4e5a6f | 118 | static const RegisterID callFrameRegister = ARMRegisters::r5; |
93a37866 | 119 | |
4e4e5a6f A |
120 | static const FPRegisterID fpRegT0 = ARMRegisters::d0; |
121 | static const FPRegisterID fpRegT1 = ARMRegisters::d1; | |
122 | static const FPRegisterID fpRegT2 = ARMRegisters::d2; | |
123 | static const FPRegisterID fpRegT3 = ARMRegisters::d3; | |
93a37866 A |
124 | #elif CPU(ARM64) |
125 | static const RegisterID returnValueRegister = ARM64Registers::x0; | |
126 | static const RegisterID cachedResultRegister = ARM64Registers::x0; | |
127 | static const RegisterID firstArgumentRegister = ARM64Registers::x0; | |
128 | ||
129 | #if ENABLE(VALUE_PROFILER) | |
130 | static const RegisterID bucketCounterRegister = ARM64Registers::x7; | |
131 | #endif | |
132 | ||
133 | static const RegisterID regT0 = ARM64Registers::x0; | |
134 | static const RegisterID regT1 = ARM64Registers::x1; | |
135 | static const RegisterID regT2 = ARM64Registers::x2; | |
136 | static const RegisterID regT3 = ARM64Registers::x23; | |
4e4e5a6f | 137 | |
93a37866 A |
138 | static const RegisterID callFrameRegister = ARM64Registers::x25; |
139 | static const RegisterID timeoutCheckRegister = ARM64Registers::x26; | |
140 | static const RegisterID tagTypeNumberRegister = ARM64Registers::x27; | |
141 | static const RegisterID tagMaskRegister = ARM64Registers::x28; | |
4e4e5a6f | 142 | |
93a37866 A |
143 | static const FPRegisterID fpRegT0 = ARM64Registers::q0; |
144 | static const FPRegisterID fpRegT1 = ARM64Registers::q1; | |
145 | static const FPRegisterID fpRegT2 = ARM64Registers::q2; | |
146 | static const FPRegisterID fpRegT3 = ARM64Registers::q3; | |
147 | ||
148 | static const RegisterID nonArgGPR1 = ARM64Registers::x9; | |
4e4e5a6f A |
149 | #elif CPU(MIPS) |
150 | static const RegisterID returnValueRegister = MIPSRegisters::v0; | |
151 | static const RegisterID cachedResultRegister = MIPSRegisters::v0; | |
152 | static const RegisterID firstArgumentRegister = MIPSRegisters::a0; | |
153 | ||
93a37866 A |
154 | #if ENABLE(VALUE_PROFILER) |
155 | static const RegisterID bucketCounterRegister = MIPSRegisters::s3; | |
156 | #endif | |
157 | ||
4e4e5a6f A |
158 | // regT0 must be v0 for returning a 32-bit value. |
159 | static const RegisterID regT0 = MIPSRegisters::v0; | |
160 | ||
161 | // regT1 must be v1 for returning a pair of 32-bit value. | |
162 | static const RegisterID regT1 = MIPSRegisters::v1; | |
163 | ||
164 | static const RegisterID regT2 = MIPSRegisters::t4; | |
165 | ||
166 | // regT3 must be saved in the callee, so use an S register. | |
167 | static const RegisterID regT3 = MIPSRegisters::s2; | |
168 | ||
169 | static const RegisterID callFrameRegister = MIPSRegisters::s0; | |
4e4e5a6f A |
170 | |
171 | static const FPRegisterID fpRegT0 = MIPSRegisters::f4; | |
172 | static const FPRegisterID fpRegT1 = MIPSRegisters::f6; | |
173 | static const FPRegisterID fpRegT2 = MIPSRegisters::f8; | |
14957cd0 A |
174 | static const FPRegisterID fpRegT3 = MIPSRegisters::f10; |
175 | #elif CPU(SH4) | |
14957cd0 A |
176 | static const RegisterID callFrameRegister = SH4Registers::fp; |
177 | ||
178 | static const RegisterID regT0 = SH4Registers::r0; | |
179 | static const RegisterID regT1 = SH4Registers::r1; | |
180 | static const RegisterID regT2 = SH4Registers::r2; | |
181 | static const RegisterID regT3 = SH4Registers::r10; | |
182 | static const RegisterID regT4 = SH4Registers::r4; | |
183 | static const RegisterID regT5 = SH4Registers::r5; | |
184 | static const RegisterID regT6 = SH4Registers::r6; | |
185 | static const RegisterID regT7 = SH4Registers::r7; | |
186 | static const RegisterID firstArgumentRegister =regT4; | |
187 | ||
188 | static const RegisterID returnValueRegister = SH4Registers::r0; | |
189 | static const RegisterID cachedResultRegister = SH4Registers::r0; | |
190 | ||
191 | static const FPRegisterID fpRegT0 = SH4Registers::fr0; | |
192 | static const FPRegisterID fpRegT1 = SH4Registers::fr2; | |
193 | static const FPRegisterID fpRegT2 = SH4Registers::fr4; | |
194 | static const FPRegisterID fpRegT3 = SH4Registers::fr6; | |
195 | static const FPRegisterID fpRegT4 = SH4Registers::fr8; | |
196 | static const FPRegisterID fpRegT5 = SH4Registers::fr10; | |
197 | static const FPRegisterID fpRegT6 = SH4Registers::fr12; | |
198 | static const FPRegisterID fpRegT7 = SH4Registers::fr14; | |
4e4e5a6f A |
199 | #else |
200 | #error "JIT not supported on this platform." | |
201 | #endif | |
202 | ||
14957cd0 A |
203 | #if USE(JSVALUE32_64) |
204 | // Can't just propogate JSValue::Int32Tag as visual studio doesn't like it | |
205 | static const unsigned Int32Tag = 0xffffffff; | |
206 | COMPILE_ASSERT(Int32Tag == JSValue::Int32Tag, Int32Tag_out_of_sync); | |
207 | #else | |
208 | static const unsigned Int32Tag = TagTypeNumber >> 32; | |
209 | #endif | |
4e4e5a6f A |
210 | inline Jump emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload); |
211 | inline Jump emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst); | |
212 | inline Jump emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch); | |
213 | ||
214 | #if USE(JSVALUE32_64) | |
215 | inline Jump emitJumpIfNotJSCell(unsigned virtualRegisterIndex); | |
14957cd0 | 216 | inline Address tagFor(int index, RegisterID base = callFrameRegister); |
4e4e5a6f A |
217 | #endif |
218 | ||
14957cd0 | 219 | #if USE(JSVALUE64) |
93a37866 | 220 | Jump emitJumpIfNotJSCell(RegisterID); |
4e4e5a6f A |
221 | Jump emitJumpIfImmediateNumber(RegisterID reg); |
222 | Jump emitJumpIfNotImmediateNumber(RegisterID reg); | |
223 | void emitFastArithImmToInt(RegisterID reg); | |
93a37866 | 224 | void emitFastArithIntToImmNoCheck(RegisterID src, RegisterID dest); |
4e4e5a6f A |
225 | #endif |
226 | ||
93a37866 A |
227 | Jump emitJumpIfNotType(RegisterID baseReg, RegisterID scratchReg, JSType); |
228 | ||
229 | void emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry, RegisterID to, RegisterID from = callFrameRegister); | |
230 | void emitPutToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry); | |
231 | void emitPutImmediateToCallFrameHeader(void* value, JSStack::CallFrameHeaderEntry); | |
232 | void emitPutCellToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry); | |
233 | ||
234 | void preserveReturnAddressAfterCall(RegisterID); | |
235 | void restoreReturnAddressBeforeReturn(RegisterID); | |
236 | void restoreReturnAddressBeforeReturn(Address); | |
237 | void restoreArgumentReference(); | |
238 | ||
14957cd0 A |
239 | inline Address payloadFor(int index, RegisterID base = callFrameRegister); |
240 | inline Address intPayloadFor(int index, RegisterID base = callFrameRegister); | |
241 | inline Address intTagFor(int index, RegisterID base = callFrameRegister); | |
242 | inline Address addressFor(int index, RegisterID base = callFrameRegister); | |
4e4e5a6f A |
243 | }; |
244 | ||
245 | struct ThunkHelpers { | |
4e4e5a6f A |
246 | static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString, m_length); } |
247 | static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString, m_value); } | |
248 | }; | |
249 | ||
250 | #if USE(JSVALUE32_64) | |
251 | inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload) | |
252 | { | |
253 | loadPtr(payloadFor(virtualRegisterIndex), payload); | |
254 | return emitJumpIfNotJSCell(virtualRegisterIndex); | |
255 | } | |
256 | ||
257 | inline JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex) | |
258 | { | |
259 | ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex); | |
14957cd0 | 260 | return branch32(NotEqual, tagFor(virtualRegisterIndex), TrustedImm32(JSValue::CellTag)); |
4e4e5a6f A |
261 | } |
262 | ||
263 | inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst) | |
264 | { | |
265 | ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex); | |
266 | loadPtr(payloadFor(virtualRegisterIndex), dst); | |
14957cd0 | 267 | return branch32(NotEqual, tagFor(static_cast<int>(virtualRegisterIndex)), TrustedImm32(JSValue::Int32Tag)); |
4e4e5a6f A |
268 | } |
269 | ||
14957cd0 | 270 | inline JSInterfaceJIT::Address JSInterfaceJIT::tagFor(int virtualRegisterIndex, RegisterID base) |
4e4e5a6f | 271 | { |
14957cd0 A |
272 | ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex); |
273 | return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); | |
4e4e5a6f A |
274 | } |
275 | ||
14957cd0 | 276 | inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base) |
4e4e5a6f | 277 | { |
14957cd0 A |
278 | ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex); |
279 | return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); | |
280 | } | |
281 | ||
282 | inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base) | |
283 | { | |
284 | return payloadFor(virtualRegisterIndex, base); | |
285 | } | |
286 | ||
287 | inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base) | |
288 | { | |
289 | return tagFor(virtualRegisterIndex, base); | |
4e4e5a6f A |
290 | } |
291 | ||
292 | inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch) | |
293 | { | |
294 | ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex); | |
295 | loadPtr(tagFor(virtualRegisterIndex), scratch); | |
14957cd0 A |
296 | Jump isDouble = branch32(Below, scratch, TrustedImm32(JSValue::LowestTag)); |
297 | Jump notInt = branch32(NotEqual, scratch, TrustedImm32(JSValue::Int32Tag)); | |
4e4e5a6f A |
298 | loadPtr(payloadFor(virtualRegisterIndex), scratch); |
299 | convertInt32ToDouble(scratch, dst); | |
300 | Jump done = jump(); | |
301 | isDouble.link(this); | |
302 | loadDouble(addressFor(virtualRegisterIndex), dst); | |
303 | done.link(this); | |
304 | return notInt; | |
6fe7ccc8 A |
305 | } |
306 | ||
4e4e5a6f A |
307 | #endif |
308 | ||
309 | #if USE(JSVALUE64) | |
93a37866 A |
310 | ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotJSCell(RegisterID reg) |
311 | { | |
312 | return branchTest64(NonZero, reg, tagMaskRegister); | |
313 | } | |
314 | ||
4e4e5a6f A |
315 | ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg) |
316 | { | |
93a37866 | 317 | return branchTest64(NonZero, reg, tagTypeNumberRegister); |
4e4e5a6f A |
318 | } |
319 | ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg) | |
320 | { | |
93a37866 | 321 | return branchTest64(Zero, reg, tagTypeNumberRegister); |
4e4e5a6f A |
322 | } |
323 | inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID dst) | |
324 | { | |
93a37866 A |
325 | load64(addressFor(virtualRegisterIndex), dst); |
326 | return branchTest64(NonZero, dst, tagMaskRegister); | |
4e4e5a6f A |
327 | } |
328 | ||
329 | inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst) | |
330 | { | |
93a37866 A |
331 | load64(addressFor(virtualRegisterIndex), dst); |
332 | Jump result = branch64(Below, dst, tagTypeNumberRegister); | |
4e4e5a6f A |
333 | zeroExtend32ToPtr(dst, dst); |
334 | return result; | |
335 | } | |
336 | ||
337 | inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch) | |
338 | { | |
93a37866 | 339 | load64(addressFor(virtualRegisterIndex), scratch); |
4e4e5a6f | 340 | Jump notNumber = emitJumpIfNotImmediateNumber(scratch); |
93a37866 | 341 | Jump notInt = branch64(Below, scratch, tagTypeNumberRegister); |
4e4e5a6f A |
342 | convertInt32ToDouble(scratch, dst); |
343 | Jump done = jump(); | |
344 | notInt.link(this); | |
93a37866 A |
345 | add64(tagTypeNumberRegister, scratch); |
346 | move64ToDouble(scratch, dst); | |
4e4e5a6f A |
347 | done.link(this); |
348 | return notNumber; | |
349 | } | |
6fe7ccc8 | 350 | |
4e4e5a6f A |
351 | ALWAYS_INLINE void JSInterfaceJIT::emitFastArithImmToInt(RegisterID) |
352 | { | |
353 | } | |
354 | ||
93a37866 A |
355 | // operand is int32_t, must have been zero-extended if register is 64-bit. |
356 | ALWAYS_INLINE void JSInterfaceJIT::emitFastArithIntToImmNoCheck(RegisterID src, RegisterID dest) | |
357 | { | |
358 | if (src != dest) | |
359 | move(src, dest); | |
360 | or64(tagTypeNumberRegister, dest); | |
361 | } | |
4e4e5a6f A |
362 | #endif |
363 | ||
14957cd0 A |
364 | #if USE(JSVALUE64) |
365 | inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base) | |
4e4e5a6f | 366 | { |
14957cd0 A |
367 | ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex); |
368 | return addressFor(virtualRegisterIndex, base); | |
4e4e5a6f A |
369 | } |
370 | ||
14957cd0 | 371 | inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base) |
4e4e5a6f | 372 | { |
14957cd0 A |
373 | ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex); |
374 | return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); | |
4e4e5a6f | 375 | } |
14957cd0 | 376 | inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base) |
4e4e5a6f | 377 | { |
14957cd0 A |
378 | ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex); |
379 | return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); | |
4e4e5a6f A |
380 | } |
381 | #endif | |
382 | ||
93a37866 A |
383 | ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotType(RegisterID baseReg, RegisterID scratchReg, JSType type) |
384 | { | |
385 | loadPtr(Address(baseReg, JSCell::structureOffset()), scratchReg); | |
386 | return branch8(NotEqual, Address(scratchReg, Structure::typeInfoTypeOffset()), TrustedImm32(type)); | |
387 | } | |
388 | ||
389 | ALWAYS_INLINE void JSInterfaceJIT::emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry, RegisterID to, RegisterID from) | |
390 | { | |
391 | loadPtr(Address(from, entry * sizeof(Register)), to); | |
392 | } | |
393 | ||
394 | ALWAYS_INLINE void JSInterfaceJIT::emitPutToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry) | |
395 | { | |
396 | #if USE(JSVALUE32_64) | |
397 | storePtr(from, payloadFor(entry, callFrameRegister)); | |
398 | #else | |
399 | store64(from, addressFor(entry, callFrameRegister)); | |
400 | #endif | |
401 | } | |
402 | ||
403 | ALWAYS_INLINE void JSInterfaceJIT::emitPutImmediateToCallFrameHeader(void* value, JSStack::CallFrameHeaderEntry entry) | |
404 | { | |
405 | storePtr(TrustedImmPtr(value), Address(callFrameRegister, entry * sizeof(Register))); | |
406 | } | |
407 | ||
408 | ALWAYS_INLINE void JSInterfaceJIT::emitPutCellToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry) | |
409 | { | |
410 | #if USE(JSVALUE32_64) | |
411 | store32(TrustedImm32(JSValue::CellTag), tagFor(entry, callFrameRegister)); | |
412 | store32(from, payloadFor(entry, callFrameRegister)); | |
413 | #else | |
414 | store64(from, addressFor(entry, callFrameRegister)); | |
415 | #endif | |
416 | } | |
417 | ||
14957cd0 | 418 | inline JSInterfaceJIT::Address JSInterfaceJIT::addressFor(int virtualRegisterIndex, RegisterID base) |
4e4e5a6f | 419 | { |
14957cd0 A |
420 | ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex); |
421 | return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register))); | |
4e4e5a6f A |
422 | } |
423 | ||
93a37866 A |
424 | #if CPU(ARM) || CPU(ARM64) |
425 | ||
426 | ALWAYS_INLINE void JSInterfaceJIT::preserveReturnAddressAfterCall(RegisterID reg) | |
427 | { | |
428 | move(linkRegister, reg); | |
429 | } | |
430 | ||
431 | ALWAYS_INLINE void JSInterfaceJIT::restoreReturnAddressBeforeReturn(RegisterID reg) | |
432 | { | |
433 | move(reg, linkRegister); | |
434 | } | |
435 | ||
436 | ALWAYS_INLINE void JSInterfaceJIT::restoreReturnAddressBeforeReturn(Address address) | |
437 | { | |
438 | loadPtr(address, linkRegister); | |
439 | } | |
440 | #elif CPU(SH4) | |
441 | ||
442 | ALWAYS_INLINE void JSInterfaceJIT::preserveReturnAddressAfterCall(RegisterID reg) | |
443 | { | |
444 | m_assembler.stspr(reg); | |
445 | } | |
446 | ||
447 | ALWAYS_INLINE void JSInterfaceJIT::restoreReturnAddressBeforeReturn(RegisterID reg) | |
448 | { | |
449 | m_assembler.ldspr(reg); | |
450 | } | |
451 | ||
452 | ALWAYS_INLINE void JSInterfaceJIT::restoreReturnAddressBeforeReturn(Address address) | |
453 | { | |
454 | loadPtrLinkReg(address); | |
455 | } | |
456 | ||
457 | #elif CPU(MIPS) | |
458 | ||
459 | ALWAYS_INLINE void JSInterfaceJIT::preserveReturnAddressAfterCall(RegisterID reg) | |
460 | { | |
461 | move(returnAddressRegister, reg); | |
462 | } | |
463 | ||
464 | ALWAYS_INLINE void JSInterfaceJIT::restoreReturnAddressBeforeReturn(RegisterID reg) | |
465 | { | |
466 | move(reg, returnAddressRegister); | |
467 | } | |
468 | ||
469 | ALWAYS_INLINE void JSInterfaceJIT::restoreReturnAddressBeforeReturn(Address address) | |
470 | { | |
471 | loadPtr(address, returnAddressRegister); | |
472 | } | |
473 | ||
474 | #else // CPU(X86) || CPU(X86_64) | |
475 | ||
476 | ALWAYS_INLINE void JSInterfaceJIT::preserveReturnAddressAfterCall(RegisterID reg) | |
477 | { | |
478 | pop(reg); | |
479 | } | |
480 | ||
481 | ALWAYS_INLINE void JSInterfaceJIT::restoreReturnAddressBeforeReturn(RegisterID reg) | |
482 | { | |
483 | push(reg); | |
484 | } | |
485 | ||
486 | ALWAYS_INLINE void JSInterfaceJIT::restoreReturnAddressBeforeReturn(Address address) | |
487 | { | |
488 | push(address); | |
489 | } | |
490 | ||
491 | #endif | |
492 | ||
493 | ALWAYS_INLINE void JSInterfaceJIT::restoreArgumentReference() | |
494 | { | |
495 | move(stackPointerRegister, firstArgumentRegister); | |
496 | poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); | |
497 | } | |
498 | ||
499 | } // namespace JSC | |
500 | ||
501 | #endif // ENABLE(JIT) | |
4e4e5a6f A |
502 | |
503 | #endif // JSInterfaceJIT_h |