AssemblyHelpers should not have a VM field
[WebKit.git] / Source / JavaScriptCore / jit / JSInterfaceJIT.h
1 /*
2  * Copyright (C) 2010, 2016 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 #pragma once
27
28 #include "BytecodeConventions.h"
29 #include "CCallHelpers.h"
30 #include "FPRInfo.h"
31 #include "GPRInfo.h"
32 #include "JITCode.h"
33 #include "JITOperations.h"
34 #include "JSCJSValue.h"
35 #include "JSString.h"
36 #include "MacroAssembler.h"
37
38 #if ENABLE(JIT)
39
40 namespace JSC {
41     class JSInterfaceJIT : public CCallHelpers, public GPRInfo, public FPRInfo {
42     public:
43         JSInterfaceJIT(VM* vm, CodeBlock* codeBlock = 0)
44             : CCallHelpers(codeBlock)
45             , m_vm(vm)
46         {
47         }
48
49 #if USE(JSVALUE32_64)
50         static const unsigned Int32Tag = static_cast<unsigned>(JSValue::Int32Tag);
51 #else
52         static const unsigned Int32Tag = static_cast<unsigned>(TagTypeNumber >> 32);
53 #endif
54         inline Jump emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload);
55         inline Jump emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst);
56         inline Jump emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch);
57
58 #if USE(JSVALUE32_64)
59         inline Jump emitJumpIfNotJSCell(unsigned virtualRegisterIndex);
60         inline Address tagFor(int index, RegisterID base = callFrameRegister);
61 #endif
62
63 #if USE(JSVALUE64)
64         Jump emitJumpIfNotJSCell(RegisterID);
65         Jump emitJumpIfNumber(RegisterID);
66         Jump emitJumpIfNotNumber(RegisterID);
67         void emitTagInt(RegisterID src, RegisterID dest);
68 #endif
69
70         Jump emitJumpIfNotType(RegisterID baseReg, JSType);
71
72         void emitGetFromCallFrameHeaderPtr(int entry, RegisterID to, RegisterID from = callFrameRegister);
73         void emitPutToCallFrameHeader(RegisterID from, int entry);
74         void emitPutToCallFrameHeader(void* value, int entry);
75         void emitPutCellToCallFrameHeader(RegisterID from, int entry);
76
77         inline Address payloadFor(int index, RegisterID base = callFrameRegister);
78         inline Address intPayloadFor(int index, RegisterID base = callFrameRegister);
79         inline Address intTagFor(int index, RegisterID base = callFrameRegister);
80         inline Address addressFor(int index, RegisterID base = callFrameRegister);
81
82         VM* vm() const { return m_vm; }
83
84         VM* m_vm;
85     };
86
87     struct ThunkHelpers {
88         static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString, m_length); }
89         static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString, m_value); }
90     };
91
92 #if USE(JSVALUE32_64)
93     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload)
94     {
95         loadPtr(payloadFor(virtualRegisterIndex), payload);
96         return emitJumpIfNotJSCell(virtualRegisterIndex);
97     }
98
99     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex)
100     {
101         ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
102         return branch32(NotEqual, tagFor(virtualRegisterIndex), TrustedImm32(JSValue::CellTag));
103     }
104     
105     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
106     {
107         ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
108         loadPtr(payloadFor(virtualRegisterIndex), dst);
109         return branch32(NotEqual, tagFor(static_cast<int>(virtualRegisterIndex)), TrustedImm32(JSValue::Int32Tag));
110     }
111     
112     inline JSInterfaceJIT::Address JSInterfaceJIT::tagFor(int virtualRegisterIndex, RegisterID base)
113     {
114         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
115         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.tag));
116     }
117     
118     inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base)
119     {
120         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
121         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.payload));
122     }
123
124     inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base)
125     {
126         return payloadFor(virtualRegisterIndex, base);
127     }
128
129     inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base)
130     {
131         return tagFor(virtualRegisterIndex, base);
132     }
133
134     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
135     {
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);
142         Jump done = jump();
143         isDouble.link(this);
144         loadDouble(addressFor(virtualRegisterIndex), dst);
145         done.link(this);
146         return notInt;
147     }
148
149 #endif
150
151 #if USE(JSVALUE64)
152     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotJSCell(RegisterID reg)
153     {
154         return branchTest64(NonZero, reg, tagMaskRegister);
155     }
156
157     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNumber(RegisterID reg)
158     {
159         return branchTest64(NonZero, reg, tagTypeNumberRegister);
160     }
161     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotNumber(RegisterID reg)
162     {
163         return branchTest64(Zero, reg, tagTypeNumberRegister);
164     }
165     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID dst)
166     {
167         load64(addressFor(virtualRegisterIndex), dst);
168         return branchTest64(NonZero, dst, tagMaskRegister);
169     }
170     
171     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
172     {
173         load64(addressFor(virtualRegisterIndex), dst);
174         Jump result = branch64(Below, dst, tagTypeNumberRegister);
175         zeroExtend32ToPtr(dst, dst);
176         return result;
177     }
178
179     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
180     {
181         load64(addressFor(virtualRegisterIndex), scratch);
182         Jump notNumber = emitJumpIfNotNumber(scratch);
183         Jump notInt = branch64(Below, scratch, tagTypeNumberRegister);
184         convertInt32ToDouble(scratch, dst);
185         Jump done = jump();
186         notInt.link(this);
187         add64(tagTypeNumberRegister, scratch);
188         move64ToDouble(scratch, dst);
189         done.link(this);
190         return notNumber;
191     }
192
193     // operand is int32_t, must have been zero-extended if register is 64-bit.
194     ALWAYS_INLINE void JSInterfaceJIT::emitTagInt(RegisterID src, RegisterID dest)
195     {
196         if (src != dest)
197             move(src, dest);
198         or64(tagTypeNumberRegister, dest);
199     }
200 #endif
201
202 #if USE(JSVALUE64)
203     inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base)
204     {
205         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
206         return addressFor(virtualRegisterIndex, base);
207     }
208
209     inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base)
210     {
211         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
212         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
213     }
214     inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base)
215     {
216         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
217         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
218     }
219 #endif
220
221     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotType(RegisterID baseReg, JSType type)
222     {
223         return branch8(NotEqual, Address(baseReg, JSCell::typeInfoTypeOffset()), TrustedImm32(type));
224     }
225
226     ALWAYS_INLINE void JSInterfaceJIT::emitGetFromCallFrameHeaderPtr(int entry, RegisterID to, RegisterID from)
227     {
228         loadPtr(Address(from, entry * sizeof(Register)), to);
229     }
230
231     ALWAYS_INLINE void JSInterfaceJIT::emitPutToCallFrameHeader(RegisterID from, int entry)
232     {
233 #if USE(JSVALUE32_64)
234         storePtr(from, payloadFor(entry, callFrameRegister));
235 #else
236         store64(from, addressFor(entry, callFrameRegister));
237 #endif
238     }
239
240     ALWAYS_INLINE void JSInterfaceJIT::emitPutToCallFrameHeader(void* value, int entry)
241     {
242         storePtr(TrustedImmPtr(value), Address(callFrameRegister, entry * sizeof(Register)));
243     }
244
245     ALWAYS_INLINE void JSInterfaceJIT::emitPutCellToCallFrameHeader(RegisterID from, int entry)
246     {
247 #if USE(JSVALUE32_64)
248         store32(TrustedImm32(JSValue::CellTag), tagFor(entry, callFrameRegister));
249         store32(from, payloadFor(entry, callFrameRegister));
250 #else
251         store64(from, addressFor(entry, callFrameRegister));
252 #endif
253     }
254
255     inline JSInterfaceJIT::Address JSInterfaceJIT::addressFor(int virtualRegisterIndex, RegisterID base)
256     {
257         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
258         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)));
259     }
260
261 } // namespace JSC
262
263 #endif // ENABLE(JIT)