Swipe snapshot removed too early (jumps around) on arstechnica and NYT
[WebKit-https.git] / Source / JavaScriptCore / jit / JSInterfaceJIT.h
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #ifndef JSInterfaceJIT_h
27 #define JSInterfaceJIT_h
28
29 #include "BytecodeConventions.h"
30 #include "CCallHelpers.h"
31 #include "FPRInfo.h"
32 #include "GPRInfo.h"
33 #include "JITCode.h"
34 #include "JITOperations.h"
35 #include "JITStubs.h"
36 #include "JSCJSValue.h"
37 #include "JSStack.h"
38 #include "JSString.h"
39 #include "MacroAssembler.h"
40 #include <wtf/Vector.h>
41
42 #if ENABLE(JIT)
43
44 namespace JSC {
45     class JSInterfaceJIT : public CCallHelpers, public GPRInfo, public FPRInfo {
46     public:
47         JSInterfaceJIT(VM* vm, CodeBlock* codeBlock = 0)
48             : CCallHelpers(vm, codeBlock)
49         {
50         }
51
52 #if USE(JSVALUE32_64)
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);
56 #else
57         static const unsigned Int32Tag = static_cast<unsigned>(TagTypeNumber >> 32);
58 #endif
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);
62
63 #if USE(JSVALUE32_64)
64         inline Jump emitJumpIfNotJSCell(unsigned virtualRegisterIndex);
65         inline Address tagFor(int index, RegisterID base = callFrameRegister);
66 #endif
67
68 #if USE(JSVALUE64)
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);
74 #endif
75
76         Jump emitJumpIfNotType(RegisterID baseReg, JSType);
77
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);
82
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);
87     };
88
89     struct ThunkHelpers {
90         static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString, m_length); }
91         static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString, m_value); }
92     };
93
94 #if USE(JSVALUE32_64)
95     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload)
96     {
97         loadPtr(payloadFor(virtualRegisterIndex), payload);
98         return emitJumpIfNotJSCell(virtualRegisterIndex);
99     }
100
101     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex)
102     {
103         ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
104         return branch32(NotEqual, tagFor(virtualRegisterIndex), TrustedImm32(JSValue::CellTag));
105     }
106     
107     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
108     {
109         ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
110         loadPtr(payloadFor(virtualRegisterIndex), dst);
111         return branch32(NotEqual, tagFor(static_cast<int>(virtualRegisterIndex)), TrustedImm32(JSValue::Int32Tag));
112     }
113     
114     inline JSInterfaceJIT::Address JSInterfaceJIT::tagFor(int virtualRegisterIndex, RegisterID base)
115     {
116         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
117         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.tag));
118     }
119     
120     inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base)
121     {
122         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
123         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.payload));
124     }
125
126     inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base)
127     {
128         return payloadFor(virtualRegisterIndex, base);
129     }
130
131     inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base)
132     {
133         return tagFor(virtualRegisterIndex, base);
134     }
135
136     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
137     {
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);
144         Jump done = jump();
145         isDouble.link(this);
146         loadDouble(addressFor(virtualRegisterIndex), dst);
147         done.link(this);
148         return notInt;
149     }
150
151 #endif
152
153 #if USE(JSVALUE64)
154     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotJSCell(RegisterID reg)
155     {
156         return branchTest64(NonZero, reg, tagMaskRegister);
157     }
158
159     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg)
160     {
161         return branchTest64(NonZero, reg, tagTypeNumberRegister);
162     }
163     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg)
164     {
165         return branchTest64(Zero, reg, tagTypeNumberRegister);
166     }
167     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID dst)
168     {
169         load64(addressFor(virtualRegisterIndex), dst);
170         return branchTest64(NonZero, dst, tagMaskRegister);
171     }
172     
173     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
174     {
175         load64(addressFor(virtualRegisterIndex), dst);
176         Jump result = branch64(Below, dst, tagTypeNumberRegister);
177         zeroExtend32ToPtr(dst, dst);
178         return result;
179     }
180
181     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
182     {
183         load64(addressFor(virtualRegisterIndex), scratch);
184         Jump notNumber = emitJumpIfNotImmediateNumber(scratch);
185         Jump notInt = branch64(Below, scratch, tagTypeNumberRegister);
186         convertInt32ToDouble(scratch, dst);
187         Jump done = jump();
188         notInt.link(this);
189         add64(tagTypeNumberRegister, scratch);
190         move64ToDouble(scratch, dst);
191         done.link(this);
192         return notNumber;
193     }
194
195     ALWAYS_INLINE void JSInterfaceJIT::emitFastArithImmToInt(RegisterID)
196     {
197     }
198     
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)
201     {
202         if (src != dest)
203             move(src, dest);
204         or64(tagTypeNumberRegister, dest);
205     }
206 #endif
207
208 #if USE(JSVALUE64)
209     inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base)
210     {
211         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
212         return addressFor(virtualRegisterIndex, base);
213     }
214
215     inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base)
216     {
217         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
218         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
219     }
220     inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base)
221     {
222         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
223         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
224     }
225 #endif
226
227     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotType(RegisterID baseReg, JSType type)
228     {
229         return branch8(NotEqual, Address(baseReg, JSCell::typeInfoTypeOffset()), TrustedImm32(type));
230     }
231
232     ALWAYS_INLINE void JSInterfaceJIT::emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry, RegisterID to, RegisterID from)
233     {
234         loadPtr(Address(from, entry * sizeof(Register)), to);
235     }
236
237     ALWAYS_INLINE void JSInterfaceJIT::emitPutToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry)
238     {
239 #if USE(JSVALUE32_64)
240         storePtr(from, payloadFor(entry, callFrameRegister));
241 #else
242         store64(from, addressFor(entry, callFrameRegister));
243 #endif
244     }
245
246     ALWAYS_INLINE void JSInterfaceJIT::emitPutImmediateToCallFrameHeader(void* value, JSStack::CallFrameHeaderEntry entry)
247     {
248         storePtr(TrustedImmPtr(value), Address(callFrameRegister, entry * sizeof(Register)));
249     }
250
251     ALWAYS_INLINE void JSInterfaceJIT::emitPutCellToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry)
252     {
253 #if USE(JSVALUE32_64)
254         store32(TrustedImm32(JSValue::CellTag), tagFor(entry, callFrameRegister));
255         store32(from, payloadFor(entry, callFrameRegister));
256 #else
257         store64(from, addressFor(entry, callFrameRegister));
258 #endif
259     }
260
261     inline JSInterfaceJIT::Address JSInterfaceJIT::addressFor(int virtualRegisterIndex, RegisterID base)
262     {
263         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
264         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)));
265     }
266
267 } // namespace JSC
268
269 #endif // ENABLE(JIT)
270
271 #endif // JSInterfaceJIT_h