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 static const unsigned Int32Tag
= static_cast<unsigned>(JSValue::Int32Tag
);
55 static const unsigned Int32Tag
= static_cast<unsigned>(TagTypeNumber
>> 32);
57 inline Jump
emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID payload
);
58 inline Jump
emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
);
59 inline Jump
emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
);
62 inline Jump
emitJumpIfNotJSCell(unsigned virtualRegisterIndex
);
63 inline Address
tagFor(int index
, RegisterID base
= callFrameRegister
);
67 Jump
emitJumpIfNotJSCell(RegisterID
);
68 Jump
emitJumpIfImmediateNumber(RegisterID reg
);
69 Jump
emitJumpIfNotImmediateNumber(RegisterID reg
);
70 void emitFastArithImmToInt(RegisterID reg
);
71 void emitFastArithIntToImmNoCheck(RegisterID src
, RegisterID dest
);
74 Jump
emitJumpIfNotType(RegisterID baseReg
, JSType
);
76 void emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry
, RegisterID to
, RegisterID from
= callFrameRegister
);
77 void emitPutToCallFrameHeader(RegisterID from
, JSStack::CallFrameHeaderEntry
);
78 void emitPutImmediateToCallFrameHeader(void* value
, JSStack::CallFrameHeaderEntry
);
79 void emitPutCellToCallFrameHeader(RegisterID from
, JSStack::CallFrameHeaderEntry
);
81 inline Address
payloadFor(int index
, RegisterID base
= callFrameRegister
);
82 inline Address
intPayloadFor(int index
, RegisterID base
= callFrameRegister
);
83 inline Address
intTagFor(int index
, RegisterID base
= callFrameRegister
);
84 inline Address
addressFor(int index
, RegisterID base
= callFrameRegister
);
88 static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString
, m_length
); }
89 static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString
, m_value
); }
93 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID payload
)
95 loadPtr(payloadFor(virtualRegisterIndex
), payload
);
96 return emitJumpIfNotJSCell(virtualRegisterIndex
);
99 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex
)
101 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
102 return branch32(NotEqual
, tagFor(virtualRegisterIndex
), TrustedImm32(JSValue::CellTag
));
105 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
107 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
108 loadPtr(payloadFor(virtualRegisterIndex
), dst
);
109 return branch32(NotEqual
, tagFor(static_cast<int>(virtualRegisterIndex
)), TrustedImm32(JSValue::Int32Tag
));
112 inline JSInterfaceJIT::Address
JSInterfaceJIT::tagFor(int virtualRegisterIndex
, RegisterID base
)
114 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
115 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
));
118 inline JSInterfaceJIT::Address
JSInterfaceJIT::payloadFor(int virtualRegisterIndex
, RegisterID base
)
120 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
121 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
));
124 inline JSInterfaceJIT::Address
JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex
, RegisterID base
)
126 return payloadFor(virtualRegisterIndex
, base
);
129 inline JSInterfaceJIT::Address
JSInterfaceJIT::intTagFor(int virtualRegisterIndex
, RegisterID base
)
131 return tagFor(virtualRegisterIndex
, base
);
134 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
)
136 ASSERT(static_cast<int>(virtualRegisterIndex
) < FirstConstantRegisterIndex
);
137 loadPtr(tagFor(virtualRegisterIndex
), scratch
);
138 Jump isDouble
= branch32(Below
, scratch
, TrustedImm32(JSValue::LowestTag
));
139 Jump notInt
= branch32(NotEqual
, scratch
, TrustedImm32(JSValue::Int32Tag
));
140 loadPtr(payloadFor(virtualRegisterIndex
), scratch
);
141 convertInt32ToDouble(scratch
, dst
);
144 loadDouble(addressFor(virtualRegisterIndex
), dst
);
152 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotJSCell(RegisterID reg
)
154 return branchTest64(NonZero
, reg
, tagMaskRegister
);
157 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg
)
159 return branchTest64(NonZero
, reg
, tagTypeNumberRegister
);
161 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg
)
163 return branchTest64(Zero
, reg
, tagTypeNumberRegister
);
165 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex
, RegisterID dst
)
167 load64(addressFor(virtualRegisterIndex
), dst
);
168 return branchTest64(NonZero
, dst
, tagMaskRegister
);
171 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex
, RegisterID dst
)
173 load64(addressFor(virtualRegisterIndex
), dst
);
174 Jump result
= branch64(Below
, dst
, tagTypeNumberRegister
);
175 zeroExtend32ToPtr(dst
, dst
);
179 inline JSInterfaceJIT::Jump
JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex
, FPRegisterID dst
, RegisterID scratch
)
181 load64(addressFor(virtualRegisterIndex
), scratch
);
182 Jump notNumber
= emitJumpIfNotImmediateNumber(scratch
);
183 Jump notInt
= branch64(Below
, scratch
, tagTypeNumberRegister
);
184 convertInt32ToDouble(scratch
, dst
);
187 add64(tagTypeNumberRegister
, scratch
);
188 move64ToDouble(scratch
, dst
);
193 ALWAYS_INLINE
void JSInterfaceJIT::emitFastArithImmToInt(RegisterID
)
197 // operand is int32_t, must have been zero-extended if register is 64-bit.
198 ALWAYS_INLINE
void JSInterfaceJIT::emitFastArithIntToImmNoCheck(RegisterID src
, RegisterID dest
)
202 or64(tagTypeNumberRegister
, dest
);
207 inline JSInterfaceJIT::Address
JSInterfaceJIT::payloadFor(int virtualRegisterIndex
, RegisterID base
)
209 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
210 return addressFor(virtualRegisterIndex
, base
);
213 inline JSInterfaceJIT::Address
JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex
, RegisterID base
)
215 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
216 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
));
218 inline JSInterfaceJIT::Address
JSInterfaceJIT::intTagFor(int virtualRegisterIndex
, RegisterID base
)
220 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
221 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
));
225 ALWAYS_INLINE
JSInterfaceJIT::Jump
JSInterfaceJIT::emitJumpIfNotType(RegisterID baseReg
, JSType type
)
227 return branch8(NotEqual
, Address(baseReg
, JSCell::typeInfoTypeOffset()), TrustedImm32(type
));
230 ALWAYS_INLINE
void JSInterfaceJIT::emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry
, RegisterID to
, RegisterID from
)
232 loadPtr(Address(from
, entry
* sizeof(Register
)), to
);
235 ALWAYS_INLINE
void JSInterfaceJIT::emitPutToCallFrameHeader(RegisterID from
, JSStack::CallFrameHeaderEntry entry
)
237 #if USE(JSVALUE32_64)
238 storePtr(from
, payloadFor(entry
, callFrameRegister
));
240 store64(from
, addressFor(entry
, callFrameRegister
));
244 ALWAYS_INLINE
void JSInterfaceJIT::emitPutImmediateToCallFrameHeader(void* value
, JSStack::CallFrameHeaderEntry entry
)
246 storePtr(TrustedImmPtr(value
), Address(callFrameRegister
, entry
* sizeof(Register
)));
249 ALWAYS_INLINE
void JSInterfaceJIT::emitPutCellToCallFrameHeader(RegisterID from
, JSStack::CallFrameHeaderEntry entry
)
251 #if USE(JSVALUE32_64)
252 store32(TrustedImm32(JSValue::CellTag
), tagFor(entry
, callFrameRegister
));
253 store32(from
, payloadFor(entry
, callFrameRegister
));
255 store64(from
, addressFor(entry
, callFrameRegister
));
259 inline JSInterfaceJIT::Address
JSInterfaceJIT::addressFor(int virtualRegisterIndex
, RegisterID base
)
261 ASSERT(virtualRegisterIndex
< FirstConstantRegisterIndex
);
262 return Address(base
, (static_cast<unsigned>(virtualRegisterIndex
) * sizeof(Register
)));
267 #endif // ENABLE(JIT)
269 #endif // JSInterfaceJIT_h