2008-12-11 Gavin Barraclough <barraclough@apple.com>
[WebKit-https.git] / JavaScriptCore / jit / JITInlineMethods.h
1 /*
2  * Copyright (C) 2008 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef JITInlineMethods_h
27 #define JITInlineMethods_h
28
29 #include <wtf/Platform.h>
30
31 #if ENABLE(JIT)
32
33 #define __ m_assembler.
34
35 #if PLATFORM(WIN)
36 #undef FIELD_OFFSET // Fix conflict with winnt.h.
37 #endif
38
39 // FIELD_OFFSET: Like the C++ offsetof macro, but you can use it with classes.
40 // The magic number 0x4000 is insignificant. We use it to avoid using NULL, since
41 // NULL can cause compiler problems, especially in cases of multiple inheritance.
42 #define FIELD_OFFSET(class, field) (reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<class*>(0x4000)->field)) - 0x4000)
43
44 namespace JSC {
45
46 typedef X86Assembler::JmpSrc JmpSrc;
47
48 static ALWAYS_INLINE uintptr_t asInteger(JSValue* value)
49 {
50     return reinterpret_cast<uintptr_t>(value);
51 }
52
53 ALWAYS_INLINE void JIT::killLastResultRegister()
54 {
55     m_lastResultBytecodeRegister = std::numeric_limits<int>::max();
56 }
57
58 // get arg puts an arg from the SF register array into a h/w register
59 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, RegisterID dst, unsigned currentInstructionIndex)
60 {
61     // TODO: we want to reuse values that are already in registers if we can - add a register allocator!
62     if (m_codeBlock->isConstantRegisterIndex(src)) {
63         JSValue* value = m_codeBlock->getConstant(src);
64         move(ImmPtr(value), dst);
65         killLastResultRegister();
66         return;
67     }
68
69     if (src == m_lastResultBytecodeRegister && m_codeBlock->isTemporaryRegisterIndex(src)) {
70         bool atJumpTarget = false;
71         while (m_jumpTargetsPosition < m_codeBlock->numberOfJumpTargets() && m_codeBlock->jumpTarget(m_jumpTargetsPosition) <= currentInstructionIndex) {
72             if (m_codeBlock->jumpTarget(m_jumpTargetsPosition) == currentInstructionIndex)
73                 atJumpTarget = true;
74             ++m_jumpTargetsPosition;
75         }
76
77         if (!atJumpTarget) {
78             // The argument we want is already stored in eax
79             if (dst != X86::eax)
80                 move(X86::eax, dst);
81             killLastResultRegister();
82             return;
83         }
84     }
85
86     loadPtr(Address(callFrameRegister, src * sizeof(Register)), dst);
87     killLastResultRegister();
88 }
89
90 ALWAYS_INLINE void JIT::emitGetVirtualRegisters(int src1, RegisterID dst1, int src2, RegisterID dst2, unsigned i)
91 {
92     if (src2 == m_lastResultBytecodeRegister) {
93         emitGetVirtualRegister(src2, dst2, i);
94         emitGetVirtualRegister(src1, dst1, i);
95     } else {
96         emitGetVirtualRegister(src1, dst1, i);
97         emitGetVirtualRegister(src2, dst2, i);
98     }
99 }
100
101 // puts an arg onto the stack, as an arg to a context threaded function.
102 ALWAYS_INLINE void JIT::emitPutCTIArg(RegisterID src, unsigned offset)
103 {
104     poke(src, (offset / sizeof(void*)) + 1);
105 }
106
107 ALWAYS_INLINE void JIT::emitPutCTIArgConstant(unsigned value, unsigned offset)
108 {
109     poke(Imm32(value), (offset / sizeof(void*)) + 1);
110 }
111
112 ALWAYS_INLINE void JIT::emitPutCTIArgConstant(void* value, unsigned offset)
113 {
114     poke(ImmPtr(value), (offset / sizeof(void*)) + 1);
115 }
116
117 ALWAYS_INLINE void JIT::emitGetCTIArg(unsigned offset, RegisterID dst)
118 {
119     peek(dst, (offset / sizeof(void*)) + 1);
120 }
121
122 ALWAYS_INLINE JSValue* JIT::getConstantImmediateNumericArg(unsigned src)
123 {
124     if (m_codeBlock->isConstantRegisterIndex(src)) {
125         JSValue* value = m_codeBlock->getConstant(src);
126         return JSImmediate::isNumber(value) ? value : noValue();
127     }
128     return noValue();
129 }
130
131 // get arg puts an arg from the SF register array onto the stack, as an arg to a context threaded function.
132 ALWAYS_INLINE void JIT::emitPutCTIArgFromVirtualRegister(unsigned src, unsigned offset, RegisterID scratch)
133 {
134     if (m_codeBlock->isConstantRegisterIndex(src)) {
135         JSValue* value = m_codeBlock->getConstant(src);
136         emitPutCTIArgConstant(value, offset);
137     } else {
138         loadPtr(Address(callFrameRegister, src * sizeof(Register)), scratch);
139         emitPutCTIArg(scratch, offset);
140     }
141
142     killLastResultRegister();
143 }
144
145 ALWAYS_INLINE void JIT::emitPutCTIParam(void* value, unsigned name)
146 {
147     poke(ImmPtr(value), name);
148 }
149
150 ALWAYS_INLINE void JIT::emitPutCTIParam(RegisterID from, unsigned name)
151 {
152     poke(from, name);
153 }
154
155 ALWAYS_INLINE void JIT::emitGetCTIParam(unsigned name, RegisterID to)
156 {
157     peek(to, name);
158     killLastResultRegister();
159 }
160
161 ALWAYS_INLINE void JIT::emitPutToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry entry)
162 {
163     storePtr(from, Address(callFrameRegister, entry * sizeof(Register)));
164 }
165
166 ALWAYS_INLINE void JIT::emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry)
167 {
168     storePtr(ImmPtr(value), Address(callFrameRegister, entry * sizeof(Register)));
169 }
170
171 ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, RegisterID to)
172 {
173     loadPtr(Address(callFrameRegister, entry * sizeof(Register)), to);
174     killLastResultRegister();
175 }
176
177 ALWAYS_INLINE void JIT::emitPutVirtualRegister(unsigned dst, RegisterID from)
178 {
179     storePtr(from, Address(callFrameRegister, dst * sizeof(Register)));
180     m_lastResultBytecodeRegister = (from == X86::eax) ? dst : std::numeric_limits<int>::max();
181     // FIXME: #ifndef NDEBUG, Write the correct m_type to the register.
182 }
183
184 ALWAYS_INLINE void JIT::emitInitRegister(unsigned dst)
185 {
186     storePtr(ImmPtr(jsUndefined()), Address(callFrameRegister, dst * sizeof(Register)));
187     // FIXME: #ifndef NDEBUG, Write the correct m_type to the register.
188 }
189
190 ALWAYS_INLINE JmpSrc JIT::emitNakedCall(unsigned bytecodeIndex, X86::RegisterID r)
191 {
192     JmpSrc nakedCall = call(r);
193     m_calls.append(CallRecord(nakedCall, bytecodeIndex));
194     return nakedCall;
195 }
196
197 ALWAYS_INLINE JmpSrc JIT::emitNakedCall(unsigned bytecodeIndex, void* function)
198 {
199     JmpSrc nakedCall = call();
200     m_calls.append(CallRecord(nakedCall, reinterpret_cast<CTIHelper_v>(function), bytecodeIndex));
201     return nakedCall;
202 }
203
204 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_j helper)
205 {
206 #if ENABLE(OPCODE_SAMPLING)
207     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
208 #endif
209     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
210     JmpSrc ctiCall = call();
211     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
212 #if ENABLE(OPCODE_SAMPLING)
213     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
214 #endif
215     killLastResultRegister();
216
217     return ctiCall;
218 }
219
220 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_o helper)
221 {
222 #if ENABLE(OPCODE_SAMPLING)
223     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
224 #endif
225     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
226     JmpSrc ctiCall = call();
227     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
228 #if ENABLE(OPCODE_SAMPLING)
229     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
230 #endif
231     killLastResultRegister();
232
233     return ctiCall;
234 }
235
236 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_p helper)
237 {
238 #if ENABLE(OPCODE_SAMPLING)
239     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
240 #endif
241     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
242     JmpSrc ctiCall = call();
243     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
244 #if ENABLE(OPCODE_SAMPLING)
245     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
246 #endif
247     killLastResultRegister();
248
249     return ctiCall;
250 }
251
252 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_b helper)
253 {
254 #if ENABLE(OPCODE_SAMPLING)
255     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
256 #endif
257     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
258     JmpSrc ctiCall = call();
259     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
260 #if ENABLE(OPCODE_SAMPLING)
261     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
262 #endif
263     killLastResultRegister();
264
265     return ctiCall;
266 }
267
268 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_v helper)
269 {
270 #if ENABLE(OPCODE_SAMPLING)
271     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
272 #endif
273     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
274     JmpSrc ctiCall = call();
275     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
276 #if ENABLE(OPCODE_SAMPLING)
277     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
278 #endif
279     killLastResultRegister();
280
281     return ctiCall;
282 }
283
284 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_s helper)
285 {
286 #if ENABLE(OPCODE_SAMPLING)
287     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
288 #endif
289     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
290     JmpSrc ctiCall = call();
291     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
292 #if ENABLE(OPCODE_SAMPLING)
293     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
294 #endif
295     killLastResultRegister();
296
297     return ctiCall;
298 }
299
300 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_2 helper)
301 {
302 #if ENABLE(OPCODE_SAMPLING)
303     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
304 #endif
305     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
306     JmpSrc ctiCall = call();
307     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
308 #if ENABLE(OPCODE_SAMPLING)
309     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
310 #endif
311     killLastResultRegister();
312
313     return ctiCall;
314 }
315
316 ALWAYS_INLINE JmpSrc JIT::checkStructure(RegisterID reg, Structure* structure)
317 {
318     return jnePtr(Address(reg, FIELD_OFFSET(JSCell, m_structure)), ImmPtr(structure));
319 }
320
321 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfJSCell(RegisterID reg)
322 {
323     return jz32(reg, Imm32(JSImmediate::TagMask));
324 }
325
326 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfJSCell(RegisterID reg, unsigned bytecodeIndex)
327 {
328     m_slowCases.append(SlowCaseEntry(emitJumpIfJSCell(reg), bytecodeIndex));
329 }
330
331 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotJSCell(RegisterID reg)
332 {
333     return jnz32(reg, Imm32(JSImmediate::TagMask));
334 }
335
336 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, unsigned bytecodeIndex)
337 {
338     m_slowCases.append(SlowCaseEntry(emitJumpIfNotJSCell(reg), bytecodeIndex));
339 }
340
341 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, unsigned bytecodeIndex, int vReg)
342 {
343     if (m_codeBlock->isKnownNotImmediate(vReg))
344         return;
345
346     emitJumpSlowCaseIfNotJSCell(reg, bytecodeIndex);
347 }
348
349 ALWAYS_INLINE bool JIT::linkSlowCaseIfNotJSCell(const Vector<SlowCaseEntry>::iterator& iter, int vReg)
350 {
351     if (m_codeBlock->isKnownNotImmediate(vReg))
352         return false;
353     
354     __ link(iter->from, __ label());
355     return true;
356 }
357
358 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmNum(RegisterID reg, unsigned bytecodeIndex)
359 {
360     m_slowCases.append(SlowCaseEntry(jz32(reg, Imm32(JSImmediate::TagBitTypeInteger)), bytecodeIndex));
361 }
362
363 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmNums(RegisterID reg1, RegisterID reg2, RegisterID scratch, unsigned bytecodeIndex)
364 {
365     move(reg1, scratch);
366     and32(reg2, scratch);
367     emitJumpSlowCaseIfNotImmNum(scratch, bytecodeIndex);
368 }
369
370 ALWAYS_INLINE unsigned JIT::getDeTaggedConstantImmediate(JSValue* imm)
371 {
372     ASSERT(JSImmediate::isNumber(imm));
373     return asInteger(imm) & ~JSImmediate::TagBitTypeInteger;
374 }
375
376 ALWAYS_INLINE void JIT::emitFastArithDeTagImmediate(RegisterID reg)
377 {
378     sub32(Imm32(JSImmediate::TagBitTypeInteger), reg);
379 }
380
381 ALWAYS_INLINE JmpSrc JIT::emitFastArithDeTagImmediateJumpIfZero(RegisterID reg)
382 {
383     return jzSub32(Imm32(JSImmediate::TagBitTypeInteger), reg);
384 }
385
386 ALWAYS_INLINE void JIT::emitFastArithReTagImmediate(RegisterID reg)
387 {
388     add32(Imm32(JSImmediate::TagBitTypeInteger), reg);
389 }
390
391 ALWAYS_INLINE void JIT::emitFastArithPotentiallyReTagImmediate(RegisterID reg)
392 {
393     or32(Imm32(JSImmediate::TagBitTypeInteger), reg);
394 }
395
396 ALWAYS_INLINE void JIT::emitFastArithImmToInt(RegisterID reg)
397 {
398     rshift32(Imm32(1), reg);
399 }
400
401 ALWAYS_INLINE void JIT::emitFastArithIntToImmOrSlowCase(RegisterID reg, unsigned bytecodeIndex)
402 {
403     m_slowCases.append(SlowCaseEntry(joAdd32(reg, reg), bytecodeIndex));
404     emitFastArithReTagImmediate(reg);
405 }
406
407 ALWAYS_INLINE void JIT::emitFastArithIntToImmNoCheck(RegisterID reg)
408 {
409     add32(reg, reg);
410     emitFastArithReTagImmediate(reg);
411 }
412
413 ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg)
414 {
415     lshift32(Imm32(JSImmediate::ExtendedPayloadShift), reg);
416     or32(Imm32(JSImmediate::FullTagTypeBool), reg);
417 }
418
419 }
420
421 #endif // ENABLE(JIT)
422
423 #endif