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