757190a2a2ebf69747c41e472d6ee565332e4344
[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 void JIT::restoreArgumentReference()
205 {
206 #if USE(CTI_ARGUMENT)
207 #if USE(FAST_CALL_CTI_ARGUMENT)
208     __ movl_rr(X86::esp, X86::ecx);
209 #else
210     __ movl_rm(X86::esp, 0, X86::esp);
211 #endif
212 #endif
213 }
214
215 ALWAYS_INLINE void JIT::restoreArgumentReferenceForTrampoline()
216 {
217 #if USE(CTI_ARGUMENT) && USE(FAST_CALL_CTI_ARGUMENT)
218     __ movl_rr(X86::esp, X86::ecx);
219     __ addl_i32r(4, X86::ecx);
220 #endif
221 }
222
223
224 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_j helper)
225 {
226 #if ENABLE(OPCODE_SAMPLING)
227     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
228 #endif
229     restoreArgumentReference();
230     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
231     JmpSrc ctiCall = call();
232     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
233 #if ENABLE(OPCODE_SAMPLING)
234     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
235 #endif
236     killLastResultRegister();
237
238     return ctiCall;
239 }
240
241 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_o helper)
242 {
243 #if ENABLE(OPCODE_SAMPLING)
244     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
245 #endif
246     restoreArgumentReference();
247     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
248     JmpSrc ctiCall = call();
249     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
250 #if ENABLE(OPCODE_SAMPLING)
251     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
252 #endif
253     killLastResultRegister();
254
255     return ctiCall;
256 }
257
258 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_p helper)
259 {
260 #if ENABLE(OPCODE_SAMPLING)
261     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
262 #endif
263     restoreArgumentReference();
264     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
265     JmpSrc ctiCall = call();
266     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
267 #if ENABLE(OPCODE_SAMPLING)
268     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
269 #endif
270     killLastResultRegister();
271
272     return ctiCall;
273 }
274
275 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_b helper)
276 {
277 #if ENABLE(OPCODE_SAMPLING)
278     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
279 #endif
280     restoreArgumentReference();
281     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
282     JmpSrc ctiCall = call();
283     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
284 #if ENABLE(OPCODE_SAMPLING)
285     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
286 #endif
287     killLastResultRegister();
288
289     return ctiCall;
290 }
291
292 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_v helper)
293 {
294 #if ENABLE(OPCODE_SAMPLING)
295     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
296 #endif
297     restoreArgumentReference();
298     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
299     JmpSrc ctiCall = call();
300     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
301 #if ENABLE(OPCODE_SAMPLING)
302     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
303 #endif
304     killLastResultRegister();
305
306     return ctiCall;
307 }
308
309 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_s helper)
310 {
311 #if ENABLE(OPCODE_SAMPLING)
312     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
313 #endif
314     restoreArgumentReference();
315     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
316     JmpSrc ctiCall = call();
317     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
318 #if ENABLE(OPCODE_SAMPLING)
319     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
320 #endif
321     killLastResultRegister();
322
323     return ctiCall;
324 }
325
326 ALWAYS_INLINE JmpSrc JIT::emitCTICall(unsigned bytecodeIndex, CTIHelper_2 helper)
327 {
328 #if ENABLE(OPCODE_SAMPLING)
329     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, true)), m_interpreter->sampler()->sampleSlot());
330 #endif
331     restoreArgumentReference();
332     emitPutCTIParam(callFrameRegister, CTI_ARGS_callFrame);
333     JmpSrc ctiCall = call();
334     m_calls.append(CallRecord(ctiCall, helper, bytecodeIndex));
335 #if ENABLE(OPCODE_SAMPLING)
336     store32(Imm32(m_interpreter->sampler()->encodeSample(m_codeBlock->instructions().begin() + bytecodeIndex, false)), m_interpreter->sampler()->sampleSlot());
337 #endif
338     killLastResultRegister();
339
340     return ctiCall;
341 }
342
343 ALWAYS_INLINE JmpSrc JIT::checkStructure(RegisterID reg, Structure* structure)
344 {
345     return jnePtr(Address(reg, FIELD_OFFSET(JSCell, m_structure)), ImmPtr(structure));
346 }
347
348 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfJSCell(RegisterID reg)
349 {
350     return jz32(reg, Imm32(JSImmediate::TagMask));
351 }
352
353 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfJSCell(RegisterID reg, unsigned bytecodeIndex)
354 {
355     m_slowCases.append(SlowCaseEntry(emitJumpIfJSCell(reg), bytecodeIndex));
356 }
357
358 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotJSCell(RegisterID reg)
359 {
360     return jnz32(reg, Imm32(JSImmediate::TagMask));
361 }
362
363 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, unsigned bytecodeIndex)
364 {
365     m_slowCases.append(SlowCaseEntry(emitJumpIfNotJSCell(reg), bytecodeIndex));
366 }
367
368 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, unsigned bytecodeIndex, int vReg)
369 {
370     if (m_codeBlock->isKnownNotImmediate(vReg))
371         return;
372
373     emitJumpSlowCaseIfNotJSCell(reg, bytecodeIndex);
374 }
375
376 ALWAYS_INLINE bool JIT::linkSlowCaseIfNotJSCell(const Vector<SlowCaseEntry>::iterator& iter, int vReg)
377 {
378     if (m_codeBlock->isKnownNotImmediate(vReg))
379         return false;
380     
381     __ link(iter->from, __ label());
382     return true;
383 }
384
385 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmNum(RegisterID reg, unsigned bytecodeIndex)
386 {
387     m_slowCases.append(SlowCaseEntry(jz32(reg, Imm32(JSImmediate::TagBitTypeInteger)), bytecodeIndex));
388 }
389
390 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmNums(RegisterID reg1, RegisterID reg2, RegisterID scratch, unsigned bytecodeIndex)
391 {
392     move(reg1, scratch);
393     and32(reg2, scratch);
394     emitJumpSlowCaseIfNotImmNum(scratch, bytecodeIndex);
395 }
396
397 ALWAYS_INLINE unsigned JIT::getDeTaggedConstantImmediate(JSValue* imm)
398 {
399     ASSERT(JSImmediate::isNumber(imm));
400     return asInteger(imm) & ~JSImmediate::TagBitTypeInteger;
401 }
402
403 ALWAYS_INLINE void JIT::emitFastArithDeTagImmediate(RegisterID reg)
404 {
405     sub32(Imm32(JSImmediate::TagBitTypeInteger), reg);
406 }
407
408 ALWAYS_INLINE JmpSrc JIT::emitFastArithDeTagImmediateJumpIfZero(RegisterID reg)
409 {
410     return jzSub32(Imm32(JSImmediate::TagBitTypeInteger), reg);
411 }
412
413 ALWAYS_INLINE void JIT::emitFastArithReTagImmediate(RegisterID reg)
414 {
415     add32(Imm32(JSImmediate::TagBitTypeInteger), reg);
416 }
417
418 ALWAYS_INLINE void JIT::emitFastArithPotentiallyReTagImmediate(RegisterID reg)
419 {
420     or32(Imm32(JSImmediate::TagBitTypeInteger), reg);
421 }
422
423 ALWAYS_INLINE void JIT::emitFastArithImmToInt(RegisterID reg)
424 {
425     rshift32(Imm32(1), reg);
426 }
427
428 ALWAYS_INLINE void JIT::emitFastArithIntToImmOrSlowCase(RegisterID reg, unsigned bytecodeIndex)
429 {
430     m_slowCases.append(SlowCaseEntry(joAdd32(reg, reg), bytecodeIndex));
431     emitFastArithReTagImmediate(reg);
432 }
433
434 ALWAYS_INLINE void JIT::emitFastArithIntToImmNoCheck(RegisterID reg)
435 {
436     add32(reg, reg);
437     emitFastArithReTagImmediate(reg);
438 }
439
440 ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg)
441 {
442     lshift32(Imm32(JSImmediate::ExtendedPayloadShift), reg);
443     or32(Imm32(JSImmediate::FullTagTypeBool), reg);
444 }
445
446 }
447
448 #endif // ENABLE(JIT)
449
450 #endif