[JSC] Record CoW status in ArrayProfile
[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     if (shouldEmitProfiling())
352         or32(indexingType, AbsoluteAddress(arrayProfile->addressOfObservedIndexingModes()));
353 }
354
355 inline void JIT::emitArrayProfilingSiteForBytecodeIndexWithCell(RegisterID cell, RegisterID indexingType, unsigned bytecodeIndex)
356 {
357     emitArrayProfilingSiteWithCell(cell, indexingType, m_codeBlock->getOrAddArrayProfile(bytecodeIndex));
358 }
359
360 inline void JIT::emitArrayProfileStoreToHoleSpecialCase(ArrayProfile* arrayProfile)
361 {
362     store8(TrustedImm32(1), arrayProfile->addressOfMayStoreToHole());
363 }
364
365 inline void JIT::emitArrayProfileOutOfBoundsSpecialCase(ArrayProfile* arrayProfile)
366 {
367     store8(TrustedImm32(1), arrayProfile->addressOfOutOfBounds());
368 }
369
370 static inline bool arrayProfileSaw(ArrayModes arrayModes, IndexingType capability)
371 {
372     return arrayModesInclude(arrayModes, capability);
373 }
374
375 inline JITArrayMode JIT::chooseArrayMode(ArrayProfile* profile)
376 {
377     ConcurrentJSLocker locker(m_codeBlock->m_lock);
378     profile->computeUpdatedPrediction(locker, m_codeBlock);
379     ArrayModes arrayModes = profile->observedArrayModes(locker);
380     if (arrayProfileSaw(arrayModes, DoubleShape))
381         return JITDouble;
382     if (arrayProfileSaw(arrayModes, Int32Shape))
383         return JITInt32;
384     if (arrayProfileSaw(arrayModes, ArrayStorageShape))
385         return JITArrayStorage;
386     return JITContiguous;
387 }
388
389 ALWAYS_INLINE int32_t JIT::getOperandConstantInt(int src)
390 {
391     return getConstantOperand(src).asInt32();
392 }
393
394 ALWAYS_INLINE double JIT::getOperandConstantDouble(int src)
395 {
396     return getConstantOperand(src).asDouble();
397 }
398
399 ALWAYS_INLINE void JIT::emitInitRegister(int dst)
400 {
401     storeTrustedValue(jsUndefined(), addressFor(dst));
402 }
403
404 #if USE(JSVALUE32_64)
405
406 inline void JIT::emitLoadTag(int index, RegisterID tag)
407 {
408     if (m_codeBlock->isConstantRegisterIndex(index)) {
409         move(Imm32(getConstantOperand(index).tag()), tag);
410         return;
411     }
412
413     load32(tagFor(index), tag);
414 }
415
416 inline void JIT::emitLoadPayload(int index, RegisterID payload)
417 {
418     if (m_codeBlock->isConstantRegisterIndex(index)) {
419         move(Imm32(getConstantOperand(index).payload()), payload);
420         return;
421     }
422
423     load32(payloadFor(index), payload);
424 }
425
426 inline void JIT::emitLoad(const JSValue& v, RegisterID tag, RegisterID payload)
427 {
428     move(Imm32(v.payload()), payload);
429     move(Imm32(v.tag()), tag);
430 }
431
432 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, JSValueRegs dst)
433 {
434     emitLoad(src, dst.tagGPR(), dst.payloadGPR());
435 }
436
437 ALWAYS_INLINE void JIT::emitPutVirtualRegister(int dst, JSValueRegs from)
438 {
439     emitStore(dst, from.tagGPR(), from.payloadGPR());
440 }
441
442 inline void JIT::emitLoad(int index, RegisterID tag, RegisterID payload, RegisterID base)
443 {
444     RELEASE_ASSERT(tag != payload);
445
446     if (base == callFrameRegister) {
447         RELEASE_ASSERT(payload != base);
448         emitLoadPayload(index, payload);
449         emitLoadTag(index, tag);
450         return;
451     }
452
453     VirtualRegister target { index };
454     if (payload == base) { // avoid stomping base
455         load32(tagFor(target, base), tag);
456         load32(payloadFor(target, base), payload);
457         return;
458     }
459
460     load32(payloadFor(target, base), payload);
461     load32(tagFor(target, base), tag);
462 }
463
464 inline void JIT::emitLoad2(int index1, RegisterID tag1, RegisterID payload1, int index2, RegisterID tag2, RegisterID payload2)
465 {
466     emitLoad(index2, tag2, payload2);
467     emitLoad(index1, tag1, payload1);
468 }
469
470 inline void JIT::emitLoadDouble(int index, FPRegisterID value)
471 {
472     if (m_codeBlock->isConstantRegisterIndex(index)) {
473         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
474         loadDouble(TrustedImmPtr(&inConstantPool), value);
475     } else
476         loadDouble(addressFor(index), value);
477 }
478
479 inline void JIT::emitLoadInt32ToDouble(int index, FPRegisterID value)
480 {
481     if (m_codeBlock->isConstantRegisterIndex(index)) {
482         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
483         char* bytePointer = reinterpret_cast<char*>(&inConstantPool);
484         convertInt32ToDouble(AbsoluteAddress(bytePointer + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), value);
485     } else
486         convertInt32ToDouble(payloadFor(index), value);
487 }
488
489 inline void JIT::emitStore(int index, RegisterID tag, RegisterID payload, RegisterID base)
490 {
491     VirtualRegister target { index };
492     store32(payload, payloadFor(target, base));
493     store32(tag, tagFor(target, base));
494 }
495
496 inline void JIT::emitStoreInt32(int index, RegisterID payload, bool indexIsInt32)
497 {
498     store32(payload, payloadFor(index));
499     if (!indexIsInt32)
500         store32(TrustedImm32(JSValue::Int32Tag), tagFor(index));
501 }
502
503 inline void JIT::emitStoreInt32(int index, TrustedImm32 payload, bool indexIsInt32)
504 {
505     store32(payload, payloadFor(index));
506     if (!indexIsInt32)
507         store32(TrustedImm32(JSValue::Int32Tag), tagFor(index));
508 }
509
510 inline void JIT::emitStoreCell(int index, RegisterID payload, bool indexIsCell)
511 {
512     store32(payload, payloadFor(index));
513     if (!indexIsCell)
514         store32(TrustedImm32(JSValue::CellTag), tagFor(index));
515 }
516
517 inline void JIT::emitStoreBool(int index, RegisterID payload, bool indexIsBool)
518 {
519     store32(payload, payloadFor(index));
520     if (!indexIsBool)
521         store32(TrustedImm32(JSValue::BooleanTag), tagFor(index));
522 }
523
524 inline void JIT::emitStoreDouble(int index, FPRegisterID value)
525 {
526     storeDouble(value, addressFor(index));
527 }
528
529 inline void JIT::emitStore(int index, const JSValue constant, RegisterID base)
530 {
531     VirtualRegister target { index };
532     store32(Imm32(constant.payload()), payloadFor(target, base));
533     store32(Imm32(constant.tag()), tagFor(target, base));
534 }
535
536 inline void JIT::emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex)
537 {
538     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) {
539         if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
540             addSlowCase(jump());
541         else
542             addSlowCase(emitJumpIfNotJSCell(virtualRegisterIndex));
543     }
544 }
545
546 inline void JIT::emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex, RegisterID tag)
547 {
548     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) {
549         if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
550             addSlowCase(jump());
551         else
552             addSlowCase(branchIfNotCell(tag));
553     }
554 }
555
556 ALWAYS_INLINE bool JIT::isOperandConstantInt(int src)
557 {
558     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32();
559 }
560
561 ALWAYS_INLINE bool JIT::getOperandConstantInt(int op1, int op2, int& op, int32_t& constant)
562 {
563     if (isOperandConstantInt(op1)) {
564         constant = getConstantOperand(op1).asInt32();
565         op = op2;
566         return true;
567     }
568
569     if (isOperandConstantInt(op2)) {
570         constant = getConstantOperand(op2).asInt32();
571         op = op1;
572         return true;
573     }
574     
575     return false;
576 }
577
578 #else // USE(JSVALUE32_64)
579
580 // get arg puts an arg from the SF register array into a h/w register
581 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, RegisterID dst)
582 {
583     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.
584
585     if (m_codeBlock->isConstantRegisterIndex(src)) {
586         JSValue value = m_codeBlock->getConstant(src);
587         if (!value.isNumber())
588             move(TrustedImm64(JSValue::encode(value)), dst);
589         else
590             move(Imm64(JSValue::encode(value)), dst);
591         return;
592     }
593
594     load64(addressFor(src), dst);
595 }
596
597 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, JSValueRegs dst)
598 {
599     emitGetVirtualRegister(src, dst.payloadGPR());
600 }
601
602 ALWAYS_INLINE void JIT::emitGetVirtualRegister(VirtualRegister src, RegisterID dst)
603 {
604     emitGetVirtualRegister(src.offset(), dst);
605 }
606
607 ALWAYS_INLINE void JIT::emitGetVirtualRegisters(int src1, RegisterID dst1, int src2, RegisterID dst2)
608 {
609     emitGetVirtualRegister(src1, dst1);
610     emitGetVirtualRegister(src2, dst2);
611 }
612
613 ALWAYS_INLINE void JIT::emitGetVirtualRegisters(VirtualRegister src1, RegisterID dst1, VirtualRegister src2, RegisterID dst2)
614 {
615     emitGetVirtualRegisters(src1.offset(), dst1, src2.offset(), dst2);
616 }
617
618 ALWAYS_INLINE bool JIT::isOperandConstantInt(int src)
619 {
620     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32();
621 }
622
623 ALWAYS_INLINE void JIT::emitPutVirtualRegister(int dst, RegisterID from)
624 {
625     store64(from, addressFor(dst));
626 }
627
628 ALWAYS_INLINE void JIT::emitPutVirtualRegister(int dst, JSValueRegs from)
629 {
630     emitPutVirtualRegister(dst, from.payloadGPR());
631 }
632
633 ALWAYS_INLINE void JIT::emitPutVirtualRegister(VirtualRegister dst, RegisterID from)
634 {
635     emitPutVirtualRegister(dst.offset(), from);
636 }
637
638 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfBothJSCells(RegisterID reg1, RegisterID reg2, RegisterID scratch)
639 {
640     move(reg1, scratch);
641     or64(reg2, scratch);
642     return branchIfCell(scratch);
643 }
644
645 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfJSCell(RegisterID reg)
646 {
647     addSlowCase(branchIfCell(reg));
648 }
649
650 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg)
651 {
652     addSlowCase(branchIfNotCell(reg));
653 }
654
655 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, int vReg)
656 {
657     if (!m_codeBlock->isKnownNotImmediate(vReg))
658         emitJumpSlowCaseIfNotJSCell(reg);
659 }
660
661 inline void JIT::emitLoadDouble(int index, FPRegisterID value)
662 {
663     if (m_codeBlock->isConstantRegisterIndex(index)) {
664         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
665         loadDouble(TrustedImmPtr(&inConstantPool), value);
666     } else
667         loadDouble(addressFor(index), value);
668 }
669
670 inline void JIT::emitLoadInt32ToDouble(int index, FPRegisterID value)
671 {
672     if (m_codeBlock->isConstantRegisterIndex(index)) {
673         ASSERT(isOperandConstantInt(index));
674         convertInt32ToDouble(Imm32(getConstantOperand(index).asInt32()), value);
675     } else
676         convertInt32ToDouble(addressFor(index), value);
677 }
678
679 ALWAYS_INLINE JIT::PatchableJump JIT::emitPatchableJumpIfNotInt(RegisterID reg)
680 {
681     return patchableBranch64(Below, reg, tagTypeNumberRegister);
682 }
683
684 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotInt(RegisterID reg1, RegisterID reg2, RegisterID scratch)
685 {
686     move(reg1, scratch);
687     and64(reg2, scratch);
688     return branchIfNotInt32(scratch);
689 }
690
691 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotInt(RegisterID reg)
692 {
693     addSlowCase(branchIfNotInt32(reg));
694 }
695
696 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotInt(RegisterID reg1, RegisterID reg2, RegisterID scratch)
697 {
698     addSlowCase(emitJumpIfNotInt(reg1, reg2, scratch));
699 }
700
701 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotNumber(RegisterID reg)
702 {
703     addSlowCase(branchIfNotNumber(reg));
704 }
705
706 inline Instruction* JIT::copiedInstruction(Instruction* inst)
707 {
708     return &m_instructions[m_codeBlock->bytecodeOffset(inst)];
709 }
710
711 #endif // USE(JSVALUE32_64)
712
713 } // namespace JSC
714
715 #endif // ENABLE(JIT)