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
31 #include "JSImmediate.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 fpRegT2
= MIPSRegisters::f10
;
157 #error "JIT not supported on this platform."
160 inline Jump
emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID payload
);
161 inline Jump
emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
);
162 inline Jump
emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
);
164 #if USE(JSVALUE32_64)
165 inline Jump
emitJumpIfNotJSCell(unsigned virtualRegisterIndex
);
166 inline Address
tagFor(unsigned index
, RegisterID base
= callFrameRegister
);
169 #if USE(JSVALUE32) || USE(JSVALUE64)
170 Jump
emitJumpIfImmediateNumber(RegisterID reg
);
171 Jump
emitJumpIfNotImmediateNumber(RegisterID reg
);
172 void emitFastArithImmToInt(RegisterID reg
);
175 inline Address
payloadFor(unsigned index
, RegisterID base
= callFrameRegister
);
176 inline Address
addressFor(unsigned index
, RegisterID base
= callFrameRegister
);
179 struct ThunkHelpers
{
180 static unsigned stringImplDataOffset() { return WebCore::StringImpl::dataOffset(); }
181 static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString
, m_length
); }
182 static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString
, m_value
); }
185 #if USE(JSVALUE32_64)
186 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID payload
)
188 loadPtr(payloadFor(virtualRegisterIndex
), payload
);
189 return emitJumpIfNotJSCell(virtualRegisterIndex
);
192 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex
)
194 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
195 return branch32(NotEqual
, tagFor(virtualRegisterIndex
), Imm32(JSValue::CellTag
));
198 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
200 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
201 loadPtr(payloadFor(virtualRegisterIndex
), dst
);
202 return branch32(NotEqual
, tagFor(virtualRegisterIndex
), Imm32(JSValue::Int32Tag
));
205 inline JSInterfaceJIT::Address
JSInterfaceJIT::tagFor(unsigned virtualRegisterIndex
, RegisterID base
)
207 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
208 return Address(base
, (virtualRegisterIndex
* sizeof(Register
)) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
));
211 inline JSInterfaceJIT::Address
JSInterfaceJIT::payloadFor(unsigned virtualRegisterIndex
, RegisterID base
)
213 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
214 return Address(base
, (virtualRegisterIndex
* sizeof(Register
)) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
));
217 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
)
219 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
220 loadPtr(tagFor(virtualRegisterIndex
), scratch
);
221 Jump isDouble
= branch32(Below
, scratch
, Imm32(JSValue::LowestTag
));
222 Jump notInt
= branch32(NotEqual
, scratch
, Imm32(JSValue::Int32Tag
));
223 loadPtr(payloadFor(virtualRegisterIndex
), scratch
);
224 convertInt32ToDouble(scratch
, dst
);
227 loadDouble(addressFor(virtualRegisterIndex
), dst
);
234 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg
)
236 return branchTestPtr(NonZero
, reg
, tagTypeNumberRegister
);
238 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg
)
240 return branchTestPtr(Zero
, reg
, tagTypeNumberRegister
);
242 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID dst
)
244 loadPtr(addressFor(virtualRegisterIndex
), dst
);
245 return branchTestPtr(NonZero
, dst
, tagMaskRegister
);
248 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
250 loadPtr(addressFor(virtualRegisterIndex
), dst
);
251 Jump result
= branchPtr(Below
, dst
, tagTypeNumberRegister
);
252 zeroExtend32ToPtr(dst
, dst
);
256 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
)
258 loadPtr(addressFor(virtualRegisterIndex
), scratch
);
259 Jump notNumber
= emitJumpIfNotImmediateNumber(scratch
);
260 Jump notInt
= branchPtr(Below
, scratch
, tagTypeNumberRegister
);
261 convertInt32ToDouble(scratch
, dst
);
264 addPtr(tagTypeNumberRegister
, scratch
);
265 movePtrToDouble(scratch
, dst
);
270 ALWAYS_INLINE
void JSInterfaceJIT::emitFastArithImmToInt(RegisterID
)
277 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID dst
)
279 loadPtr(addressFor(virtualRegisterIndex
), dst
);
280 return branchTest32(NonZero
, dst
, Imm32(JSImmediate::TagMask
));
283 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
285 loadPtr(addressFor(virtualRegisterIndex
), dst
);
286 Jump result
= branchTest32(Zero
, dst
, Imm32(JSImmediate::TagTypeNumber
));
287 rshift32(Imm32(JSImmediate::IntegerPayloadShift
), dst
);
291 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned, FPRegisterID
, RegisterID
)
293 ASSERT_NOT_REACHED();
297 ALWAYS_INLINE
void JSInterfaceJIT::emitFastArithImmToInt(RegisterID reg
)
299 rshift32(Imm32(JSImmediate::IntegerPayloadShift
), reg
);
304 #if !USE(JSVALUE32_64)
305 inline JSInterfaceJIT::Address
JSInterfaceJIT::payloadFor(unsigned virtualRegisterIndex
, RegisterID base
)
307 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
308 return addressFor(virtualRegisterIndex
, base
);
312 inline JSInterfaceJIT::Address
JSInterfaceJIT::addressFor(unsigned virtualRegisterIndex
, RegisterID base
)
314 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
315 return Address(base
, (virtualRegisterIndex
* sizeof(Register
)));
320 #endif // JSInterfaceJIT_h