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