8d02157586dd19be6c8e263ed7f86b1360bab6b9
[WebKit-https.git] / Source / JavaScriptCore / jit / JITInlines.h
1 /*
2  * Copyright (C) 2008, 2012, 2013 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 #ifndef JITInlines_h
27 #define JITInlines_h
28
29
30 #if ENABLE(JIT)
31
32 #include "CallFrameInlines.h"
33
34 namespace JSC {
35
36 ALWAYS_INLINE bool JIT::isOperandConstantImmediateDouble(int src)
37 {
38     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isDouble();
39 }
40
41 ALWAYS_INLINE JSValue JIT::getConstantOperand(int src)
42 {
43     ASSERT(m_codeBlock->isConstantRegisterIndex(src));
44     return m_codeBlock->getConstant(src);
45 }
46
47 ALWAYS_INLINE void JIT::emitPutIntToCallFrameHeader(RegisterID from, JSStack::CallFrameHeaderEntry entry)
48 {
49 #if USE(JSVALUE32_64)
50     store32(TrustedImm32(Int32Tag), intTagFor(entry, callFrameRegister));
51     store32(from, intPayloadFor(entry, callFrameRegister));
52 #else
53     store64(from, addressFor(entry, callFrameRegister));
54 #endif
55 }
56
57 ALWAYS_INLINE void JIT::emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry, RegisterID to, RegisterID from)
58 {
59     loadPtr(Address(from, entry * sizeof(Register)), to);
60 #if USE(JSVALUE64)
61     killLastResultRegister();
62 #endif
63 }
64
65 ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader32(JSStack::CallFrameHeaderEntry entry, RegisterID to, RegisterID from)
66 {
67     load32(Address(from, entry * sizeof(Register)), to);
68 #if USE(JSVALUE64)
69     killLastResultRegister();
70 #endif
71 }
72
73 #if USE(JSVALUE64)
74 ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader64(JSStack::CallFrameHeaderEntry entry, RegisterID to, RegisterID from)
75 {
76     load64(Address(from, entry * sizeof(Register)), to);
77     killLastResultRegister();
78 }
79 #endif
80
81 ALWAYS_INLINE void JIT::emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList& failures)
82 {
83     failures.append(branchPtr(NotEqual, Address(src, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get())));
84     failures.append(branch32(NotEqual, MacroAssembler::Address(src, ThunkHelpers::jsStringLengthOffset()), TrustedImm32(1)));
85     loadPtr(MacroAssembler::Address(src, ThunkHelpers::jsStringValueOffset()), dst);
86     failures.append(branchTest32(Zero, dst));
87     loadPtr(MacroAssembler::Address(dst, StringImpl::flagsOffset()), regT1);
88     loadPtr(MacroAssembler::Address(dst, StringImpl::dataOffset()), dst);
89
90     JumpList is16Bit;
91     JumpList cont8Bit;
92     is16Bit.append(branchTest32(Zero, regT1, TrustedImm32(StringImpl::flagIs8Bit())));
93     load8(MacroAssembler::Address(dst, 0), dst);
94     cont8Bit.append(jump());
95     is16Bit.link(this);
96     load16(MacroAssembler::Address(dst, 0), dst);
97     cont8Bit.link(this);
98 }
99
100 ALWAYS_INLINE JIT::Call JIT::emitNakedCall(CodePtr function)
101 {
102     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
103
104     Call nakedCall = nearCall();
105     m_calls.append(CallRecord(nakedCall, m_bytecodeOffset, function.executableAddress()));
106     return nakedCall;
107 }
108
109 ALWAYS_INLINE bool JIT::atJumpTarget()
110 {
111     while (m_jumpTargetsPosition < m_codeBlock->numberOfJumpTargets() && m_codeBlock->jumpTarget(m_jumpTargetsPosition) <= m_bytecodeOffset) {
112         if (m_codeBlock->jumpTarget(m_jumpTargetsPosition) == m_bytecodeOffset)
113             return true;
114         ++m_jumpTargetsPosition;
115     }
116     return false;
117 }
118
119 #if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
120
121 ALWAYS_INLINE void JIT::beginUninterruptedSequence(int insnSpace, int constSpace)
122 {
123 #if CPU(ARM_TRADITIONAL)
124 #ifndef NDEBUG
125     // Ensure the label after the sequence can also fit
126     insnSpace += sizeof(ARMWord);
127     constSpace += sizeof(uint64_t);
128 #endif
129
130     ensureSpace(insnSpace, constSpace);
131
132 #elif CPU(SH4)
133 #ifndef NDEBUG
134     insnSpace += sizeof(SH4Word);
135     constSpace += sizeof(uint64_t);
136 #endif
137
138     m_assembler.ensureSpace(insnSpace + m_assembler.maxInstructionSize + 2, constSpace + 8);
139 #endif
140
141 #ifndef NDEBUG
142     m_uninterruptedInstructionSequenceBegin = label();
143     m_uninterruptedConstantSequenceBegin = sizeOfConstantPool();
144 #endif
145 }
146
147 ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace, int dst)
148 {
149 #ifndef NDEBUG
150     /* There are several cases when the uninterrupted sequence is larger than
151      * maximum required offset for pathing the same sequence. Eg.: if in a
152      * uninterrupted sequence the last macroassembler's instruction is a stub
153      * call, it emits store instruction(s) which should not be included in the
154      * calculation of length of uninterrupted sequence. So, the insnSpace and
155      * constSpace should be upper limit instead of hard limit.
156      */
157
158 #if CPU(SH4)
159     if ((dst > 15) || (dst < -16)) {
160         insnSpace += 8;
161         constSpace += 2;
162     }
163
164     if (((dst >= -16) && (dst < 0)) || ((dst > 7) && (dst <= 15)))
165         insnSpace += 8;
166 #else
167     UNUSED_PARAM(dst);
168 #endif
169
170     ASSERT(differenceBetween(m_uninterruptedInstructionSequenceBegin, label()) <= insnSpace);
171     ASSERT(sizeOfConstantPool() - m_uninterruptedConstantSequenceBegin <= constSpace);
172 #else
173     UNUSED_PARAM(insnSpace);
174     UNUSED_PARAM(constSpace);
175     UNUSED_PARAM(dst);
176 #endif
177 }
178
179 #endif // ASSEMBLER_HAS_CONSTANT_POOL
180
181 ALWAYS_INLINE void JIT::updateTopCallFrame()
182 {
183     ASSERT(static_cast<int>(m_bytecodeOffset) >= 0);
184 #if USE(JSVALUE32_64)
185     Instruction* instruction = m_codeBlock->instructions().begin() + m_bytecodeOffset + 1; 
186     uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction);
187 #else
188     uint32_t locationBits = CallFrame::Location::encodeAsBytecodeOffset(m_bytecodeOffset + 1);
189 #endif
190     store32(TrustedImm32(locationBits), intTagFor(JSStack::ArgumentCount));
191     storePtr(callFrameRegister, &m_vm->topCallFrame);
192 }
193
194 ALWAYS_INLINE void JIT::restoreArgumentReferenceForTrampoline()
195 {
196 #if CPU(X86)
197     // Within a trampoline the return address will be on the stack at this point.
198     addPtr(TrustedImm32(sizeof(void*)), stackPointerRegister, firstArgumentRegister);
199 #elif CPU(ARM)
200     move(stackPointerRegister, firstArgumentRegister);
201 #elif CPU(SH4)
202     move(stackPointerRegister, firstArgumentRegister);
203 #endif
204     // In the trampoline on x86-64, the first argument register is not overwritten.
205 }
206
207 ALWAYS_INLINE JIT::Jump JIT::checkStructure(RegisterID reg, Structure* structure)
208 {
209     return branchPtr(NotEqual, Address(reg, JSCell::structureOffset()), TrustedImmPtr(structure));
210 }
211
212 ALWAYS_INLINE void JIT::linkSlowCaseIfNotJSCell(Vector<SlowCaseEntry>::iterator& iter, int vReg)
213 {
214     if (!m_codeBlock->isKnownNotImmediate(vReg))
215         linkSlowCase(iter);
216 }
217
218 ALWAYS_INLINE void JIT::addSlowCase(Jump jump)
219 {
220     ASSERT(m_bytecodeOffset != (unsigned)-1); // 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(JumpList jumpList)
226 {
227     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
228
229     const JumpList::JumpVector& jumpVector = jumpList.jumps();
230     size_t size = jumpVector.size();
231     for (size_t i = 0; i < size; ++i)
232         m_slowCases.append(SlowCaseEntry(jumpVector[i], m_bytecodeOffset));
233 }
234
235 ALWAYS_INLINE void JIT::addSlowCase()
236 {
237     ASSERT(m_bytecodeOffset != (unsigned)-1); // 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 != (unsigned)-1); // 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 != (unsigned)-1); // 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::emitJumpIfNotObject(RegisterID structureReg)
258 {
259     return branch8(Below, Address(structureReg, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
260 }
261
262 #if ENABLE(SAMPLING_FLAGS)
263 ALWAYS_INLINE void JIT::setSamplingFlag(int32_t flag)
264 {
265     ASSERT(flag >= 1);
266     ASSERT(flag <= 32);
267     or32(TrustedImm32(1u << (flag - 1)), AbsoluteAddress(SamplingFlags::addressOfFlags()));
268 }
269
270 ALWAYS_INLINE void JIT::clearSamplingFlag(int32_t flag)
271 {
272     ASSERT(flag >= 1);
273     ASSERT(flag <= 32);
274     and32(TrustedImm32(~(1u << (flag - 1))), AbsoluteAddress(SamplingFlags::addressOfFlags()));
275 }
276 #endif
277
278 #if ENABLE(SAMPLING_COUNTERS)
279 ALWAYS_INLINE void JIT::emitCount(AbstractSamplingCounter& counter, int32_t count)
280 {
281     add64(TrustedImm32(count), AbsoluteAddress(counter.addressOfCounter()));
282 }
283 #endif
284
285 #if ENABLE(OPCODE_SAMPLING)
286 #if CPU(X86_64)
287 ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction)
288 {
289     move(TrustedImmPtr(m_interpreter->sampler()->sampleSlot()), X86Registers::ecx);
290     storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), X86Registers::ecx);
291 }
292 #else
293 ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction)
294 {
295     storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), m_interpreter->sampler()->sampleSlot());
296 }
297 #endif
298 #endif
299
300 #if ENABLE(CODEBLOCK_SAMPLING)
301 #if CPU(X86_64)
302 ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock)
303 {
304     move(TrustedImmPtr(m_interpreter->sampler()->codeBlockSlot()), X86Registers::ecx);
305     storePtr(TrustedImmPtr(codeBlock), X86Registers::ecx);
306 }
307 #else
308 ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock)
309 {
310     storePtr(TrustedImmPtr(codeBlock), m_interpreter->sampler()->codeBlockSlot());
311 }
312 #endif
313 #endif
314
315 ALWAYS_INLINE bool JIT::isOperandConstantImmediateChar(int src)
316 {
317     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isString() && asString(getConstantOperand(src).asCell())->length() == 1;
318 }
319
320 template<typename StructureType>
321 inline void JIT::emitAllocateJSObject(RegisterID allocator, StructureType structure, RegisterID result, RegisterID scratch)
322 {
323     loadPtr(Address(allocator, MarkedAllocator::offsetOfFreeListHead()), result);
324     addSlowCase(branchTestPtr(Zero, result));
325
326     // remove the object from the free list
327     loadPtr(Address(result), scratch);
328     storePtr(scratch, Address(allocator, MarkedAllocator::offsetOfFreeListHead()));
329
330     // initialize the object's structure
331     storePtr(structure, Address(result, JSCell::structureOffset()));
332
333     // initialize the object's property storage pointer
334     storePtr(TrustedImmPtr(0), Address(result, JSObject::butterflyOffset()));
335 }
336
337 #if ENABLE(VALUE_PROFILER)
338 inline void JIT::emitValueProfilingSite(ValueProfile* valueProfile, RegisterID bucketCounterRegister)
339 {
340     ASSERT(shouldEmitProfiling());
341     ASSERT(valueProfile);
342
343     const RegisterID value = regT0;
344 #if USE(JSVALUE32_64)
345     const RegisterID valueTag = regT1;
346 #endif
347     const RegisterID scratch = regT3;
348     
349     if (ValueProfile::numberOfBuckets == 1) {
350         // We're in a simple configuration: only one bucket, so we can just do a direct
351         // store.
352 #if USE(JSVALUE64)
353         store64(value, valueProfile->m_buckets);
354 #else
355         EncodedValueDescriptor* descriptor = bitwise_cast<EncodedValueDescriptor*>(valueProfile->m_buckets);
356         store32(value, &descriptor->asBits.payload);
357         store32(valueTag, &descriptor->asBits.tag);
358 #endif
359         return;
360     }
361     
362     if (m_randomGenerator.getUint32() & 1)
363         add32(TrustedImm32(1), bucketCounterRegister);
364     else
365         add32(TrustedImm32(3), bucketCounterRegister);
366     and32(TrustedImm32(ValueProfile::bucketIndexMask), bucketCounterRegister);
367     move(TrustedImmPtr(valueProfile->m_buckets), scratch);
368 #if USE(JSVALUE64)
369     store64(value, BaseIndex(scratch, bucketCounterRegister, TimesEight));
370 #elif USE(JSVALUE32_64)
371     store32(value, BaseIndex(scratch, bucketCounterRegister, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
372     store32(valueTag, BaseIndex(scratch, bucketCounterRegister, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
373 #endif
374 }
375
376 inline void JIT::emitValueProfilingSite(unsigned bytecodeOffset, RegisterID bucketCounterRegister)
377 {
378     if (!shouldEmitProfiling())
379         return;
380     emitValueProfilingSite(m_codeBlock->valueProfileForBytecodeOffset(bytecodeOffset), bucketCounterRegister);
381 }
382
383 inline void JIT::emitValueProfilingSite(RegisterID bucketCounterRegister)
384 {
385     emitValueProfilingSite(m_bytecodeOffset, bucketCounterRegister);
386 }
387 #endif // ENABLE(VALUE_PROFILER)
388
389 inline void JIT::emitArrayProfilingSite(RegisterID structureAndIndexingType, RegisterID scratch, ArrayProfile* arrayProfile)
390 {
391     UNUSED_PARAM(scratch); // We had found this scratch register useful here before, so I will keep it for now.
392     
393     RegisterID structure = structureAndIndexingType;
394     RegisterID indexingType = structureAndIndexingType;
395     
396     if (shouldEmitProfiling())
397         storePtr(structure, arrayProfile->addressOfLastSeenStructure());
398
399     load8(Address(structure, Structure::indexingTypeOffset()), indexingType);
400 }
401
402 inline void JIT::emitArrayProfilingSiteForBytecodeIndex(RegisterID structureAndIndexingType, RegisterID scratch, unsigned bytecodeIndex)
403 {
404 #if ENABLE(VALUE_PROFILER)
405     emitArrayProfilingSite(structureAndIndexingType, scratch, m_codeBlock->getOrAddArrayProfile(bytecodeIndex));
406 #else
407     UNUSED_PARAM(bytecodeIndex);
408     emitArrayProfilingSite(structureAndIndexingType, scratch, 0);
409 #endif
410 }
411
412 inline void JIT::emitArrayProfileStoreToHoleSpecialCase(ArrayProfile* arrayProfile)
413 {
414 #if ENABLE(VALUE_PROFILER)    
415     store8(TrustedImm32(1), arrayProfile->addressOfMayStoreToHole());
416 #else
417     UNUSED_PARAM(arrayProfile);
418 #endif
419 }
420
421 inline void JIT::emitArrayProfileOutOfBoundsSpecialCase(ArrayProfile* arrayProfile)
422 {
423 #if ENABLE(VALUE_PROFILER)    
424     store8(TrustedImm32(1), arrayProfile->addressOfOutOfBounds());
425 #else
426     UNUSED_PARAM(arrayProfile);
427 #endif
428 }
429
430 static inline bool arrayProfileSaw(ArrayModes arrayModes, IndexingType capability)
431 {
432 #if ENABLE(VALUE_PROFILER)
433     return arrayModesInclude(arrayModes, capability);
434 #else
435     UNUSED_PARAM(arrayModes);
436     UNUSED_PARAM(capability);
437     return false;
438 #endif
439 }
440
441 inline JITArrayMode JIT::chooseArrayMode(ArrayProfile* profile)
442 {
443 #if ENABLE(VALUE_PROFILER)
444     ConcurrentJITLocker locker(m_codeBlock->m_lock);
445     profile->computeUpdatedPrediction(locker, m_codeBlock);
446     ArrayModes arrayModes = profile->observedArrayModes(locker);
447     if (arrayProfileSaw(arrayModes, DoubleShape))
448         return JITDouble;
449     if (arrayProfileSaw(arrayModes, Int32Shape))
450         return JITInt32;
451     if (arrayProfileSaw(arrayModes, ArrayStorageShape))
452         return JITArrayStorage;
453     return JITContiguous;
454 #else
455     UNUSED_PARAM(profile);
456     return JITContiguous;
457 #endif
458 }
459
460 #if USE(JSVALUE32_64)
461
462 inline void JIT::emitLoadTag(int index, RegisterID tag)
463 {
464     RegisterID mappedTag;
465     if (getMappedTag(index, mappedTag)) {
466         move(mappedTag, tag);
467         unmap(tag);
468         return;
469     }
470
471     if (m_codeBlock->isConstantRegisterIndex(index)) {
472         move(Imm32(getConstantOperand(index).tag()), tag);
473         unmap(tag);
474         return;
475     }
476
477     load32(tagFor(index), tag);
478     unmap(tag);
479 }
480
481 inline void JIT::emitLoadPayload(int index, RegisterID payload)
482 {
483     RegisterID mappedPayload;
484     if (getMappedPayload(index, mappedPayload)) {
485         move(mappedPayload, payload);
486         unmap(payload);
487         return;
488     }
489
490     if (m_codeBlock->isConstantRegisterIndex(index)) {
491         move(Imm32(getConstantOperand(index).payload()), payload);
492         unmap(payload);
493         return;
494     }
495
496     load32(payloadFor(index), payload);
497     unmap(payload);
498 }
499
500 inline void JIT::emitLoad(const JSValue& v, RegisterID tag, RegisterID payload)
501 {
502     move(Imm32(v.payload()), payload);
503     move(Imm32(v.tag()), tag);
504 }
505
506 inline void JIT::emitLoad(int index, RegisterID tag, RegisterID payload, RegisterID base)
507 {
508     RELEASE_ASSERT(tag != payload);
509
510     if (base == callFrameRegister) {
511         RELEASE_ASSERT(payload != base);
512         emitLoadPayload(index, payload);
513         emitLoadTag(index, tag);
514         return;
515     }
516
517     if (payload == base) { // avoid stomping base
518         load32(tagFor(index, base), tag);
519         load32(payloadFor(index, base), payload);
520         return;
521     }
522
523     load32(payloadFor(index, base), payload);
524     load32(tagFor(index, base), tag);
525 }
526
527 inline void JIT::emitLoad2(int index1, RegisterID tag1, RegisterID payload1, int index2, RegisterID tag2, RegisterID payload2)
528 {
529     if (isMapped(index1)) {
530         emitLoad(index1, tag1, payload1);
531         emitLoad(index2, tag2, payload2);
532         return;
533     }
534     emitLoad(index2, tag2, payload2);
535     emitLoad(index1, tag1, payload1);
536 }
537
538 inline void JIT::emitLoadDouble(int index, FPRegisterID value)
539 {
540     if (m_codeBlock->isConstantRegisterIndex(index)) {
541         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
542         loadDouble(&inConstantPool, value);
543     } else
544         loadDouble(addressFor(index), value);
545 }
546
547 inline void JIT::emitLoadInt32ToDouble(int index, FPRegisterID value)
548 {
549     if (m_codeBlock->isConstantRegisterIndex(index)) {
550         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
551         char* bytePointer = reinterpret_cast<char*>(&inConstantPool);
552         convertInt32ToDouble(AbsoluteAddress(bytePointer + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), value);
553     } else
554         convertInt32ToDouble(payloadFor(index), value);
555 }
556
557 inline void JIT::emitStore(int index, RegisterID tag, RegisterID payload, RegisterID base)
558 {
559     store32(payload, payloadFor(index, base));
560     store32(tag, tagFor(index, base));
561 }
562
563 inline void JIT::emitStoreInt32(int index, RegisterID payload, bool indexIsInt32)
564 {
565     store32(payload, payloadFor(index, callFrameRegister));
566     if (!indexIsInt32)
567         store32(TrustedImm32(JSValue::Int32Tag), tagFor(index, callFrameRegister));
568 }
569
570 inline void JIT::emitStoreAndMapInt32(int index, RegisterID tag, RegisterID payload, bool indexIsInt32, size_t opcodeLength)
571 {
572     emitStoreInt32(index, payload, indexIsInt32);
573     map(m_bytecodeOffset + opcodeLength, index, tag, payload);
574 }
575
576 inline void JIT::emitStoreInt32(int index, TrustedImm32 payload, bool indexIsInt32)
577 {
578     store32(payload, payloadFor(index, callFrameRegister));
579     if (!indexIsInt32)
580         store32(TrustedImm32(JSValue::Int32Tag), tagFor(index, callFrameRegister));
581 }
582
583 inline void JIT::emitStoreCell(int index, RegisterID payload, bool indexIsCell)
584 {
585     store32(payload, payloadFor(index, callFrameRegister));
586     if (!indexIsCell)
587         store32(TrustedImm32(JSValue::CellTag), tagFor(index, callFrameRegister));
588 }
589
590 inline void JIT::emitStoreBool(int index, RegisterID payload, bool indexIsBool)
591 {
592     store32(payload, payloadFor(index, callFrameRegister));
593     if (!indexIsBool)
594         store32(TrustedImm32(JSValue::BooleanTag), tagFor(index, callFrameRegister));
595 }
596
597 inline void JIT::emitStoreDouble(int index, FPRegisterID value)
598 {
599     storeDouble(value, addressFor(index));
600 }
601
602 inline void JIT::emitStore(int index, const JSValue constant, RegisterID base)
603 {
604     store32(Imm32(constant.payload()), payloadFor(index, base));
605     store32(Imm32(constant.tag()), tagFor(index, base));
606 }
607
608 ALWAYS_INLINE void JIT::emitInitRegister(int dst)
609 {
610     emitStore(dst, jsUndefined());
611 }
612
613 inline bool JIT::isLabeled(unsigned bytecodeOffset)
614 {
615     for (size_t numberOfJumpTargets = m_codeBlock->numberOfJumpTargets(); m_jumpTargetIndex != numberOfJumpTargets; ++m_jumpTargetIndex) {
616         unsigned jumpTarget = m_codeBlock->jumpTarget(m_jumpTargetIndex);
617         if (jumpTarget == bytecodeOffset)
618             return true;
619         if (jumpTarget > bytecodeOffset)
620             return false;
621     }
622     return false;
623 }
624
625 inline void JIT::map(unsigned bytecodeOffset, int virtualRegisterIndex, RegisterID tag, RegisterID payload)
626 {
627     if (isLabeled(bytecodeOffset))
628         return;
629
630     m_mappedBytecodeOffset = bytecodeOffset;
631     m_mappedVirtualRegisterIndex = virtualRegisterIndex;
632     m_mappedTag = tag;
633     m_mappedPayload = payload;
634     
635     ASSERT(!canBeOptimizedOrInlined() || m_mappedPayload == regT0);
636     ASSERT(!canBeOptimizedOrInlined() || m_mappedTag == regT1);
637 }
638
639 inline void JIT::unmap(RegisterID registerID)
640 {
641     if (m_mappedTag == registerID)
642         m_mappedTag = (RegisterID)-1;
643     else if (m_mappedPayload == registerID)
644         m_mappedPayload = (RegisterID)-1;
645 }
646
647 inline void JIT::unmap()
648 {
649     m_mappedBytecodeOffset = (unsigned)-1;
650     m_mappedVirtualRegisterIndex = JSStack::ReturnPC;
651     m_mappedTag = (RegisterID)-1;
652     m_mappedPayload = (RegisterID)-1;
653 }
654
655 inline bool JIT::isMapped(int virtualRegisterIndex)
656 {
657     if (m_mappedBytecodeOffset != m_bytecodeOffset)
658         return false;
659     if (m_mappedVirtualRegisterIndex != virtualRegisterIndex)
660         return false;
661     return true;
662 }
663
664 inline bool JIT::getMappedPayload(int virtualRegisterIndex, RegisterID& payload)
665 {
666     if (m_mappedBytecodeOffset != m_bytecodeOffset)
667         return false;
668     if (m_mappedVirtualRegisterIndex != virtualRegisterIndex)
669         return false;
670     if (m_mappedPayload == (RegisterID)-1)
671         return false;
672     payload = m_mappedPayload;
673     return true;
674 }
675
676 inline bool JIT::getMappedTag(int virtualRegisterIndex, RegisterID& tag)
677 {
678     if (m_mappedBytecodeOffset != m_bytecodeOffset)
679         return false;
680     if (m_mappedVirtualRegisterIndex != virtualRegisterIndex)
681         return false;
682     if (m_mappedTag == (RegisterID)-1)
683         return false;
684     tag = m_mappedTag;
685     return true;
686 }
687
688 inline void JIT::emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex)
689 {
690     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) {
691         if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
692             addSlowCase(jump());
693         else
694             addSlowCase(emitJumpIfNotJSCell(virtualRegisterIndex));
695     }
696 }
697
698 inline void JIT::emitJumpSlowCaseIfNotJSCell(int virtualRegisterIndex, RegisterID tag)
699 {
700     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) {
701         if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
702             addSlowCase(jump());
703         else
704             addSlowCase(branch32(NotEqual, tag, TrustedImm32(JSValue::CellTag)));
705     }
706 }
707
708 ALWAYS_INLINE bool JIT::isOperandConstantImmediateInt(int src)
709 {
710     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32();
711 }
712
713 ALWAYS_INLINE bool JIT::getOperandConstantImmediateInt(int op1, int op2, int& op, int32_t& constant)
714 {
715     if (isOperandConstantImmediateInt(op1)) {
716         constant = getConstantOperand(op1).asInt32();
717         op = op2;
718         return true;
719     }
720
721     if (isOperandConstantImmediateInt(op2)) {
722         constant = getConstantOperand(op2).asInt32();
723         op = op1;
724         return true;
725     }
726     
727     return false;
728 }
729
730 #else // USE(JSVALUE32_64)
731
732 /* Deprecated: Please use JITStubCall instead. */
733
734 ALWAYS_INLINE void JIT::emitGetJITStubArg(int argumentNumber, RegisterID dst)
735 {
736     int argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
737     peek64(dst, argumentStackOffset);
738 }
739
740 ALWAYS_INLINE void JIT::killLastResultRegister()
741 {
742     m_lastResultBytecodeRegister = std::numeric_limits<int>::max();
743 }
744
745 // get arg puts an arg from the SF register array into a h/w register
746 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, RegisterID dst)
747 {
748     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
749
750     // TODO: we want to reuse values that are already in registers if we can - add a register allocator!
751     if (m_codeBlock->isConstantRegisterIndex(src)) {
752         JSValue value = m_codeBlock->getConstant(src);
753         if (!value.isNumber())
754             move(TrustedImm64(JSValue::encode(value)), dst);
755         else
756             move(Imm64(JSValue::encode(value)), dst);
757         killLastResultRegister();
758         return;
759     }
760
761     if (src == m_lastResultBytecodeRegister && operandIsLocal(src) && m_codeBlock->isTemporaryRegisterIndex(VirtualRegister(src).toLocal()) && !atJumpTarget()) {
762         // The argument we want is already stored in eax
763         if (dst != cachedResultRegister)
764             move(cachedResultRegister, dst);
765         killLastResultRegister();
766         return;
767     }
768
769     load64(Address(callFrameRegister, src * sizeof(Register)), dst);
770     killLastResultRegister();
771 }
772
773 ALWAYS_INLINE void JIT::emitGetVirtualRegister(VirtualRegister src, RegisterID dst)
774 {
775     emitGetVirtualRegister(src.offset(), dst);
776 }
777
778 ALWAYS_INLINE void JIT::emitGetVirtualRegisters(int src1, RegisterID dst1, int src2, RegisterID dst2)
779 {
780     if (src2 == m_lastResultBytecodeRegister) {
781         emitGetVirtualRegister(src2, dst2);
782         emitGetVirtualRegister(src1, dst1);
783     } else {
784         emitGetVirtualRegister(src1, dst1);
785         emitGetVirtualRegister(src2, dst2);
786     }
787 }
788
789 ALWAYS_INLINE void JIT::emitGetVirtualRegisters(VirtualRegister src1, RegisterID dst1, VirtualRegister src2, RegisterID dst2)
790 {
791     emitGetVirtualRegisters(src1.offset(), dst1, src2.offset(), dst2);
792 }
793
794 ALWAYS_INLINE int32_t JIT::getConstantOperandImmediateInt(int src)
795 {
796     return getConstantOperand(src).asInt32();
797 }
798
799 ALWAYS_INLINE bool JIT::isOperandConstantImmediateInt(int src)
800 {
801     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32();
802 }
803
804 ALWAYS_INLINE void JIT::emitPutVirtualRegister(int dst, RegisterID from)
805 {
806     store64(from, Address(callFrameRegister, dst * sizeof(Register)));
807     m_lastResultBytecodeRegister = (from == cachedResultRegister) ? dst : std::numeric_limits<int>::max();
808 }
809
810 ALWAYS_INLINE void JIT::emitPutVirtualRegister(VirtualRegister dst, RegisterID from)
811 {
812     emitPutVirtualRegister(dst.offset(), from);
813 }
814
815 ALWAYS_INLINE void JIT::emitInitRegister(int dst)
816 {
817     store64(TrustedImm64(JSValue::encode(jsUndefined())), Address(callFrameRegister, dst * sizeof(Register)));
818 }
819
820 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfJSCell(RegisterID reg)
821 {
822     return branchTest64(Zero, reg, tagMaskRegister);
823 }
824
825 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfBothJSCells(RegisterID reg1, RegisterID reg2, RegisterID scratch)
826 {
827     move(reg1, scratch);
828     or64(reg2, scratch);
829     return emitJumpIfJSCell(scratch);
830 }
831
832 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfJSCell(RegisterID reg)
833 {
834     addSlowCase(emitJumpIfJSCell(reg));
835 }
836
837 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg)
838 {
839     addSlowCase(emitJumpIfNotJSCell(reg));
840 }
841
842 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, int vReg)
843 {
844     if (!m_codeBlock->isKnownNotImmediate(vReg))
845         emitJumpSlowCaseIfNotJSCell(reg);
846 }
847
848 inline void JIT::emitLoadDouble(int index, FPRegisterID value)
849 {
850     if (m_codeBlock->isConstantRegisterIndex(index)) {
851         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
852         loadDouble(&inConstantPool, value);
853     } else
854         loadDouble(addressFor(index), value);
855 }
856
857 inline void JIT::emitLoadInt32ToDouble(int index, FPRegisterID value)
858 {
859     if (m_codeBlock->isConstantRegisterIndex(index)) {
860         ASSERT(isOperandConstantImmediateInt(index));
861         convertInt32ToDouble(Imm32(getConstantOperand(index).asInt32()), value);
862     } else
863         convertInt32ToDouble(addressFor(index), value);
864 }
865
866 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfImmediateInteger(RegisterID reg)
867 {
868     return branch64(AboveOrEqual, reg, tagTypeNumberRegister);
869 }
870
871 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateInteger(RegisterID reg)
872 {
873     return branch64(Below, reg, tagTypeNumberRegister);
874 }
875
876 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateIntegers(RegisterID reg1, RegisterID reg2, RegisterID scratch)
877 {
878     move(reg1, scratch);
879     and64(reg2, scratch);
880     return emitJumpIfNotImmediateInteger(scratch);
881 }
882
883 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateInteger(RegisterID reg)
884 {
885     addSlowCase(emitJumpIfNotImmediateInteger(reg));
886 }
887
888 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateIntegers(RegisterID reg1, RegisterID reg2, RegisterID scratch)
889 {
890     addSlowCase(emitJumpIfNotImmediateIntegers(reg1, reg2, scratch));
891 }
892
893 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateNumber(RegisterID reg)
894 {
895     addSlowCase(emitJumpIfNotImmediateNumber(reg));
896 }
897
898 ALWAYS_INLINE void JIT::emitFastArithReTagImmediate(RegisterID src, RegisterID dest)
899 {
900     emitFastArithIntToImmNoCheck(src, dest);
901 }
902
903 ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg)
904 {
905     or32(TrustedImm32(static_cast<int32_t>(ValueFalse)), reg);
906 }
907
908 #endif // USE(JSVALUE32_64)
909
910 } // namespace JSC
911
912 #endif // ENABLE(JIT)
913
914 #endif // JITInlines_h
915