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