2 * Copyright (C) 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #ifndef JSInterfaceJIT_h
27 #define JSInterfaceJIT_h
29 #include "BytecodeConventions.h"
32 #include "JSCJSValue.h"
35 #include "MacroAssembler.h"
36 #include <wtf/Vector.h>
41 class JSInterfaceJIT
: public MacroAssembler
{
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.
50 // regT3 is required to be callee-preserved.
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.
57 static const RegisterID returnValueRegister
= X86Registers::eax
;
58 static const RegisterID cachedResultRegister
= X86Registers::eax
;
60 static const RegisterID firstArgumentRegister
= X86Registers::edi
;
62 static const RegisterID firstArgumentRegister
= X86Registers::ecx
;
65 #if ENABLE(VALUE_PROFILER)
66 static const RegisterID bucketCounterRegister
= X86Registers::r10
;
69 static const RegisterID callFrameRegister
= X86Registers::r13
;
70 static const RegisterID tagTypeNumberRegister
= X86Registers::r14
;
71 static const RegisterID tagMaskRegister
= X86Registers::r15
;
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
;
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
;
83 static const RegisterID nonArgGPR1
= X86Registers::eax
; // regT0
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
;
91 static const RegisterID bucketCounterRegister
= X86Registers::esi
;
92 static const RegisterID callFrameRegister
= X86Registers::edi
;
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
;
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
;
104 static const RegisterID returnValueRegister
= ARMRegisters::r0
;
105 static const RegisterID cachedResultRegister
= ARMRegisters::r0
;
106 static const RegisterID firstArgumentRegister
= ARMRegisters::r0
;
108 #if ENABLE(VALUE_PROFILER)
109 static const RegisterID bucketCounterRegister
= ARMRegisters::r7
;
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
;
117 // Update ctiTrampoline in JITStubs.cpp if these values are changed!
118 static const RegisterID callFrameRegister
= ARMRegisters::r5
;
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
;
125 static const RegisterID returnValueRegister
= ARM64Registers::x0
;
126 static const RegisterID cachedResultRegister
= ARM64Registers::x0
;
127 static const RegisterID firstArgumentRegister
= ARM64Registers::x0
;
129 #if ENABLE(VALUE_PROFILER)
130 static const RegisterID bucketCounterRegister
= ARM64Registers::x7
;
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
;
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
;
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
;
148 static const RegisterID nonArgGPR1
= ARM64Registers::x9
;
150 static const RegisterID returnValueRegister
= MIPSRegisters::v0
;
151 static const RegisterID cachedResultRegister
= MIPSRegisters::v0
;
152 static const RegisterID firstArgumentRegister
= MIPSRegisters::a0
;
154 #if ENABLE(VALUE_PROFILER)
155 static const RegisterID bucketCounterRegister
= MIPSRegisters::s3
;
158 // regT0 must be v0 for returning a 32-bit value.
159 static const RegisterID regT0
= MIPSRegisters::v0
;
161 // regT1 must be v1 for returning a pair of 32-bit value.
162 static const RegisterID regT1
= MIPSRegisters::v1
;
164 static const RegisterID regT2
= MIPSRegisters::t4
;
166 // regT3 must be saved in the callee, so use an S register.
167 static const RegisterID regT3
= MIPSRegisters::s2
;
169 static const RegisterID callFrameRegister
= MIPSRegisters::s0
;
171 static const FPRegisterID fpRegT0
= MIPSRegisters::f4
;
172 static const FPRegisterID fpRegT1
= MIPSRegisters::f6
;
173 static const FPRegisterID fpRegT2
= MIPSRegisters::f8
;
174 static const FPRegisterID fpRegT3
= MIPSRegisters::f10
;
176 static const RegisterID callFrameRegister
= SH4Registers::fp
;
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
;
188 static const RegisterID returnValueRegister
= SH4Registers::r0
;
189 static const RegisterID cachedResultRegister
= SH4Registers::r0
;
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
;
200 #error "JIT not supported on this platform."
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
);
208 static const unsigned Int32Tag
= TagTypeNumber
>> 32;
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
);
214 #if USE(JSVALUE32_64)
215 inline Jump
emitJumpIfNotJSCell(unsigned virtualRegisterIndex
);
216 inline Address
tagFor(int index
, RegisterID base
= callFrameRegister
);
220 Jump
emitJumpIfNotJSCell(RegisterID
);
221 Jump
emitJumpIfImmediateNumber(RegisterID reg
);
222 Jump
emitJumpIfNotImmediateNumber(RegisterID reg
);
223 void emitFastArithImmToInt(RegisterID reg
);
224 void emitFastArithIntToImmNoCheck(RegisterID src
, RegisterID dest
);
227 Jump
emitJumpIfNotType(RegisterID baseReg
, RegisterID scratchReg
, JSType
);
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
);
234 void preserveReturnAddressAfterCall(RegisterID
);
235 void restoreReturnAddressBeforeReturn(RegisterID
);
236 void restoreReturnAddressBeforeReturn(Address
);
237 void restoreArgumentReference();
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
);
245 struct ThunkHelpers
{
246 static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString
, m_length
); }
247 static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString
, m_value
); }
250 #if USE(JSVALUE32_64)
251 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID payload
)
253 loadPtr(payloadFor(virtualRegisterIndex
), payload
);
254 return emitJumpIfNotJSCell(virtualRegisterIndex
);
257 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex
)
259 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
260 return branch32(NotEqual
, tagFor(virtualRegisterIndex
), TrustedImm32(JSValue::CellTag
));
263 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
265 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
266 loadPtr(payloadFor(virtualRegisterIndex
), dst
);
267 return branch32(NotEqual
, tagFor(static_cast<int>(virtualRegisterIndex
)), TrustedImm32(JSValue::Int32Tag
));
270 inline JSInterfaceJIT::Address
JSInterfaceJIT::tagFor(int virtualRegisterIndex
, RegisterID base
)
272 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
273 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
));
276 inline JSInterfaceJIT::Address
JSInterfaceJIT::payloadFor(int virtualRegisterIndex
, RegisterID base
)
278 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
279 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
));
282 inline JSInterfaceJIT::Address
JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex
, RegisterID base
)
284 return payloadFor(virtualRegisterIndex
, base
);
287 inline JSInterfaceJIT::Address
JSInterfaceJIT::intTagFor(int virtualRegisterIndex
, RegisterID base
)
289 return tagFor(virtualRegisterIndex
, base
);
292 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
)
294 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
295 loadPtr(tagFor(virtualRegisterIndex
), scratch
);
296 Jump isDouble
= branch32(Below
, scratch
, TrustedImm32(JSValue::LowestTag
));
297 Jump notInt
= branch32(NotEqual
, scratch
, TrustedImm32(JSValue::Int32Tag
));
298 loadPtr(payloadFor(virtualRegisterIndex
), scratch
);
299 convertInt32ToDouble(scratch
, dst
);
302 loadDouble(addressFor(virtualRegisterIndex
), dst
);
310 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotJSCell(RegisterID reg
)
312 return branchTest64(NonZero
, reg
, tagMaskRegister
);
315 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg
)
317 return branchTest64(NonZero
, reg
, tagTypeNumberRegister
);
319 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg
)
321 return branchTest64(Zero
, reg
, tagTypeNumberRegister
);
323 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID dst
)
325 load64(addressFor(virtualRegisterIndex
), dst
);
326 return branchTest64(NonZero
, dst
, tagMaskRegister
);
329 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
331 load64(addressFor(virtualRegisterIndex
), dst
);
332 Jump result
= branch64(Below
, dst
, tagTypeNumberRegister
);
333 zeroExtend32ToPtr(dst
, dst
);
337 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
)
339 load64(addressFor(virtualRegisterIndex
), scratch
);
340 Jump notNumber
= emitJumpIfNotImmediateNumber(scratch
);
341 Jump notInt
= branch64(Below
, scratch
, tagTypeNumberRegister
);
342 convertInt32ToDouble(scratch
, dst
);
345 add64(tagTypeNumberRegister
, scratch
);
346 move64ToDouble(scratch
, dst
);
351 ALWAYS_INLINE
void JSInterfaceJIT::emitFastArithImmToInt(RegisterID
)
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
)
360 or64(tagTypeNumberRegister
, dest
);
365 inline JSInterfaceJIT::Address
JSInterfaceJIT::payloadFor(int virtualRegisterIndex
, RegisterID base
)
367 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
368 return addressFor(virtualRegisterIndex
, base
);
371 inline JSInterfaceJIT::Address
JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex
, RegisterID base
)
373 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
374 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
));
376 inline JSInterfaceJIT::Address
JSInterfaceJIT::intTagFor(int virtualRegisterIndex
, RegisterID base
)
378 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
379 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
));
383 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotType(RegisterID baseReg
, RegisterID scratchReg
, JSType type
)
385 loadPtr(Address(baseReg
, JSCell::structureOffset()), scratchReg
);
386 return branch8(NotEqual
, Address(scratchReg
, Structure::typeInfoTypeOffset()), TrustedImm32(type
));
389 ALWAYS_INLINE
void JSInterfaceJIT::emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry
, RegisterID to
, RegisterID from
)
391 loadPtr(Address(from
, entry
* sizeof(Register
)), to
);
394 ALWAYS_INLINE
void JSInterfaceJIT::emitPutToCallFrameHeader(RegisterID from
, JSStack::CallFrameHeaderEntry entry
)
396 #if USE(JSVALUE32_64)
397 storePtr(from
, payloadFor(entry
, callFrameRegister
));
399 store64(from
, addressFor(entry
, callFrameRegister
));
403 ALWAYS_INLINE
void JSInterfaceJIT::emitPutImmediateToCallFrameHeader(void* value
, JSStack::CallFrameHeaderEntry entry
)
405 storePtr(TrustedImmPtr(value
), Address(callFrameRegister
, entry
* sizeof(Register
)));
408 ALWAYS_INLINE
void JSInterfaceJIT::emitPutCellToCallFrameHeader(RegisterID from
, JSStack::CallFrameHeaderEntry entry
)
410 #if USE(JSVALUE32_64)
411 store32(TrustedImm32(JSValue::CellTag
), tagFor(entry
, callFrameRegister
));
412 store32(from
, payloadFor(entry
, callFrameRegister
));
414 store64(from
, addressFor(entry
, callFrameRegister
));
418 inline JSInterfaceJIT::Address
JSInterfaceJIT::addressFor(int virtualRegisterIndex
, RegisterID base
)
420 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
421 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)));
424 #if CPU(ARM) || CPU(ARM64)
426 ALWAYS_INLINE
void JSInterfaceJIT::preserveReturnAddressAfterCall(RegisterID reg
)
428 move(linkRegister
, reg
);
431 ALWAYS_INLINE
void JSInterfaceJIT::restoreReturnAddressBeforeReturn(RegisterID reg
)
433 move(reg
, linkRegister
);
436 ALWAYS_INLINE
void JSInterfaceJIT::restoreReturnAddressBeforeReturn(Address address
)
438 loadPtr(address
, linkRegister
);
442 ALWAYS_INLINE
void JSInterfaceJIT::preserveReturnAddressAfterCall(RegisterID reg
)
444 m_assembler
.stspr(reg
);
447 ALWAYS_INLINE
void JSInterfaceJIT::restoreReturnAddressBeforeReturn(RegisterID reg
)
449 m_assembler
.ldspr(reg
);
452 ALWAYS_INLINE
void JSInterfaceJIT::restoreReturnAddressBeforeReturn(Address address
)
454 loadPtrLinkReg(address
);
459 ALWAYS_INLINE
void JSInterfaceJIT::preserveReturnAddressAfterCall(RegisterID reg
)
461 move(returnAddressRegister
, reg
);
464 ALWAYS_INLINE
void JSInterfaceJIT::restoreReturnAddressBeforeReturn(RegisterID reg
)
466 move(reg
, returnAddressRegister
);
469 ALWAYS_INLINE
void JSInterfaceJIT::restoreReturnAddressBeforeReturn(Address address
)
471 loadPtr(address
, returnAddressRegister
);
474 #else // CPU(X86) || CPU(X86_64)
476 ALWAYS_INLINE
void JSInterfaceJIT::preserveReturnAddressAfterCall(RegisterID reg
)
481 ALWAYS_INLINE
void JSInterfaceJIT::restoreReturnAddressBeforeReturn(RegisterID reg
)
486 ALWAYS_INLINE
void JSInterfaceJIT::restoreReturnAddressBeforeReturn(Address address
)
493 ALWAYS_INLINE
void JSInterfaceJIT::restoreArgumentReference()
495 move(stackPointerRegister
, firstArgumentRegister
);
496 poke(callFrameRegister
, OBJECT_OFFSETOF(struct JITStackFrame
, callFrame
) / sizeof(void*));
501 #endif // ENABLE(JIT)
503 #endif // JSInterfaceJIT_h