[Baseline] Store constant directly in emit_op_mov
[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::emitJumpSlowToHot(Jump jump, 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     jump.linkTo(m_labels[m_bytecodeOffset + relativeOffset], this);
243 }
244
245 #if ENABLE(SAMPLING_FLAGS)
246 ALWAYS_INLINE void JIT::setSamplingFlag(int32_t flag)
247 {
248     ASSERT(flag >= 1);
249     ASSERT(flag <= 32);
250     or32(TrustedImm32(1u << (flag - 1)), AbsoluteAddress(SamplingFlags::addressOfFlags()));
251 }
252
253 ALWAYS_INLINE void JIT::clearSamplingFlag(int32_t flag)
254 {
255     ASSERT(flag >= 1);
256     ASSERT(flag <= 32);
257     and32(TrustedImm32(~(1u << (flag - 1))), AbsoluteAddress(SamplingFlags::addressOfFlags()));
258 }
259 #endif
260
261 #if ENABLE(SAMPLING_COUNTERS)
262 ALWAYS_INLINE void JIT::emitCount(AbstractSamplingCounter& counter, int32_t count)
263 {
264     add64(TrustedImm32(count), AbsoluteAddress(counter.addressOfCounter()));
265 }
266 #endif
267
268 #if ENABLE(OPCODE_SAMPLING)
269 #if CPU(X86_64)
270 ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction)
271 {
272     move(TrustedImmPtr(m_interpreter->sampler()->sampleSlot()), X86Registers::ecx);
273     storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), X86Registers::ecx);
274 }
275 #else
276 ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction)
277 {
278     storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), m_interpreter->sampler()->sampleSlot());
279 }
280 #endif
281 #endif
282
283 #if ENABLE(CODEBLOCK_SAMPLING)
284 #if CPU(X86_64)
285 ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock)
286 {
287     move(TrustedImmPtr(m_interpreter->sampler()->codeBlockSlot()), X86Registers::ecx);
288     storePtr(TrustedImmPtr(codeBlock), X86Registers::ecx);
289 }
290 #else
291 ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock)
292 {
293     storePtr(TrustedImmPtr(codeBlock), m_interpreter->sampler()->codeBlockSlot());
294 }
295 #endif
296 #endif
297
298 ALWAYS_INLINE bool JIT::isOperandConstantChar(int src)
299 {
300     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isString() && asString(getConstantOperand(src).asCell())->length() == 1;
301 }
302
303 inline void JIT::emitValueProfilingSite(ValueProfile& valueProfile)
304 {
305     ASSERT(shouldEmitProfiling());
306
307     const RegisterID value = regT0;
308 #if USE(JSVALUE32_64)
309     const RegisterID valueTag = regT1;
310 #endif
311     
312     // We're in a simple configuration: only one bucket, so we can just do a direct
313     // store.
314 #if USE(JSVALUE64)
315     store64(value, valueProfile.m_buckets);
316 #else
317     EncodedValueDescriptor* descriptor = bitwise_cast<EncodedValueDescriptor*>(valueProfile.m_buckets);
318     store32(value, &descriptor->asBits.payload);
319     store32(valueTag, &descriptor->asBits.tag);
320 #endif
321 }
322
323 inline void JIT::emitValueProfilingSite(unsigned bytecodeOffset)
324 {
325     if (!shouldEmitProfiling())
326         return;
327     emitValueProfilingSite(m_codeBlock->valueProfileForBytecodeOffset(bytecodeOffset));
328 }
329
330 inline void JIT::emitValueProfilingSite()
331 {
332     emitValueProfilingSite(m_bytecodeOffset);
333 }
334
335 inline void JIT::emitArrayProfilingSiteWithCell(RegisterID cell, RegisterID indexingType, ArrayProfile* arrayProfile)
336 {
337     if (shouldEmitProfiling()) {
338         load32(MacroAssembler::Address(cell, JSCell::structureIDOffset()), indexingType);
339         store32(indexingType, arrayProfile->addressOfLastSeenStructureID());
340     }
341
342     load8(Address(cell, JSCell::indexingTypeAndMiscOffset()), indexingType);
343 }
344
345 inline void JIT::emitArrayProfilingSiteForBytecodeIndexWithCell(RegisterID cell, RegisterID indexingType, unsigned bytecodeIndex)
346 {
347     emitArrayProfilingSiteWithCell(cell, indexingType, m_codeBlock->getOrAddArrayProfile(bytecodeIndex));
348 }
349
350 inline void JIT::emitArrayProfileStoreToHoleSpecialCase(ArrayProfile* arrayProfile)
351 {
352     store8(TrustedImm32(1), arrayProfile->addressOfMayStoreToHole());
353 }
354
355 inline void JIT::emitArrayProfileOutOfBoundsSpecialCase(ArrayProfile* arrayProfile)
356 {
357     store8(TrustedImm32(1), arrayProfile->addressOfOutOfBounds());
358 }
359
360 static inline bool arrayProfileSaw(ArrayModes arrayModes, IndexingType capability)
361 {
362     return arrayModesInclude(arrayModes, capability);
363 }
364
365 inline JITArrayMode JIT::chooseArrayMode(ArrayProfile* profile)
366 {
367     ConcurrentJSLocker locker(m_codeBlock->m_lock);
368     profile->computeUpdatedPrediction(locker, m_codeBlock);
369     ArrayModes arrayModes = profile->observedArrayModes(locker);
370     if (arrayProfileSaw(arrayModes, DoubleShape))
371         return JITDouble;
372     if (arrayProfileSaw(arrayModes, Int32Shape))
373         return JITInt32;
374     if (arrayProfileSaw(arrayModes, ArrayStorageShape))
375         return JITArrayStorage;
376     return JITContiguous;
377 }
378
379 ALWAYS_INLINE int32_t JIT::getOperandConstantInt(int src)
380 {
381     return getConstantOperand(src).asInt32();
382 }
383
384 ALWAYS_INLINE double JIT::getOperandConstantDouble(int src)
385 {
386     return getConstantOperand(src).asDouble();
387 }
388
389 ALWAYS_INLINE void JIT::emitInitRegister(int dst)
390 {
391     storeTrustedValue(jsUndefined(), addressFor(dst));
392 }
393
394 #if USE(JSVALUE32_64)
395
396 inline void JIT::emitLoadTag(int index, RegisterID tag)
397 {
398     if (m_codeBlock->isConstantRegisterIndex(index)) {
399         move(Imm32(getConstantOperand(index).tag()), tag);
400         return;
401     }
402
403     load32(tagFor(index), tag);
404 }
405
406 inline void JIT::emitLoadPayload(int index, RegisterID payload)
407 {
408     if (m_codeBlock->isConstantRegisterIndex(index)) {
409         move(Imm32(getConstantOperand(index).payload()), payload);
410         return;
411     }
412
413     load32(payloadFor(index), payload);
414 }
415
416 inline void JIT::emitLoad(const JSValue& v, RegisterID tag, RegisterID payload)
417 {
418     move(Imm32(v.payload()), payload);
419     move(Imm32(v.tag()), tag);
420 }
421
422 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, JSValueRegs dst)
423 {
424     emitLoad(src, dst.tagGPR(), dst.payloadGPR());
425 }
426
427 ALWAYS_INLINE void JIT::emitPutVirtualRegister(int dst, JSValueRegs from)
428 {
429     emitStore(dst, from.tagGPR(), from.payloadGPR());
430 }
431
432 inline void JIT::emitLoad(int index, RegisterID tag, RegisterID payload, RegisterID base)
433 {
434     RELEASE_ASSERT(tag != payload);
435
436     if (base == callFrameRegister) {
437         RELEASE_ASSERT(payload != base);
438         emitLoadPayload(index, payload);
439         emitLoadTag(index, tag);
440         return;
441     }
442
443     VirtualRegister target { index };
444     if (payload == base) { // avoid stomping base
445         load32(tagFor(target, base), tag);
446         load32(payloadFor(target, base), payload);
447         return;
448     }
449
450     load32(payloadFor(target, base), payload);
451     load32(tagFor(target, base), tag);
452 }
453
454 inline void JIT::emitLoad2(int index1, RegisterID tag1, RegisterID payload1, int index2, RegisterID tag2, RegisterID payload2)
455 {
456     emitLoad(index2, tag2, payload2);
457     emitLoad(index1, tag1, payload1);
458 }
459
460 inline void JIT::emitLoadDouble(int index, FPRegisterID value)
461 {
462     if (m_codeBlock->isConstantRegisterIndex(index)) {
463         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
464         loadDouble(TrustedImmPtr(&inConstantPool), value);
465     } else
466         loadDouble(addressFor(index), value);
467 }
468
469 inline void JIT::emitLoadInt32ToDouble(int index, FPRegisterID value)
470 {
471     if (m_codeBlock->isConstantRegisterIndex(index)) {
472         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
473         char* bytePointer = reinterpret_cast<char*>(&inConstantPool);
474         convertInt32ToDouble(AbsoluteAddress(bytePointer + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), value);
475     } else
476         convertInt32ToDouble(payloadFor(index), value);
477 }
478
479 inline void JIT::emitStore(int index, RegisterID tag, RegisterID payload, RegisterID base)
480 {
481     VirtualRegister target { index };
482     store32(payload, payloadFor(target, base));
483     store32(tag, tagFor(target, base));
484 }
485
486 inline void JIT::emitStoreInt32(int index, RegisterID payload, bool indexIsInt32)
487 {
488     store32(payload, payloadFor(index));
489     if (!indexIsInt32)
490         store32(TrustedImm32(JSValue::Int32Tag), tagFor(index));
491 }
492
493 inline void JIT::emitStoreInt32(int index, TrustedImm32 payload, bool indexIsInt32)
494 {
495     store32(payload, payloadFor(index));
496     if (!indexIsInt32)
497         store32(TrustedImm32(JSValue::Int32Tag), tagFor(index));
498 }
499
500 inline void JIT::emitStoreCell(int index, RegisterID payload, bool indexIsCell)
501 {
502     store32(payload, payloadFor(index));
503     if (!indexIsCell)
504         store32(TrustedImm32(JSValue::CellTag), tagFor(index));
505 }
506
507 inline void JIT::emitStoreBool(int index, RegisterID payload, bool indexIsBool)
508 {
509     store32(payload, payloadFor(index));
510     if (!indexIsBool)
511         store32(TrustedImm32(JSValue::BooleanTag), tagFor(index));
512 }
513
514 inline void JIT::emitStoreDouble(int index, FPRegisterID value)
515 {
516     storeDouble(value, addressFor(index));
517 }
518
519 inline void JIT::emitStore(int index, const JSValue constant, RegisterID base)
520 {
521     VirtualRegister target { index };
522     store32(Imm32(constant.payload()), payloadFor(target, base));
523     store32(Imm32(constant.tag()), tagFor(target, base));
524 }
525
526 inline void JIT::emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex)
527 {
528     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) {
529         if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
530             addSlowCase(jump());
531         else
532             addSlowCase(emitJumpIfNotJSCell(virtualRegisterIndex));
533     }
534 }
535
536 inline void JIT::emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex, RegisterID tag)
537 {
538     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) {
539         if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
540             addSlowCase(jump());
541         else
542             addSlowCase(branchIfNotCell(tag));
543     }
544 }
545
546 ALWAYS_INLINE bool JIT::isOperandConstantInt(int src)
547 {
548     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32();
549 }
550
551 ALWAYS_INLINE bool JIT::getOperandConstantInt(int op1, int op2, int& op, int32_t& constant)
552 {
553     if (isOperandConstantInt(op1)) {
554         constant = getConstantOperand(op1).asInt32();
555         op = op2;
556         return true;
557     }
558
559     if (isOperandConstantInt(op2)) {
560         constant = getConstantOperand(op2).asInt32();
561         op = op1;
562         return true;
563     }
564     
565     return false;
566 }
567
568 #else // USE(JSVALUE32_64)
569
570 // get arg puts an arg from the SF register array into a h/w register
571 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, RegisterID dst)
572 {
573     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.
574
575     if (m_codeBlock->isConstantRegisterIndex(src)) {
576         JSValue value = m_codeBlock->getConstant(src);
577         if (!value.isNumber())
578             move(TrustedImm64(JSValue::encode(value)), dst);
579         else
580             move(Imm64(JSValue::encode(value)), dst);
581         return;
582     }
583
584     load64(addressFor(src), dst);
585 }
586
587 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, JSValueRegs dst)
588 {
589     emitGetVirtualRegister(src, dst.payloadGPR());
590 }
591
592 ALWAYS_INLINE void JIT::emitGetVirtualRegister(VirtualRegister src, RegisterID dst)
593 {
594     emitGetVirtualRegister(src.offset(), dst);
595 }
596
597 ALWAYS_INLINE void JIT::emitGetVirtualRegisters(int src1, RegisterID dst1, int src2, RegisterID dst2)
598 {
599     emitGetVirtualRegister(src1, dst1);
600     emitGetVirtualRegister(src2, dst2);
601 }
602
603 ALWAYS_INLINE void JIT::emitGetVirtualRegisters(VirtualRegister src1, RegisterID dst1, VirtualRegister src2, RegisterID dst2)
604 {
605     emitGetVirtualRegisters(src1.offset(), dst1, src2.offset(), dst2);
606 }
607
608 ALWAYS_INLINE bool JIT::isOperandConstantInt(int src)
609 {
610     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32();
611 }
612
613 ALWAYS_INLINE void JIT::emitPutVirtualRegister(int dst, RegisterID from)
614 {
615     store64(from, addressFor(dst));
616 }
617
618 ALWAYS_INLINE void JIT::emitPutVirtualRegister(int dst, JSValueRegs from)
619 {
620     emitPutVirtualRegister(dst, from.payloadGPR());
621 }
622
623 ALWAYS_INLINE void JIT::emitPutVirtualRegister(VirtualRegister dst, RegisterID from)
624 {
625     emitPutVirtualRegister(dst.offset(), from);
626 }
627
628 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfBothJSCells(RegisterID reg1, RegisterID reg2, RegisterID scratch)
629 {
630     move(reg1, scratch);
631     or64(reg2, scratch);
632     return branchIfCell(scratch);
633 }
634
635 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfJSCell(RegisterID reg)
636 {
637     addSlowCase(branchIfCell(reg));
638 }
639
640 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg)
641 {
642     addSlowCase(branchIfNotCell(reg));
643 }
644
645 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, int vReg)
646 {
647     if (!m_codeBlock->isKnownNotImmediate(vReg))
648         emitJumpSlowCaseIfNotJSCell(reg);
649 }
650
651 inline void JIT::emitLoadDouble(int index, FPRegisterID value)
652 {
653     if (m_codeBlock->isConstantRegisterIndex(index)) {
654         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
655         loadDouble(TrustedImmPtr(&inConstantPool), value);
656     } else
657         loadDouble(addressFor(index), value);
658 }
659
660 inline void JIT::emitLoadInt32ToDouble(int index, FPRegisterID value)
661 {
662     if (m_codeBlock->isConstantRegisterIndex(index)) {
663         ASSERT(isOperandConstantInt(index));
664         convertInt32ToDouble(Imm32(getConstantOperand(index).asInt32()), value);
665     } else
666         convertInt32ToDouble(addressFor(index), value);
667 }
668
669 ALWAYS_INLINE JIT::PatchableJump JIT::emitPatchableJumpIfNotInt(RegisterID reg)
670 {
671     return patchableBranch64(Below, reg, tagTypeNumberRegister);
672 }
673
674 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotInt(RegisterID reg1, RegisterID reg2, RegisterID scratch)
675 {
676     move(reg1, scratch);
677     and64(reg2, scratch);
678     return branchIfNotInt32(scratch);
679 }
680
681 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotInt(RegisterID reg)
682 {
683     addSlowCase(branchIfNotInt32(reg));
684 }
685
686 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotInt(RegisterID reg1, RegisterID reg2, RegisterID scratch)
687 {
688     addSlowCase(emitJumpIfNotInt(reg1, reg2, scratch));
689 }
690
691 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotNumber(RegisterID reg)
692 {
693     addSlowCase(branchIfNotNumber(reg));
694 }
695
696 inline Instruction* JIT::copiedInstruction(Instruction* inst)
697 {
698     return &m_instructions[m_codeBlock->bytecodeOffset(inst)];
699 }
700
701 #endif // USE(JSVALUE32_64)
702
703 } // namespace JSC
704
705 #endif // ENABLE(JIT)