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"
30 #include "CCallHelpers.h"
34 #include "JITOperations.h"
36 #include "JSCJSValue.h"
39 #include "MacroAssembler.h"
40 #include <wtf/Vector.h>
45 class JSInterfaceJIT
: public CCallHelpers
, public GPRInfo
, public FPRInfo
{
47 JSInterfaceJIT(VM
* vm
, CodeBlock
* codeBlock
= 0)
48 : CCallHelpers(vm
, codeBlock
)
53 // Can't just propogate JSValue::Int32Tag as visual studio doesn't like it
54 static const unsigned Int32Tag
= 0xffffffff;
55 COMPILE_ASSERT(Int32Tag
== JSValue::Int32Tag
, Int32Tag_out_of_sync
);
57 static const unsigned Int32Tag
= static_cast<unsigned>(TagTypeNumber
>> 32);
59 inline Jump
emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID payload
);
60 inline Jump
emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
);
61 inline Jump
emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
);
64 inline Jump
emitJumpIfNotJSCell(unsigned virtualRegisterIndex
);
65 inline Address
tagFor(int index
, RegisterID base
= callFrameRegister
);
69 Jump
emitJumpIfNotJSCell(RegisterID
);
70 Jump
emitJumpIfImmediateNumber(RegisterID reg
);
71 Jump
emitJumpIfNotImmediateNumber(RegisterID reg
);
72 void emitFastArithImmToInt(RegisterID reg
);
73 void emitFastArithIntToImmNoCheck(RegisterID src
, RegisterID dest
);
76 Jump
emitJumpIfNotType(RegisterID baseReg
, JSType
);
78 void emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry
, RegisterID to
, RegisterID from
= callFrameRegister
);
79 void emitPutToCallFrameHeader(RegisterID from
, JSStack::CallFrameHeaderEntry
);
80 void emitPutImmediateToCallFrameHeader(void* value
, JSStack::CallFrameHeaderEntry
);
81 void emitPutCellToCallFrameHeader(RegisterID from
, JSStack::CallFrameHeaderEntry
);
83 inline Address
payloadFor(int index
, RegisterID base
= callFrameRegister
);
84 inline Address
intPayloadFor(int index
, RegisterID base
= callFrameRegister
);
85 inline Address
intTagFor(int index
, RegisterID base
= callFrameRegister
);
86 inline Address
addressFor(int index
, RegisterID base
= callFrameRegister
);
90 static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString
, m_length
); }
91 static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString
, m_value
); }
95 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID payload
)
97 loadPtr(payloadFor(virtualRegisterIndex
), payload
);
98 return emitJumpIfNotJSCell(virtualRegisterIndex
);
101 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex
)
103 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
104 return branch32(NotEqual
, tagFor(virtualRegisterIndex
), TrustedImm32(JSValue::CellTag
));
107 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
109 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
110 loadPtr(payloadFor(virtualRegisterIndex
), dst
);
111 return branch32(NotEqual
, tagFor(static_cast<int>(virtualRegisterIndex
)), TrustedImm32(JSValue::Int32Tag
));
114 inline JSInterfaceJIT::Address
JSInterfaceJIT::tagFor(int virtualRegisterIndex
, RegisterID base
)
116 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
117 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
));
120 inline JSInterfaceJIT::Address
JSInterfaceJIT::payloadFor(int virtualRegisterIndex
, RegisterID base
)
122 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
123 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
));
126 inline JSInterfaceJIT::Address
JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex
, RegisterID base
)
128 return payloadFor(virtualRegisterIndex
, base
);
131 inline JSInterfaceJIT::Address
JSInterfaceJIT::intTagFor(int virtualRegisterIndex
, RegisterID base
)
133 return tagFor(virtualRegisterIndex
, base
);
136 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
)
138 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
139 loadPtr(tagFor(virtualRegisterIndex
), scratch
);
140 Jump isDouble
= branch32(Below
, scratch
, TrustedImm32(JSValue::LowestTag
));
141 Jump notInt
= branch32(NotEqual
, scratch
, TrustedImm32(JSValue::Int32Tag
));
142 loadPtr(payloadFor(virtualRegisterIndex
), scratch
);
143 convertInt32ToDouble(scratch
, dst
);
146 loadDouble(addressFor(virtualRegisterIndex
), dst
);
154 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotJSCell(RegisterID reg
)
156 return branchTest64(NonZero
, reg
, tagMaskRegister
);
159 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg
)
161 return branchTest64(NonZero
, reg
, tagTypeNumberRegister
);
163 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg
)
165 return branchTest64(Zero
, reg
, tagTypeNumberRegister
);
167 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID dst
)
169 load64(addressFor(virtualRegisterIndex
), dst
);
170 return branchTest64(NonZero
, dst
, tagMaskRegister
);
173 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
175 load64(addressFor(virtualRegisterIndex
), dst
);
176 Jump result
= branch64(Below
, dst
, tagTypeNumberRegister
);
177 zeroExtend32ToPtr(dst
, dst
);
181 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
)
183 load64(addressFor(virtualRegisterIndex
), scratch
);
184 Jump notNumber
= emitJumpIfNotImmediateNumber(scratch
);
185 Jump notInt
= branch64(Below
, scratch
, tagTypeNumberRegister
);
186 convertInt32ToDouble(scratch
, dst
);
189 add64(tagTypeNumberRegister
, scratch
);
190 move64ToDouble(scratch
, dst
);
195 ALWAYS_INLINE
void JSInterfaceJIT::emitFastArithImmToInt(RegisterID
)
199 // operand is int32_t, must have been zero-extended if register is 64-bit.
200 ALWAYS_INLINE
void JSInterfaceJIT::emitFastArithIntToImmNoCheck(RegisterID src
, RegisterID dest
)
204 or64(tagTypeNumberRegister
, dest
);
209 inline JSInterfaceJIT::Address
JSInterfaceJIT::payloadFor(int virtualRegisterIndex
, RegisterID base
)
211 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
212 return addressFor(virtualRegisterIndex
, base
);
215 inline JSInterfaceJIT::Address
JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex
, RegisterID base
)
217 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
218 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
));
220 inline JSInterfaceJIT::Address
JSInterfaceJIT::intTagFor(int virtualRegisterIndex
, RegisterID base
)
222 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
223 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
));
227 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotType(RegisterID baseReg
, JSType type
)
229 return branch8(NotEqual
, Address(baseReg
, JSCell::typeInfoTypeOffset()), TrustedImm32(type
));
232 ALWAYS_INLINE
void JSInterfaceJIT::emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry
, RegisterID to
, RegisterID from
)
234 loadPtr(Address(from
, entry
* sizeof(Register
)), to
);
237 ALWAYS_INLINE
void JSInterfaceJIT::emitPutToCallFrameHeader(RegisterID from
, JSStack::CallFrameHeaderEntry entry
)
239 #if USE(JSVALUE32_64)
240 storePtr(from
, payloadFor(entry
, callFrameRegister
));
242 store64(from
, addressFor(entry
, callFrameRegister
));
246 ALWAYS_INLINE
void JSInterfaceJIT::emitPutImmediateToCallFrameHeader(void* value
, JSStack::CallFrameHeaderEntry entry
)
248 storePtr(TrustedImmPtr(value
), Address(callFrameRegister
, entry
* sizeof(Register
)));
251 ALWAYS_INLINE
void JSInterfaceJIT::emitPutCellToCallFrameHeader(RegisterID from
, JSStack::CallFrameHeaderEntry entry
)
253 #if USE(JSVALUE32_64)
254 store32(TrustedImm32(JSValue::CellTag
), tagFor(entry
, callFrameRegister
));
255 store32(from
, payloadFor(entry
, callFrameRegister
));
257 store64(from
, addressFor(entry
, callFrameRegister
));
261 inline JSInterfaceJIT::Address
JSInterfaceJIT::addressFor(int virtualRegisterIndex
, RegisterID base
)
263 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
264 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)));
269 #endif // ENABLE(JIT)
271 #endif // JSInterfaceJIT_h