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
32 #include "MacroAssembler.h"
33 #include "RegisterFile.h"
34 #include <wtf/AlwaysInline.h>
35 #include <wtf/Vector.h>
38 class JSInterfaceJIT
: public MacroAssembler
{
42 // regT0 has two special meanings. The return value from a stub
43 // call will always be in regT0, and by default (unless
44 // a register is specified) emitPutVirtualRegister() will store
45 // the value from regT0.
47 // regT3 is required to be callee-preserved.
49 // tempRegister2 is has no such dependencies. It is important that
50 // on x86/x86-64 it is ecx for performance reasons, since the
51 // MacroAssembler will need to plant register swaps if it is not -
52 // however the code will still function correctly.
54 static const RegisterID returnValueRegister
= X86Registers::eax
;
55 static const RegisterID cachedResultRegister
= X86Registers::eax
;
56 static const RegisterID firstArgumentRegister
= X86Registers::edi
;
58 static const RegisterID timeoutCheckRegister
= X86Registers::r12
;
59 static const RegisterID callFrameRegister
= X86Registers::r13
;
60 static const RegisterID tagTypeNumberRegister
= X86Registers::r14
;
61 static const RegisterID tagMaskRegister
= X86Registers::r15
;
63 static const RegisterID regT0
= X86Registers::eax
;
64 static const RegisterID regT1
= X86Registers::edx
;
65 static const RegisterID regT2
= X86Registers::ecx
;
66 static const RegisterID regT3
= X86Registers::ebx
;
68 static const FPRegisterID fpRegT0
= X86Registers::xmm0
;
69 static const FPRegisterID fpRegT1
= X86Registers::xmm1
;
70 static const FPRegisterID fpRegT2
= X86Registers::xmm2
;
71 static const FPRegisterID fpRegT3
= X86Registers::xmm3
;
73 static const RegisterID returnValueRegister
= X86Registers::eax
;
74 static const RegisterID cachedResultRegister
= X86Registers::eax
;
75 // On x86 we always use fastcall conventions = but on
76 // OS X if might make more sense to just use regparm.
77 static const RegisterID firstArgumentRegister
= X86Registers::ecx
;
79 static const RegisterID timeoutCheckRegister
= X86Registers::esi
;
80 static const RegisterID callFrameRegister
= X86Registers::edi
;
82 static const RegisterID regT0
= X86Registers::eax
;
83 static const RegisterID regT1
= X86Registers::edx
;
84 static const RegisterID regT2
= X86Registers::ecx
;
85 static const RegisterID regT3
= X86Registers::ebx
;
87 static const FPRegisterID fpRegT0
= X86Registers::xmm0
;
88 static const FPRegisterID fpRegT1
= X86Registers::xmm1
;
89 static const FPRegisterID fpRegT2
= X86Registers::xmm2
;
90 static const FPRegisterID fpRegT3
= X86Registers::xmm3
;
92 static const RegisterID returnValueRegister
= ARMRegisters::r0
;
93 static const RegisterID cachedResultRegister
= ARMRegisters::r0
;
94 static const RegisterID firstArgumentRegister
= ARMRegisters::r0
;
96 static const RegisterID regT0
= ARMRegisters::r0
;
97 static const RegisterID regT1
= ARMRegisters::r1
;
98 static const RegisterID regT2
= ARMRegisters::r2
;
99 static const RegisterID regT3
= ARMRegisters::r4
;
101 static const RegisterID callFrameRegister
= ARMRegisters::r5
;
102 static const RegisterID timeoutCheckRegister
= ARMRegisters::r6
;
104 static const FPRegisterID fpRegT0
= ARMRegisters::d0
;
105 static const FPRegisterID fpRegT1
= ARMRegisters::d1
;
106 static const FPRegisterID fpRegT2
= ARMRegisters::d2
;
107 static const FPRegisterID fpRegT3
= ARMRegisters::d3
;
108 #elif CPU(ARM_TRADITIONAL)
109 static const RegisterID returnValueRegister
= ARMRegisters::r0
;
110 static const RegisterID cachedResultRegister
= ARMRegisters::r0
;
111 static const RegisterID firstArgumentRegister
= ARMRegisters::r0
;
113 static const RegisterID timeoutCheckRegister
= ARMRegisters::r5
;
114 static const RegisterID callFrameRegister
= ARMRegisters::r4
;
116 static const RegisterID regT0
= ARMRegisters::r0
;
117 static const RegisterID regT1
= ARMRegisters::r1
;
118 static const RegisterID regT2
= ARMRegisters::r2
;
120 static const RegisterID regT3
= ARMRegisters::r7
;
122 static const RegisterID regS0
= ARMRegisters::S0
;
124 static const RegisterID regS1
= ARMRegisters::S1
;
126 static const RegisterID regStackPtr
= ARMRegisters::sp
;
127 static const RegisterID regLink
= ARMRegisters::lr
;
129 static const FPRegisterID fpRegT0
= ARMRegisters::d0
;
130 static const FPRegisterID fpRegT1
= ARMRegisters::d1
;
131 static const FPRegisterID fpRegT2
= ARMRegisters::d2
;
132 static const FPRegisterID fpRegT3
= ARMRegisters::d3
;
134 static const RegisterID returnValueRegister
= MIPSRegisters::v0
;
135 static const RegisterID cachedResultRegister
= MIPSRegisters::v0
;
136 static const RegisterID firstArgumentRegister
= MIPSRegisters::a0
;
138 // regT0 must be v0 for returning a 32-bit value.
139 static const RegisterID regT0
= MIPSRegisters::v0
;
141 // regT1 must be v1 for returning a pair of 32-bit value.
142 static const RegisterID regT1
= MIPSRegisters::v1
;
144 static const RegisterID regT2
= MIPSRegisters::t4
;
146 // regT3 must be saved in the callee, so use an S register.
147 static const RegisterID regT3
= MIPSRegisters::s2
;
149 static const RegisterID callFrameRegister
= MIPSRegisters::s0
;
150 static const RegisterID timeoutCheckRegister
= MIPSRegisters::s1
;
152 static const FPRegisterID fpRegT0
= MIPSRegisters::f4
;
153 static const FPRegisterID fpRegT1
= MIPSRegisters::f6
;
154 static const FPRegisterID fpRegT2
= MIPSRegisters::f8
;
155 static const FPRegisterID fpRegT3
= MIPSRegisters::f10
;
157 static const RegisterID timeoutCheckRegister
= SH4Registers::r8
;
158 static const RegisterID callFrameRegister
= SH4Registers::fp
;
160 static const RegisterID regT0
= SH4Registers::r0
;
161 static const RegisterID regT1
= SH4Registers::r1
;
162 static const RegisterID regT2
= SH4Registers::r2
;
163 static const RegisterID regT3
= SH4Registers::r10
;
164 static const RegisterID regT4
= SH4Registers::r4
;
165 static const RegisterID regT5
= SH4Registers::r5
;
166 static const RegisterID regT6
= SH4Registers::r6
;
167 static const RegisterID regT7
= SH4Registers::r7
;
168 static const RegisterID firstArgumentRegister
=regT4
;
170 static const RegisterID returnValueRegister
= SH4Registers::r0
;
171 static const RegisterID cachedResultRegister
= SH4Registers::r0
;
173 static const FPRegisterID fpRegT0
= SH4Registers::fr0
;
174 static const FPRegisterID fpRegT1
= SH4Registers::fr2
;
175 static const FPRegisterID fpRegT2
= SH4Registers::fr4
;
176 static const FPRegisterID fpRegT3
= SH4Registers::fr6
;
177 static const FPRegisterID fpRegT4
= SH4Registers::fr8
;
178 static const FPRegisterID fpRegT5
= SH4Registers::fr10
;
179 static const FPRegisterID fpRegT6
= SH4Registers::fr12
;
180 static const FPRegisterID fpRegT7
= SH4Registers::fr14
;
182 #error "JIT not supported on this platform."
185 #if USE(JSVALUE32_64)
186 // Can't just propogate JSValue::Int32Tag as visual studio doesn't like it
187 static const unsigned Int32Tag
= 0xffffffff;
188 COMPILE_ASSERT(Int32Tag
== JSValue::Int32Tag
, Int32Tag_out_of_sync
);
190 static const unsigned Int32Tag
= TagTypeNumber
>> 32;
192 inline Jump
emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID payload
);
193 inline Jump
emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
);
194 inline Jump
emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
);
196 inline void storePtrWithWriteBarrier(TrustedImmPtr ptr
, RegisterID
/* owner */, Address dest
)
201 #if USE(JSVALUE32_64)
202 inline Jump
emitJumpIfNotJSCell(unsigned virtualRegisterIndex
);
203 inline Address
tagFor(int index
, RegisterID base
= callFrameRegister
);
207 Jump
emitJumpIfImmediateNumber(RegisterID reg
);
208 Jump
emitJumpIfNotImmediateNumber(RegisterID reg
);
209 void emitFastArithImmToInt(RegisterID reg
);
212 inline Address
payloadFor(int index
, RegisterID base
= callFrameRegister
);
213 inline Address
intPayloadFor(int index
, RegisterID base
= callFrameRegister
);
214 inline Address
intTagFor(int index
, RegisterID base
= callFrameRegister
);
215 inline Address
addressFor(int index
, RegisterID base
= callFrameRegister
);
218 struct ThunkHelpers
{
219 static unsigned stringImplDataOffset() { return StringImpl::dataOffset(); }
220 static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString
, m_length
); }
221 static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString
, m_value
); }
224 #if USE(JSVALUE32_64)
225 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID payload
)
227 loadPtr(payloadFor(virtualRegisterIndex
), payload
);
228 return emitJumpIfNotJSCell(virtualRegisterIndex
);
231 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex
)
233 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
234 return branch32(NotEqual
, tagFor(virtualRegisterIndex
), TrustedImm32(JSValue::CellTag
));
237 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
239 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
240 loadPtr(payloadFor(virtualRegisterIndex
), dst
);
241 return branch32(NotEqual
, tagFor(static_cast<int>(virtualRegisterIndex
)), TrustedImm32(JSValue::Int32Tag
));
244 inline JSInterfaceJIT::Address
JSInterfaceJIT::tagFor(int virtualRegisterIndex
, RegisterID base
)
246 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
247 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
));
250 inline JSInterfaceJIT::Address
JSInterfaceJIT::payloadFor(int virtualRegisterIndex
, RegisterID base
)
252 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
253 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
));
256 inline JSInterfaceJIT::Address
JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex
, RegisterID base
)
258 return payloadFor(virtualRegisterIndex
, base
);
261 inline JSInterfaceJIT::Address
JSInterfaceJIT::intTagFor(int virtualRegisterIndex
, RegisterID base
)
263 return tagFor(virtualRegisterIndex
, base
);
266 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
)
268 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
269 loadPtr(tagFor(virtualRegisterIndex
), scratch
);
270 Jump isDouble
= branch32(Below
, scratch
, TrustedImm32(JSValue::LowestTag
));
271 Jump notInt
= branch32(NotEqual
, scratch
, TrustedImm32(JSValue::Int32Tag
));
272 loadPtr(payloadFor(virtualRegisterIndex
), scratch
);
273 convertInt32ToDouble(scratch
, dst
);
276 loadDouble(addressFor(virtualRegisterIndex
), dst
);
283 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg
)
285 return branchTestPtr(NonZero
, reg
, tagTypeNumberRegister
);
287 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg
)
289 return branchTestPtr(Zero
, reg
, tagTypeNumberRegister
);
291 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID dst
)
293 loadPtr(addressFor(virtualRegisterIndex
), dst
);
294 return branchTestPtr(NonZero
, dst
, tagMaskRegister
);
297 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
299 loadPtr(addressFor(virtualRegisterIndex
), dst
);
300 Jump result
= branchPtr(Below
, dst
, tagTypeNumberRegister
);
301 zeroExtend32ToPtr(dst
, dst
);
305 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
)
307 loadPtr(addressFor(virtualRegisterIndex
), scratch
);
308 Jump notNumber
= emitJumpIfNotImmediateNumber(scratch
);
309 Jump notInt
= branchPtr(Below
, scratch
, tagTypeNumberRegister
);
310 convertInt32ToDouble(scratch
, dst
);
313 addPtr(tagTypeNumberRegister
, scratch
);
314 movePtrToDouble(scratch
, dst
);
319 ALWAYS_INLINE
void JSInterfaceJIT::emitFastArithImmToInt(RegisterID
)
326 inline JSInterfaceJIT::Address
JSInterfaceJIT::payloadFor(int virtualRegisterIndex
, RegisterID base
)
328 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
329 return addressFor(virtualRegisterIndex
, base
);
332 inline JSInterfaceJIT::Address
JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex
, RegisterID base
)
334 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
335 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
));
337 inline JSInterfaceJIT::Address
JSInterfaceJIT::intTagFor(int virtualRegisterIndex
, RegisterID base
)
339 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
340 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
));
344 inline JSInterfaceJIT::Address
JSInterfaceJIT::addressFor(int virtualRegisterIndex
, RegisterID base
)
346 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
347 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)));
352 #endif // JSInterfaceJIT_h