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"
34 #include "MacroAssembler.h"
35 #include "RegisterFile.h"
36 #include <wtf/AlwaysInline.h>
37 #include <wtf/Vector.h>
40 class JSInterfaceJIT
: public MacroAssembler
{
44 // regT0 has two special meanings. The return value from a stub
45 // call will always be in regT0, and by default (unless
46 // a register is specified) emitPutVirtualRegister() will store
47 // the value from regT0.
49 // regT3 is required to be callee-preserved.
51 // tempRegister2 is has no such dependencies. It is important that
52 // on x86/x86-64 it is ecx for performance reasons, since the
53 // MacroAssembler will need to plant register swaps if it is not -
54 // however the code will still function correctly.
56 static const RegisterID returnValueRegister
= X86Registers::eax
;
57 static const RegisterID cachedResultRegister
= X86Registers::eax
;
58 static const RegisterID firstArgumentRegister
= X86Registers::edi
;
60 #if ENABLE(VALUE_PROFILER)
61 static const RegisterID bucketCounterRegister
= X86Registers::r10
;
64 static const RegisterID timeoutCheckRegister
= X86Registers::r12
;
65 static const RegisterID callFrameRegister
= X86Registers::r13
;
66 static const RegisterID tagTypeNumberRegister
= X86Registers::r14
;
67 static const RegisterID tagMaskRegister
= X86Registers::r15
;
69 static const RegisterID regT0
= X86Registers::eax
;
70 static const RegisterID regT1
= X86Registers::edx
;
71 static const RegisterID regT2
= X86Registers::ecx
;
72 static const RegisterID regT3
= X86Registers::ebx
;
74 static const FPRegisterID fpRegT0
= X86Registers::xmm0
;
75 static const FPRegisterID fpRegT1
= X86Registers::xmm1
;
76 static const FPRegisterID fpRegT2
= X86Registers::xmm2
;
77 static const FPRegisterID fpRegT3
= X86Registers::xmm3
;
79 static const RegisterID returnValueRegister
= X86Registers::eax
;
80 static const RegisterID cachedResultRegister
= X86Registers::eax
;
81 // On x86 we always use fastcall conventions = but on
82 // OS X if might make more sense to just use regparm.
83 static const RegisterID firstArgumentRegister
= X86Registers::ecx
;
85 static const RegisterID bucketCounterRegister
= X86Registers::esi
;
86 static const RegisterID callFrameRegister
= X86Registers::edi
;
88 static const RegisterID regT0
= X86Registers::eax
;
89 static const RegisterID regT1
= X86Registers::edx
;
90 static const RegisterID regT2
= X86Registers::ecx
;
91 static const RegisterID regT3
= X86Registers::ebx
;
93 static const FPRegisterID fpRegT0
= X86Registers::xmm0
;
94 static const FPRegisterID fpRegT1
= X86Registers::xmm1
;
95 static const FPRegisterID fpRegT2
= X86Registers::xmm2
;
96 static const FPRegisterID fpRegT3
= X86Registers::xmm3
;
98 static const RegisterID returnValueRegister
= ARMRegisters::r0
;
99 static const RegisterID cachedResultRegister
= ARMRegisters::r0
;
100 static const RegisterID firstArgumentRegister
= ARMRegisters::r0
;
102 #if ENABLE(VALUE_PROFILER)
103 static const RegisterID bucketCounterRegister
= ARMRegisters::r7
;
106 static const RegisterID regT0
= ARMRegisters::r0
;
107 static const RegisterID regT1
= ARMRegisters::r1
;
108 static const RegisterID regT2
= ARMRegisters::r2
;
109 static const RegisterID regT3
= ARMRegisters::r4
;
111 static const RegisterID callFrameRegister
= ARMRegisters::r5
;
112 static const RegisterID timeoutCheckRegister
= ARMRegisters::r6
;
114 static const FPRegisterID fpRegT0
= ARMRegisters::d0
;
115 static const FPRegisterID fpRegT1
= ARMRegisters::d1
;
116 static const FPRegisterID fpRegT2
= ARMRegisters::d2
;
117 static const FPRegisterID fpRegT3
= ARMRegisters::d3
;
118 #elif CPU(ARM_TRADITIONAL)
119 static const RegisterID returnValueRegister
= ARMRegisters::r0
;
120 static const RegisterID cachedResultRegister
= ARMRegisters::r0
;
121 static const RegisterID firstArgumentRegister
= ARMRegisters::r0
;
123 static const RegisterID timeoutCheckRegister
= ARMRegisters::r5
;
124 static const RegisterID callFrameRegister
= ARMRegisters::r4
;
126 static const RegisterID regT0
= ARMRegisters::r0
;
127 static const RegisterID regT1
= ARMRegisters::r1
;
128 static const RegisterID regT2
= ARMRegisters::r2
;
130 static const RegisterID regT3
= ARMRegisters::r7
;
132 static const RegisterID regS0
= ARMRegisters::S0
;
134 static const RegisterID regS1
= ARMRegisters::S1
;
136 static const RegisterID regStackPtr
= ARMRegisters::sp
;
137 static const RegisterID regLink
= ARMRegisters::lr
;
139 static const FPRegisterID fpRegT0
= ARMRegisters::d0
;
140 static const FPRegisterID fpRegT1
= ARMRegisters::d1
;
141 static const FPRegisterID fpRegT2
= ARMRegisters::d2
;
142 static const FPRegisterID fpRegT3
= ARMRegisters::d3
;
144 static const RegisterID returnValueRegister
= MIPSRegisters::v0
;
145 static const RegisterID cachedResultRegister
= MIPSRegisters::v0
;
146 static const RegisterID firstArgumentRegister
= MIPSRegisters::a0
;
148 // regT0 must be v0 for returning a 32-bit value.
149 static const RegisterID regT0
= MIPSRegisters::v0
;
151 // regT1 must be v1 for returning a pair of 32-bit value.
152 static const RegisterID regT1
= MIPSRegisters::v1
;
154 static const RegisterID regT2
= MIPSRegisters::t4
;
156 // regT3 must be saved in the callee, so use an S register.
157 static const RegisterID regT3
= MIPSRegisters::s2
;
159 static const RegisterID callFrameRegister
= MIPSRegisters::s0
;
160 static const RegisterID timeoutCheckRegister
= MIPSRegisters::s1
;
162 static const FPRegisterID fpRegT0
= MIPSRegisters::f4
;
163 static const FPRegisterID fpRegT1
= MIPSRegisters::f6
;
164 static const FPRegisterID fpRegT2
= MIPSRegisters::f8
;
165 static const FPRegisterID fpRegT3
= MIPSRegisters::f10
;
167 static const RegisterID timeoutCheckRegister
= SH4Registers::r8
;
168 static const RegisterID callFrameRegister
= SH4Registers::fp
;
170 static const RegisterID regT0
= SH4Registers::r0
;
171 static const RegisterID regT1
= SH4Registers::r1
;
172 static const RegisterID regT2
= SH4Registers::r2
;
173 static const RegisterID regT3
= SH4Registers::r10
;
174 static const RegisterID regT4
= SH4Registers::r4
;
175 static const RegisterID regT5
= SH4Registers::r5
;
176 static const RegisterID regT6
= SH4Registers::r6
;
177 static const RegisterID regT7
= SH4Registers::r7
;
178 static const RegisterID firstArgumentRegister
=regT4
;
180 static const RegisterID returnValueRegister
= SH4Registers::r0
;
181 static const RegisterID cachedResultRegister
= SH4Registers::r0
;
183 static const FPRegisterID fpRegT0
= SH4Registers::fr0
;
184 static const FPRegisterID fpRegT1
= SH4Registers::fr2
;
185 static const FPRegisterID fpRegT2
= SH4Registers::fr4
;
186 static const FPRegisterID fpRegT3
= SH4Registers::fr6
;
187 static const FPRegisterID fpRegT4
= SH4Registers::fr8
;
188 static const FPRegisterID fpRegT5
= SH4Registers::fr10
;
189 static const FPRegisterID fpRegT6
= SH4Registers::fr12
;
190 static const FPRegisterID fpRegT7
= SH4Registers::fr14
;
192 #error "JIT not supported on this platform."
195 #if USE(JSVALUE32_64)
196 // Can't just propogate JSValue::Int32Tag as visual studio doesn't like it
197 static const unsigned Int32Tag
= 0xffffffff;
198 COMPILE_ASSERT(Int32Tag
== JSValue::Int32Tag
, Int32Tag_out_of_sync
);
200 static const unsigned Int32Tag
= TagTypeNumber
>> 32;
202 inline Jump
emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID payload
);
203 inline Jump
emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
);
204 inline Jump
emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
);
206 #if USE(JSVALUE32_64)
207 inline Jump
emitJumpIfNotJSCell(unsigned virtualRegisterIndex
);
208 inline Address
tagFor(int index
, RegisterID base
= callFrameRegister
);
212 Jump
emitJumpIfImmediateNumber(RegisterID reg
);
213 Jump
emitJumpIfNotImmediateNumber(RegisterID reg
);
214 void emitFastArithImmToInt(RegisterID reg
);
217 inline Address
payloadFor(int index
, RegisterID base
= callFrameRegister
);
218 inline Address
intPayloadFor(int index
, RegisterID base
= callFrameRegister
);
219 inline Address
intTagFor(int index
, RegisterID base
= callFrameRegister
);
220 inline Address
addressFor(int index
, RegisterID base
= callFrameRegister
);
223 struct ThunkHelpers
{
224 static unsigned stringImplFlagsOffset() { return StringImpl::flagsOffset(); }
225 static unsigned stringImpl8BitFlag() { return StringImpl::flagIs8Bit(); }
226 static unsigned stringImplDataOffset() { return StringImpl::dataOffset(); }
227 static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString
, m_length
); }
228 static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString
, m_value
); }
231 #if USE(JSVALUE32_64)
232 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID payload
)
234 loadPtr(payloadFor(virtualRegisterIndex
), payload
);
235 return emitJumpIfNotJSCell(virtualRegisterIndex
);
238 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex
)
240 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
241 return branch32(NotEqual
, tagFor(virtualRegisterIndex
), TrustedImm32(JSValue::CellTag
));
244 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
246 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
247 loadPtr(payloadFor(virtualRegisterIndex
), dst
);
248 return branch32(NotEqual
, tagFor(static_cast<int>(virtualRegisterIndex
)), TrustedImm32(JSValue::Int32Tag
));
251 inline JSInterfaceJIT::Address
JSInterfaceJIT::tagFor(int virtualRegisterIndex
, RegisterID base
)
253 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
254 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
));
257 inline JSInterfaceJIT::Address
JSInterfaceJIT::payloadFor(int virtualRegisterIndex
, RegisterID base
)
259 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
260 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
));
263 inline JSInterfaceJIT::Address
JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex
, RegisterID base
)
265 return payloadFor(virtualRegisterIndex
, base
);
268 inline JSInterfaceJIT::Address
JSInterfaceJIT::intTagFor(int virtualRegisterIndex
, RegisterID base
)
270 return tagFor(virtualRegisterIndex
, base
);
273 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
)
275 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
276 loadPtr(tagFor(virtualRegisterIndex
), scratch
);
277 Jump isDouble
= branch32(Below
, scratch
, TrustedImm32(JSValue::LowestTag
));
278 Jump notInt
= branch32(NotEqual
, scratch
, TrustedImm32(JSValue::Int32Tag
));
279 loadPtr(payloadFor(virtualRegisterIndex
), scratch
);
280 convertInt32ToDouble(scratch
, dst
);
283 loadDouble(addressFor(virtualRegisterIndex
), dst
);
291 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg
)
293 return branchTestPtr(NonZero
, reg
, tagTypeNumberRegister
);
295 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg
)
297 return branchTestPtr(Zero
, reg
, tagTypeNumberRegister
);
299 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID dst
)
301 loadPtr(addressFor(virtualRegisterIndex
), dst
);
302 return branchTestPtr(NonZero
, dst
, tagMaskRegister
);
305 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
307 loadPtr(addressFor(virtualRegisterIndex
), dst
);
308 Jump result
= branchPtr(Below
, dst
, tagTypeNumberRegister
);
309 zeroExtend32ToPtr(dst
, dst
);
313 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
)
315 loadPtr(addressFor(virtualRegisterIndex
), scratch
);
316 Jump notNumber
= emitJumpIfNotImmediateNumber(scratch
);
317 Jump notInt
= branchPtr(Below
, scratch
, tagTypeNumberRegister
);
318 convertInt32ToDouble(scratch
, dst
);
321 addPtr(tagTypeNumberRegister
, scratch
);
322 movePtrToDouble(scratch
, dst
);
327 ALWAYS_INLINE
void JSInterfaceJIT::emitFastArithImmToInt(RegisterID
)
334 inline JSInterfaceJIT::Address
JSInterfaceJIT::payloadFor(int virtualRegisterIndex
, RegisterID base
)
336 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
337 return addressFor(virtualRegisterIndex
, base
);
340 inline JSInterfaceJIT::Address
JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex
, RegisterID base
)
342 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
343 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
));
345 inline JSInterfaceJIT::Address
JSInterfaceJIT::intTagFor(int virtualRegisterIndex
, RegisterID base
)
347 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
348 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
));
352 inline JSInterfaceJIT::Address
JSInterfaceJIT::addressFor(int virtualRegisterIndex
, RegisterID base
)
354 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
355 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)));
360 #endif // JSInterfaceJIT_h