2bb67f13bede04d754b92c576af8a9fa0397c384
[WebKit-https.git] / Source / JavaScriptCore / jit / JITInlines.h
1 /*
2  * Copyright (C) 2008-2018 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 #pragma once
27
28 #if ENABLE(JIT)
29
30 #include "JSCInlines.h"
31
32 namespace JSC {
33
34 inline MacroAssembler::JumpList JIT::emitDoubleGetByVal(Instruction* instruction, PatchableJump& badType)
35 {
36 #if USE(JSVALUE64)
37     JSValueRegs result = JSValueRegs(regT0);
38 #else
39     JSValueRegs result = JSValueRegs(regT1, regT0);
40 #endif
41     JumpList slowCases = emitDoubleLoad(instruction, badType);
42     boxDouble(fpRegT0, result);
43     return slowCases;
44 }
45
46 ALWAYS_INLINE MacroAssembler::JumpList JIT::emitLoadForArrayMode(Instruction* currentInstruction, JITArrayMode arrayMode, PatchableJump& badType)
47 {
48     switch (arrayMode) {
49     case JITInt32:
50         return emitInt32Load(currentInstruction, badType);
51     case JITDouble:
52         return emitDoubleLoad(currentInstruction, badType);
53     case JITContiguous:
54         return emitContiguousLoad(currentInstruction, badType);
55     case JITArrayStorage:
56         return emitArrayStorageLoad(currentInstruction, badType);
57     default:
58         break;
59     }
60     RELEASE_ASSERT_NOT_REACHED();
61     return MacroAssembler::JumpList();
62 }
63
64 inline MacroAssembler::JumpList JIT::emitContiguousGetByVal(Instruction* instruction, PatchableJump& badType, IndexingType expectedShape)
65 {
66     return emitContiguousLoad(instruction, badType, expectedShape);
67 }
68
69 inline MacroAssembler::JumpList JIT::emitArrayStorageGetByVal(Instruction* instruction, PatchableJump& badType)
70 {
71     return emitArrayStorageLoad(instruction, badType);
72 }
73
74 ALWAYS_INLINE bool JIT::isOperandConstantDouble(int src)
75 {
76     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isDouble();
77 }
78
79 ALWAYS_INLINE JSValue JIT::getConstantOperand(int src)
80 {
81     ASSERT(m_codeBlock->isConstantRegisterIndex(src));
82     return m_codeBlock->getConstant(src);
83 }
84
85 ALWAYS_INLINE void JIT::emitPutIntToCallFrameHeader(RegisterID from, int entry)
86 {
87 #if USE(JSVALUE32_64)
88     store32(TrustedImm32(JSValue::Int32Tag), tagFor(entry));
89     store32(from, payloadFor(entry));
90 #else
91     store64(from, addressFor(entry));
92 #endif
93 }
94
95 ALWAYS_INLINE void JIT::emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList& failures)
96 {
97     failures.append(branchIfNotString(src));
98     failures.append(branch32(NotEqual, MacroAssembler::Address(src, JSString::offsetOfLength()), TrustedImm32(1)));
99     loadPtr(MacroAssembler::Address(src, JSString::offsetOfValue()), dst);
100     failures.append(branchTest32(Zero, dst));
101     loadPtr(MacroAssembler::Address(dst, StringImpl::flagsOffset()), regT1);
102     loadPtr(MacroAssembler::Address(dst, StringImpl::dataOffset()), dst);
103
104     JumpList is16Bit;
105     JumpList cont8Bit;
106     is16Bit.append(branchTest32(Zero, regT1, TrustedImm32(StringImpl::flagIs8Bit())));
107     load8(MacroAssembler::Address(dst, 0), dst);
108     cont8Bit.append(jump());
109     is16Bit.link(this);
110     load16(MacroAssembler::Address(dst, 0), dst);
111     cont8Bit.link(this);
112 }
113
114 ALWAYS_INLINE JIT::Call JIT::emitNakedCall(CodePtr<NoPtrTag> target)
115 {
116     ASSERT(m_bytecodeOffset != std::numeric_limits<unsigned>::max()); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
117     Call nakedCall = nearCall();
118     m_calls.append(CallRecord(nakedCall, m_bytecodeOffset, FunctionPtr<OperationPtrTag>(target.retagged<OperationPtrTag>())));
119     return nakedCall;
120 }
121
122 ALWAYS_INLINE JIT::Call JIT::emitNakedTailCall(CodePtr<NoPtrTag> target)
123 {
124     ASSERT(m_bytecodeOffset != std::numeric_limits<unsigned>::max()); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
125     Call nakedCall = nearTailCall();
126     m_calls.append(CallRecord(nakedCall, m_bytecodeOffset, FunctionPtr<OperationPtrTag>(target.retagged<OperationPtrTag>())));
127     return nakedCall;
128 }
129
130 ALWAYS_INLINE void JIT::updateTopCallFrame()
131 {
132     ASSERT(static_cast<int>(m_bytecodeOffset) >= 0);
133 #if USE(JSVALUE32_64)
134     Instruction* instruction = &m_codeBlock->instructions()[m_bytecodeOffset]; 
135     uint32_t locationBits = CallSiteIndex(instruction).bits();
136 #else
137     uint32_t locationBits = CallSiteIndex(m_bytecodeOffset).bits();
138 #endif
139     store32(TrustedImm32(locationBits), tagFor(CallFrameSlot::argumentCount));
140     
141     // FIXME: It's not clear that this is needed. JITOperations tend to update the top call frame on
142     // the C++ side.
143     // https://bugs.webkit.org/show_bug.cgi?id=155693
144     storePtr(callFrameRegister, &m_vm->topCallFrame);
145 }
146
147 ALWAYS_INLINE MacroAssembler::Call JIT::appendCallWithExceptionCheck(const FunctionPtr<CFunctionPtrTag> function)
148 {
149     updateTopCallFrame();
150     MacroAssembler::Call call = appendCall(function);
151     exceptionCheck();
152     return call;
153 }
154
155 #if OS(WINDOWS) && CPU(X86_64)
156 ALWAYS_INLINE MacroAssembler::Call JIT::appendCallWithExceptionCheckAndSlowPathReturnType(const FunctionPtr<CFunctionPtrTag> function)
157 {
158     updateTopCallFrame();
159     MacroAssembler::Call call = appendCallWithSlowPathReturnType(function);
160     exceptionCheck();
161     return call;
162 }
163 #endif
164
165 ALWAYS_INLINE MacroAssembler::Call JIT::appendCallWithCallFrameRollbackOnException(const FunctionPtr<CFunctionPtrTag> function)
166 {
167     updateTopCallFrame(); // The callee is responsible for setting topCallFrame to their caller
168     MacroAssembler::Call call = appendCall(function);
169     exceptionCheckWithCallFrameRollback();
170     return call;
171 }
172
173 ALWAYS_INLINE MacroAssembler::Call JIT::appendCallWithExceptionCheckSetJSValueResult(const FunctionPtr<CFunctionPtrTag> function, int dst)
174 {
175     MacroAssembler::Call call = appendCallWithExceptionCheck(function);
176 #if USE(JSVALUE64)
177     emitPutVirtualRegister(dst, returnValueGPR);
178 #else
179     emitStore(dst, returnValueGPR2, returnValueGPR);
180 #endif
181     return call;
182 }
183
184 ALWAYS_INLINE MacroAssembler::Call JIT::appendCallWithExceptionCheckSetJSValueResultWithProfile(const FunctionPtr<CFunctionPtrTag> function, int dst)
185 {
186     MacroAssembler::Call call = appendCallWithExceptionCheck(function);
187     emitValueProfilingSite();
188 #if USE(JSVALUE64)
189     emitPutVirtualRegister(dst, returnValueGPR);
190 #else
191     emitStore(dst, returnValueGPR2, returnValueGPR);
192 #endif
193     return call;
194 }
195
196 ALWAYS_INLINE void JIT::linkSlowCaseIfNotJSCell(Vector<SlowCaseEntry>::iterator& iter, int vReg)
197 {
198     if (!m_codeBlock->isKnownNotImmediate(vReg))
199         linkSlowCase(iter);
200 }
201
202 ALWAYS_INLINE void JIT::linkAllSlowCasesForBytecodeOffset(Vector<SlowCaseEntry>& slowCases, Vector<SlowCaseEntry>::iterator& iter, unsigned bytecodeOffset)
203 {
204     while (iter != slowCases.end() && iter->to == bytecodeOffset)
205         linkSlowCase(iter);
206 }
207
208 ALWAYS_INLINE void JIT::addSlowCase(Jump jump)
209 {
210     ASSERT(m_bytecodeOffset != std::numeric_limits<unsigned>::max()); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
211
212     m_slowCases.append(SlowCaseEntry(jump, m_bytecodeOffset));
213 }
214
215 ALWAYS_INLINE void JIT::addSlowCase(const JumpList& jumpList)
216 {
217     ASSERT(m_bytecodeOffset != std::numeric_limits<unsigned>::max()); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
218
219     for (const Jump& jump : jumpList.jumps())
220         m_slowCases.append(SlowCaseEntry(jump, m_bytecodeOffset));
221 }
222
223 ALWAYS_INLINE void JIT::addSlowCase()
224 {
225     ASSERT(m_bytecodeOffset != std::numeric_limits<unsigned>::max()); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
226     
227     Jump emptyJump; // Doing it this way to make Windows happy.
228     m_slowCases.append(SlowCaseEntry(emptyJump, m_bytecodeOffset));
229 }
230
231 ALWAYS_INLINE void JIT::addJump(Jump jump, int relativeOffset)
232 {
233     ASSERT(m_bytecodeOffset != std::numeric_limits<unsigned>::max()); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
234
235     m_jmpTable.append(JumpTable(jump, m_bytecodeOffset + relativeOffset));
236 }
237
238 ALWAYS_INLINE void JIT::addJump(const JumpList& jumpList, int relativeOffset)
239 {
240     ASSERT(m_bytecodeOffset != std::numeric_limits<unsigned>::max()); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
241
242     for (auto& jump : jumpList.jumps())
243         addJump(jump, relativeOffset);
244 }
245
246 ALWAYS_INLINE void JIT::emitJumpSlowToHot(Jump jump, int relativeOffset)
247 {
248     ASSERT(m_bytecodeOffset != std::numeric_limits<unsigned>::max()); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
249
250     jump.linkTo(m_labels[m_bytecodeOffset + relativeOffset], this);
251 }
252
253 #if ENABLE(SAMPLING_FLAGS)
254 ALWAYS_INLINE void JIT::setSamplingFlag(int32_t flag)
255 {
256     ASSERT(flag >= 1);
257     ASSERT(flag <= 32);
258     or32(TrustedImm32(1u << (flag - 1)), AbsoluteAddress(SamplingFlags::addressOfFlags()));
259 }
260
261 ALWAYS_INLINE void JIT::clearSamplingFlag(int32_t flag)
262 {
263     ASSERT(flag >= 1);
264     ASSERT(flag <= 32);
265     and32(TrustedImm32(~(1u << (flag - 1))), AbsoluteAddress(SamplingFlags::addressOfFlags()));
266 }
267 #endif
268
269 #if ENABLE(SAMPLING_COUNTERS)
270 ALWAYS_INLINE void JIT::emitCount(AbstractSamplingCounter& counter, int32_t count)
271 {
272     add64(TrustedImm32(count), AbsoluteAddress(counter.addressOfCounter()));
273 }
274 #endif
275
276 #if ENABLE(OPCODE_SAMPLING)
277 #if CPU(X86_64)
278 ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction)
279 {
280     move(TrustedImmPtr(m_interpreter->sampler()->sampleSlot()), X86Registers::ecx);
281     storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), X86Registers::ecx);
282 }
283 #else
284 ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction)
285 {
286     storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), m_interpreter->sampler()->sampleSlot());
287 }
288 #endif
289 #endif
290
291 #if ENABLE(CODEBLOCK_SAMPLING)
292 #if CPU(X86_64)
293 ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock)
294 {
295     move(TrustedImmPtr(m_interpreter->sampler()->codeBlockSlot()), X86Registers::ecx);
296     storePtr(TrustedImmPtr(codeBlock), X86Registers::ecx);
297 }
298 #else
299 ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock)
300 {
301     storePtr(TrustedImmPtr(codeBlock), m_interpreter->sampler()->codeBlockSlot());
302 }
303 #endif
304 #endif
305
306 ALWAYS_INLINE bool JIT::isOperandConstantChar(int src)
307 {
308     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isString() && asString(getConstantOperand(src).asCell())->length() == 1;
309 }
310
311 inline void JIT::emitValueProfilingSite(ValueProfile& valueProfile)
312 {
313     ASSERT(shouldEmitProfiling());
314
315     const RegisterID value = regT0;
316 #if USE(JSVALUE32_64)
317     const RegisterID valueTag = regT1;
318 #endif
319     
320     // We're in a simple configuration: only one bucket, so we can just do a direct
321     // store.
322 #if USE(JSVALUE64)
323     store64(value, valueProfile.m_buckets);
324 #else
325     EncodedValueDescriptor* descriptor = bitwise_cast<EncodedValueDescriptor*>(valueProfile.m_buckets);
326     store32(value, &descriptor->asBits.payload);
327     store32(valueTag, &descriptor->asBits.tag);
328 #endif
329 }
330
331 inline void JIT::emitValueProfilingSite(unsigned bytecodeOffset)
332 {
333     if (!shouldEmitProfiling())
334         return;
335     emitValueProfilingSite(m_codeBlock->valueProfileForBytecodeOffset(bytecodeOffset));
336 }
337
338 inline void JIT::emitValueProfilingSite()
339 {
340     emitValueProfilingSite(m_bytecodeOffset);
341 }
342
343 inline void JIT::emitArrayProfilingSiteWithCell(RegisterID cell, RegisterID indexingType, ArrayProfile* arrayProfile)
344 {
345     if (shouldEmitProfiling()) {
346         load32(MacroAssembler::Address(cell, JSCell::structureIDOffset()), indexingType);
347         store32(indexingType, arrayProfile->addressOfLastSeenStructureID());
348     }
349
350     load8(Address(cell, JSCell::indexingTypeAndMiscOffset()), indexingType);
351 }
352
353 inline void JIT::emitArrayProfilingSiteForBytecodeIndexWithCell(RegisterID cell, RegisterID indexingType, unsigned bytecodeIndex)
354 {
355     emitArrayProfilingSiteWithCell(cell, indexingType, m_codeBlock->getOrAddArrayProfile(bytecodeIndex));
356 }
357
358 inline void JIT::emitArrayProfileStoreToHoleSpecialCase(ArrayProfile* arrayProfile)
359 {
360     store8(TrustedImm32(1), arrayProfile->addressOfMayStoreToHole());
361 }
362
363 inline void JIT::emitArrayProfileOutOfBoundsSpecialCase(ArrayProfile* arrayProfile)
364 {
365     store8(TrustedImm32(1), arrayProfile->addressOfOutOfBounds());
366 }
367
368 static inline bool arrayProfileSaw(ArrayModes arrayModes, IndexingType capability)
369 {
370     return arrayModesInclude(arrayModes, capability);
371 }
372
373 inline JITArrayMode JIT::chooseArrayMode(ArrayProfile* profile)
374 {
375     ConcurrentJSLocker locker(m_codeBlock->m_lock);
376     profile->computeUpdatedPrediction(locker, m_codeBlock);
377     ArrayModes arrayModes = profile->observedArrayModes(locker);
378     if (arrayProfileSaw(arrayModes, DoubleShape))
379         return JITDouble;
380     if (arrayProfileSaw(arrayModes, Int32Shape))
381         return JITInt32;
382     if (arrayProfileSaw(arrayModes, ArrayStorageShape))
383         return JITArrayStorage;
384     return JITContiguous;
385 }
386
387 ALWAYS_INLINE int32_t JIT::getOperandConstantInt(int src)
388 {
389     return getConstantOperand(src).asInt32();
390 }
391
392 ALWAYS_INLINE double JIT::getOperandConstantDouble(int src)
393 {
394     return getConstantOperand(src).asDouble();
395 }
396
397 ALWAYS_INLINE void JIT::emitInitRegister(int dst)
398 {
399     storeTrustedValue(jsUndefined(), addressFor(dst));
400 }
401
402 #if USE(JSVALUE32_64)
403
404 inline void JIT::emitLoadTag(int index, RegisterID tag)
405 {
406     if (m_codeBlock->isConstantRegisterIndex(index)) {
407         move(Imm32(getConstantOperand(index).tag()), tag);
408         return;
409     }
410
411     load32(tagFor(index), tag);
412 }
413
414 inline void JIT::emitLoadPayload(int index, RegisterID payload)
415 {
416     if (m_codeBlock->isConstantRegisterIndex(index)) {
417         move(Imm32(getConstantOperand(index).payload()), payload);
418         return;
419     }
420
421     load32(payloadFor(index), payload);
422 }
423
424 inline void JIT::emitLoad(const JSValue& v, RegisterID tag, RegisterID payload)
425 {
426     move(Imm32(v.payload()), payload);
427     move(Imm32(v.tag()), tag);
428 }
429
430 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, JSValueRegs dst)
431 {
432     emitLoad(src, dst.tagGPR(), dst.payloadGPR());
433 }
434
435 ALWAYS_INLINE void JIT::emitPutVirtualRegister(int dst, JSValueRegs from)
436 {
437     emitStore(dst, from.tagGPR(), from.payloadGPR());
438 }
439
440 inline void JIT::emitLoad(int index, RegisterID tag, RegisterID payload, RegisterID base)
441 {
442     RELEASE_ASSERT(tag != payload);
443
444     if (base == callFrameRegister) {
445         RELEASE_ASSERT(payload != base);
446         emitLoadPayload(index, payload);
447         emitLoadTag(index, tag);
448         return;
449     }
450
451     VirtualRegister target { index };
452     if (payload == base) { // avoid stomping base
453         load32(tagFor(target, base), tag);
454         load32(payloadFor(target, base), payload);
455         return;
456     }
457
458     load32(payloadFor(target, base), payload);
459     load32(tagFor(target, base), tag);
460 }
461
462 inline void JIT::emitLoad2(int index1, RegisterID tag1, RegisterID payload1, int index2, RegisterID tag2, RegisterID payload2)
463 {
464     emitLoad(index2, tag2, payload2);
465     emitLoad(index1, tag1, payload1);
466 }
467
468 inline void JIT::emitLoadDouble(int index, FPRegisterID value)
469 {
470     if (m_codeBlock->isConstantRegisterIndex(index)) {
471         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
472         loadDouble(TrustedImmPtr(&inConstantPool), value);
473     } else
474         loadDouble(addressFor(index), value);
475 }
476
477 inline void JIT::emitLoadInt32ToDouble(int index, FPRegisterID value)
478 {
479     if (m_codeBlock->isConstantRegisterIndex(index)) {
480         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
481         char* bytePointer = reinterpret_cast<char*>(&inConstantPool);
482         convertInt32ToDouble(AbsoluteAddress(bytePointer + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), value);
483     } else
484         convertInt32ToDouble(payloadFor(index), value);
485 }
486
487 inline void JIT::emitStore(int index, RegisterID tag, RegisterID payload, RegisterID base)
488 {
489     VirtualRegister target { index };
490     store32(payload, payloadFor(target, base));
491     store32(tag, tagFor(target, base));
492 }
493
494 inline void JIT::emitStoreInt32(int index, RegisterID payload, bool indexIsInt32)
495 {
496     store32(payload, payloadFor(index));
497     if (!indexIsInt32)
498         store32(TrustedImm32(JSValue::Int32Tag), tagFor(index));
499 }
500
501 inline void JIT::emitStoreInt32(int index, TrustedImm32 payload, bool indexIsInt32)
502 {
503     store32(payload, payloadFor(index));
504     if (!indexIsInt32)
505         store32(TrustedImm32(JSValue::Int32Tag), tagFor(index));
506 }
507
508 inline void JIT::emitStoreCell(int index, RegisterID payload, bool indexIsCell)
509 {
510     store32(payload, payloadFor(index));
511     if (!indexIsCell)
512         store32(TrustedImm32(JSValue::CellTag), tagFor(index));
513 }
514
515 inline void JIT::emitStoreBool(int index, RegisterID payload, bool indexIsBool)
516 {
517     store32(payload, payloadFor(index));
518     if (!indexIsBool)
519         store32(TrustedImm32(JSValue::BooleanTag), tagFor(index));
520 }
521
522 inline void JIT::emitStoreDouble(int index, FPRegisterID value)
523 {
524     storeDouble(value, addressFor(index));
525 }
526
527 inline void JIT::emitStore(int index, const JSValue constant, RegisterID base)
528 {
529     VirtualRegister target { index };
530     store32(Imm32(constant.payload()), payloadFor(target, base));
531     store32(Imm32(constant.tag()), tagFor(target, base));
532 }
533
534 inline void JIT::emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex)
535 {
536     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) {
537         if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
538             addSlowCase(jump());
539         else
540             addSlowCase(emitJumpIfNotJSCell(virtualRegisterIndex));
541     }
542 }
543
544 inline void JIT::emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex, RegisterID tag)
545 {
546     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) {
547         if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
548             addSlowCase(jump());
549         else
550             addSlowCase(branchIfNotCell(tag));
551     }
552 }
553
554 ALWAYS_INLINE bool JIT::isOperandConstantInt(int src)
555 {
556     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32();
557 }
558
559 ALWAYS_INLINE bool JIT::getOperandConstantInt(int op1, int op2, int& op, int32_t& constant)
560 {
561     if (isOperandConstantInt(op1)) {
562         constant = getConstantOperand(op1).asInt32();
563         op = op2;
564         return true;
565     }
566
567     if (isOperandConstantInt(op2)) {
568         constant = getConstantOperand(op2).asInt32();
569         op = op1;
570         return true;
571     }
572     
573     return false;
574 }
575
576 #else // USE(JSVALUE32_64)
577
578 // get arg puts an arg from the SF register array into a h/w register
579 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, RegisterID dst)
580 {
581     ASSERT(m_bytecodeOffset != std::numeric_limits<unsigned>::max()); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
582
583     if (m_codeBlock->isConstantRegisterIndex(src)) {
584         JSValue value = m_codeBlock->getConstant(src);
585         if (!value.isNumber())
586             move(TrustedImm64(JSValue::encode(value)), dst);
587         else
588             move(Imm64(JSValue::encode(value)), dst);
589         return;
590     }
591
592     load64(addressFor(src), dst);
593 }
594
595 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, JSValueRegs dst)
596 {
597     emitGetVirtualRegister(src, dst.payloadGPR());
598 }
599
600 ALWAYS_INLINE void JIT::emitGetVirtualRegister(VirtualRegister src, RegisterID dst)
601 {
602     emitGetVirtualRegister(src.offset(), dst);
603 }
604
605 ALWAYS_INLINE void JIT::emitGetVirtualRegisters(int src1, RegisterID dst1, int src2, RegisterID dst2)
606 {
607     emitGetVirtualRegister(src1, dst1);
608     emitGetVirtualRegister(src2, dst2);
609 }
610
611 ALWAYS_INLINE void JIT::emitGetVirtualRegisters(VirtualRegister src1, RegisterID dst1, VirtualRegister src2, RegisterID dst2)
612 {
613     emitGetVirtualRegisters(src1.offset(), dst1, src2.offset(), dst2);
614 }
615
616 ALWAYS_INLINE bool JIT::isOperandConstantInt(int src)
617 {
618     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32();
619 }
620
621 ALWAYS_INLINE void JIT::emitPutVirtualRegister(int dst, RegisterID from)
622 {
623     store64(from, addressFor(dst));
624 }
625
626 ALWAYS_INLINE void JIT::emitPutVirtualRegister(int dst, JSValueRegs from)
627 {
628     emitPutVirtualRegister(dst, from.payloadGPR());
629 }
630
631 ALWAYS_INLINE void JIT::emitPutVirtualRegister(VirtualRegister dst, RegisterID from)
632 {
633     emitPutVirtualRegister(dst.offset(), from);
634 }
635
636 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfBothJSCells(RegisterID reg1, RegisterID reg2, RegisterID scratch)
637 {
638     move(reg1, scratch);
639     or64(reg2, scratch);
640     return branchIfCell(scratch);
641 }
642
643 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfJSCell(RegisterID reg)
644 {
645     addSlowCase(branchIfCell(reg));
646 }
647
648 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg)
649 {
650     addSlowCase(branchIfNotCell(reg));
651 }
652
653 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, int vReg)
654 {
655     if (!m_codeBlock->isKnownNotImmediate(vReg))
656         emitJumpSlowCaseIfNotJSCell(reg);
657 }
658
659 inline void JIT::emitLoadDouble(int index, FPRegisterID value)
660 {
661     if (m_codeBlock->isConstantRegisterIndex(index)) {
662         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
663         loadDouble(TrustedImmPtr(&inConstantPool), value);
664     } else
665         loadDouble(addressFor(index), value);
666 }
667
668 inline void JIT::emitLoadInt32ToDouble(int index, FPRegisterID value)
669 {
670     if (m_codeBlock->isConstantRegisterIndex(index)) {
671         ASSERT(isOperandConstantInt(index));
672         convertInt32ToDouble(Imm32(getConstantOperand(index).asInt32()), value);
673     } else
674         convertInt32ToDouble(addressFor(index), value);
675 }
676
677 ALWAYS_INLINE JIT::PatchableJump JIT::emitPatchableJumpIfNotInt(RegisterID reg)
678 {
679     return patchableBranch64(Below, reg, tagTypeNumberRegister);
680 }
681
682 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotInt(RegisterID reg1, RegisterID reg2, RegisterID scratch)
683 {
684     move(reg1, scratch);
685     and64(reg2, scratch);
686     return branchIfNotInt32(scratch);
687 }
688
689 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotInt(RegisterID reg)
690 {
691     addSlowCase(branchIfNotInt32(reg));
692 }
693
694 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotInt(RegisterID reg1, RegisterID reg2, RegisterID scratch)
695 {
696     addSlowCase(emitJumpIfNotInt(reg1, reg2, scratch));
697 }
698
699 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotNumber(RegisterID reg)
700 {
701     addSlowCase(branchIfNotNumber(reg));
702 }
703
704 inline Instruction* JIT::copiedInstruction(Instruction* inst)
705 {
706     return &m_instructions[m_codeBlock->bytecodeOffset(inst)];
707 }
708
709 #endif // USE(JSVALUE32_64)
710
711 } // namespace JSC
712
713 #endif // ENABLE(JIT)