initial import
[vuplus_webkit] / Source / JavaScriptCore / jit / JITInlineMethods.h
1 /*
2  * Copyright (C) 2008 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 JITInlineMethods_h
27 #define JITInlineMethods_h
28
29
30 #if ENABLE(JIT)
31
32 namespace JSC {
33
34 /* Deprecated: Please use JITStubCall instead. */
35
36 ALWAYS_INLINE void JIT::emitGetJITStubArg(unsigned argumentNumber, RegisterID dst)
37 {
38     unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
39     peek(dst, argumentStackOffset);
40 }
41
42 ALWAYS_INLINE bool JIT::isOperandConstantImmediateDouble(unsigned src)
43 {
44     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isDouble();
45 }
46
47 ALWAYS_INLINE JSValue JIT::getConstantOperand(unsigned src)
48 {
49     ASSERT(m_codeBlock->isConstantRegisterIndex(src));
50     return m_codeBlock->getConstant(src);
51 }
52
53 ALWAYS_INLINE void JIT::emitPutToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry entry)
54 {
55     storePtr(from, payloadFor(entry, callFrameRegister));
56 }
57
58 ALWAYS_INLINE void JIT::emitPutCellToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry entry)
59 {
60 #if USE(JSVALUE32_64)
61     store32(TrustedImm32(JSValue::CellTag), tagFor(entry, callFrameRegister));
62 #endif
63     storePtr(from, payloadFor(entry, callFrameRegister));
64 }
65
66 ALWAYS_INLINE void JIT::emitPutIntToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry entry)
67 {
68     store32(TrustedImm32(Int32Tag), intTagFor(entry, callFrameRegister));
69     store32(from, intPayloadFor(entry, callFrameRegister));
70 }
71
72 ALWAYS_INLINE void JIT::emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry)
73 {
74     storePtr(TrustedImmPtr(value), Address(callFrameRegister, entry * sizeof(Register)));
75 }
76
77 ALWAYS_INLINE void JIT::emitGetFromCallFrameHeaderPtr(RegisterFile::CallFrameHeaderEntry entry, RegisterID to, RegisterID from)
78 {
79     loadPtr(Address(from, entry * sizeof(Register)), to);
80 #if USE(JSVALUE64)
81     killLastResultRegister();
82 #endif
83 }
84
85 ALWAYS_INLINE void JIT::emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList& failures)
86 {
87     failures.append(branchPtr(NotEqual, Address(src), TrustedImmPtr(m_globalData->jsStringVPtr)));
88     failures.append(branchTest32(NonZero, Address(src, OBJECT_OFFSETOF(JSString, m_fiberCount))));
89     failures.append(branch32(NotEqual, MacroAssembler::Address(src, ThunkHelpers::jsStringLengthOffset()), TrustedImm32(1)));
90     loadPtr(MacroAssembler::Address(src, ThunkHelpers::jsStringValueOffset()), dst);
91     loadPtr(MacroAssembler::Address(dst, ThunkHelpers::stringImplDataOffset()), dst);
92     load16(MacroAssembler::Address(dst, 0), dst);
93 }
94
95 ALWAYS_INLINE void JIT::emitGetFromCallFrameHeader32(RegisterFile::CallFrameHeaderEntry entry, RegisterID to, RegisterID from)
96 {
97     load32(Address(from, entry * sizeof(Register)), to);
98 #if USE(JSVALUE64)
99     killLastResultRegister();
100 #endif
101 }
102
103 ALWAYS_INLINE JIT::Call JIT::emitNakedCall(CodePtr function)
104 {
105     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
106
107     Call nakedCall = nearCall();
108     m_calls.append(CallRecord(nakedCall, m_bytecodeOffset, function.executableAddress()));
109     return nakedCall;
110 }
111
112 ALWAYS_INLINE bool JIT::atJumpTarget()
113 {
114     while (m_jumpTargetsPosition < m_codeBlock->numberOfJumpTargets() && m_codeBlock->jumpTarget(m_jumpTargetsPosition) <= m_bytecodeOffset) {
115         if (m_codeBlock->jumpTarget(m_jumpTargetsPosition) == m_bytecodeOffset)
116             return true;
117         ++m_jumpTargetsPosition;
118     }
119     return false;
120 }
121
122 #if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
123
124 ALWAYS_INLINE void JIT::beginUninterruptedSequence(int insnSpace, int constSpace)
125 {
126     JSInterfaceJIT::beginUninterruptedSequence();
127 #if CPU(ARM_TRADITIONAL)
128 #ifndef NDEBUG
129     // Ensure the label after the sequence can also fit
130     insnSpace += sizeof(ARMWord);
131     constSpace += sizeof(uint64_t);
132 #endif
133
134     ensureSpace(insnSpace, constSpace);
135
136 #elif CPU(SH4)
137 #ifndef NDEBUG
138     insnSpace += sizeof(SH4Word);
139     constSpace += sizeof(uint64_t);
140 #endif
141
142     m_assembler.ensureSpace(insnSpace + m_assembler.maxInstructionSize + 2, constSpace + 8);
143 #endif
144
145 #if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
146 #ifndef NDEBUG
147     m_uninterruptedInstructionSequenceBegin = label();
148     m_uninterruptedConstantSequenceBegin = sizeOfConstantPool();
149 #endif
150 #endif
151 }
152
153 ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace, int dst)
154 {
155     UNUSED_PARAM(dst);
156 #if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
157     /* There are several cases when the uninterrupted sequence is larger than
158      * maximum required offset for pathing the same sequence. Eg.: if in a
159      * uninterrupted sequence the last macroassembler's instruction is a stub
160      * call, it emits store instruction(s) which should not be included in the
161      * calculation of length of uninterrupted sequence. So, the insnSpace and
162      * constSpace should be upper limit instead of hard limit.
163      */
164 #if CPU(SH4)
165     if ((dst > 15) || (dst < -16)) {
166         insnSpace += 8;
167         constSpace += 2;
168     }
169
170     if (((dst >= -16) && (dst < 0)) || ((dst > 7) && (dst <= 15)))
171         insnSpace += 8;
172 #endif
173     ASSERT(differenceBetween(m_uninterruptedInstructionSequenceBegin, label()) <= insnSpace);
174     ASSERT(sizeOfConstantPool() - m_uninterruptedConstantSequenceBegin <= constSpace);
175 #endif
176     JSInterfaceJIT::endUninterruptedSequence();
177 }
178
179 #endif
180
181 #if CPU(ARM)
182
183 ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg)
184 {
185     move(linkRegister, reg);
186 }
187
188 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg)
189 {
190     move(reg, linkRegister);
191 }
192
193 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address)
194 {
195     loadPtr(address, linkRegister);
196 }
197 #elif CPU(SH4)
198
199 ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg)
200 {
201     m_assembler.stspr(reg);
202 }
203
204 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg)
205 {
206     m_assembler.ldspr(reg);
207 }
208
209 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address)
210 {
211     loadPtrLinkReg(address);
212 }
213
214 #elif CPU(MIPS)
215
216 ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg)
217 {
218     move(returnAddressRegister, reg);
219 }
220
221 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg)
222 {
223     move(reg, returnAddressRegister);
224 }
225
226 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address)
227 {
228     loadPtr(address, returnAddressRegister);
229 }
230
231 #else // CPU(X86) || CPU(X86_64)
232
233 ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg)
234 {
235     pop(reg);
236 }
237
238 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg)
239 {
240     push(reg);
241 }
242
243 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address)
244 {
245     push(address);
246 }
247
248 #endif
249
250 ALWAYS_INLINE void JIT::restoreArgumentReference()
251 {
252     move(stackPointerRegister, firstArgumentRegister);
253     poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
254 }
255
256 ALWAYS_INLINE void JIT::updateTopCallFrame()
257 {
258     storePtr(callFrameRegister, &m_globalData->topCallFrame);
259 }
260
261 ALWAYS_INLINE void JIT::restoreArgumentReferenceForTrampoline()
262 {
263 #if CPU(X86)
264     // Within a trampoline the return address will be on the stack at this point.
265     addPtr(TrustedImm32(sizeof(void*)), stackPointerRegister, firstArgumentRegister);
266 #elif CPU(ARM)
267     move(stackPointerRegister, firstArgumentRegister);
268 #elif CPU(SH4)
269     move(stackPointerRegister, firstArgumentRegister);
270 #endif
271     // In the trampoline on x86-64, the first argument register is not overwritten.
272 }
273
274 ALWAYS_INLINE JIT::Jump JIT::checkStructure(RegisterID reg, Structure* structure)
275 {
276     return branchPtr(NotEqual, Address(reg, JSCell::structureOffset()), TrustedImmPtr(structure));
277 }
278
279 ALWAYS_INLINE void JIT::linkSlowCaseIfNotJSCell(Vector<SlowCaseEntry>::iterator& iter, int vReg)
280 {
281     if (!m_codeBlock->isKnownNotImmediate(vReg))
282         linkSlowCase(iter);
283 }
284
285 ALWAYS_INLINE void JIT::addSlowCase(Jump jump)
286 {
287     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
288
289     m_slowCases.append(SlowCaseEntry(jump, m_bytecodeOffset));
290 }
291
292 ALWAYS_INLINE void JIT::addSlowCase(JumpList jumpList)
293 {
294     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
295
296     const JumpList::JumpVector& jumpVector = jumpList.jumps();
297     size_t size = jumpVector.size();
298     for (size_t i = 0; i < size; ++i)
299         m_slowCases.append(SlowCaseEntry(jumpVector[i], m_bytecodeOffset));
300 }
301
302 ALWAYS_INLINE void JIT::addJump(Jump jump, int relativeOffset)
303 {
304     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
305
306     m_jmpTable.append(JumpTable(jump, m_bytecodeOffset + relativeOffset));
307 }
308
309 ALWAYS_INLINE void JIT::emitJumpSlowToHot(Jump jump, int relativeOffset)
310 {
311     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
312
313     jump.linkTo(m_labels[m_bytecodeOffset + relativeOffset], this);
314 }
315
316 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotObject(RegisterID structureReg)
317 {
318     return branch8(NotEqual, Address(structureReg, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
319 }
320
321 #if ENABLE(SAMPLING_FLAGS)
322 ALWAYS_INLINE void JIT::setSamplingFlag(int32_t flag)
323 {
324     ASSERT(flag >= 1);
325     ASSERT(flag <= 32);
326     or32(TrustedImm32(1u << (flag - 1)), AbsoluteAddress(SamplingFlags::addressOfFlags()));
327 }
328
329 ALWAYS_INLINE void JIT::clearSamplingFlag(int32_t flag)
330 {
331     ASSERT(flag >= 1);
332     ASSERT(flag <= 32);
333     and32(TrustedImm32(~(1u << (flag - 1))), AbsoluteAddress(SamplingFlags::addressOfFlags()));
334 }
335 #endif
336
337 #if ENABLE(SAMPLING_COUNTERS)
338 ALWAYS_INLINE void JIT::emitCount(AbstractSamplingCounter& counter, uint32_t count)
339 {
340 #if CPU(X86_64) // Or any other 64-bit plattform.
341     addPtr(TrustedImm32(count), AbsoluteAddress(counter.addressOfCounter()));
342 #elif CPU(X86) // Or any other little-endian 32-bit plattform.
343     intptr_t hiWord = reinterpret_cast<intptr_t>(counter.addressOfCounter()) + sizeof(int32_t);
344     add32(TrustedImm32(count), AbsoluteAddress(counter.addressOfCounter()));
345     addWithCarry32(TrustedImm32(0), AbsoluteAddress(reinterpret_cast<void*>(hiWord)));
346 #else
347 #error "SAMPLING_FLAGS not implemented on this platform."
348 #endif
349 }
350 #endif
351
352 #if ENABLE(OPCODE_SAMPLING)
353 #if CPU(X86_64)
354 ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction)
355 {
356     move(TrustedImmPtr(m_interpreter->sampler()->sampleSlot()), X86Registers::ecx);
357     storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), X86Registers::ecx);
358 }
359 #else
360 ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction)
361 {
362     storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), m_interpreter->sampler()->sampleSlot());
363 }
364 #endif
365 #endif
366
367 #if ENABLE(CODEBLOCK_SAMPLING)
368 #if CPU(X86_64)
369 ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock)
370 {
371     move(TrustedImmPtr(m_interpreter->sampler()->codeBlockSlot()), X86Registers::ecx);
372     storePtr(TrustedImmPtr(codeBlock), X86Registers::ecx);
373 }
374 #else
375 ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock)
376 {
377     storePtr(TrustedImmPtr(codeBlock), m_interpreter->sampler()->codeBlockSlot());
378 }
379 #endif
380 #endif
381
382 ALWAYS_INLINE bool JIT::isOperandConstantImmediateChar(unsigned src)
383 {
384     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isString() && asString(getConstantOperand(src).asCell())->length() == 1;
385 }
386
387 template <typename ClassType, typename StructureType> inline void JIT::emitAllocateBasicJSObject(StructureType structure, void* vtable, RegisterID result, RegisterID storagePtr)
388 {
389     NewSpace::SizeClass* sizeClass = &m_globalData->heap.sizeClassFor(sizeof(ClassType));
390     loadPtr(&sizeClass->firstFreeCell, result);
391     addSlowCase(branchTestPtr(Zero, result));
392
393     // remove the object from the free list
394     loadPtr(Address(result), storagePtr);
395     storePtr(storagePtr, &sizeClass->firstFreeCell);
396
397     // initialize the object's vtable
398     storePtr(TrustedImmPtr(vtable), Address(result));
399
400     // initialize the object's structure
401     storePtr(structure, Address(result, JSCell::structureOffset()));
402
403     // initialize the inheritor ID
404     storePtr(TrustedImmPtr(0), Address(result, JSObject::offsetOfInheritorID()));
405
406     // initialize the object's property storage pointer
407     addPtr(TrustedImm32(sizeof(JSObject)), result, storagePtr);
408     storePtr(storagePtr, Address(result, ClassType::offsetOfPropertyStorage()));
409 }
410
411 template <typename T> inline void JIT::emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID scratch)
412 {
413     emitAllocateBasicJSObject<JSFinalObject>(structure, m_globalData->jsFinalObjectVPtr, result, scratch);
414 }
415
416 inline void JIT::emitAllocateJSFunction(FunctionExecutable* executable, RegisterID scopeChain, RegisterID result, RegisterID storagePtr)
417 {
418     emitAllocateBasicJSObject<JSFunction>(TrustedImmPtr(m_codeBlock->globalObject()->namedFunctionStructure()), m_globalData->jsFunctionVPtr, result, storagePtr);
419
420     // store the function's scope chain
421     storePtr(scopeChain, Address(result, JSFunction::offsetOfScopeChain()));
422
423     // store the function's executable member
424     storePtr(TrustedImmPtr(executable), Address(result, JSFunction::offsetOfExecutable()));
425
426     // store the function's name
427     ASSERT(executable->nameValue());
428     int functionNameOffset = sizeof(JSValue) * m_codeBlock->globalObject()->functionNameOffset();
429     storePtr(TrustedImmPtr(executable->nameValue()), Address(regT1, functionNameOffset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
430 #if USE(JSVALUE32_64)
431     store32(TrustedImm32(JSValue::CellTag), Address(regT1, functionNameOffset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
432 #endif
433 }
434
435 #if ENABLE(VALUE_PROFILER)
436 inline void JIT::emitValueProfilingSite(ValueProfilingSiteKind siteKind)
437 {
438     if (!shouldEmitProfiling())
439         return;
440     
441     const RegisterID value = regT0;
442     const RegisterID scratch = regT3;
443     
444     ValueProfile* valueProfile;
445     if (siteKind == FirstProfilingSite)
446         valueProfile = m_codeBlock->addValueProfile(m_bytecodeOffset);
447     else {
448         ASSERT(siteKind == SubsequentProfilingSite);
449         valueProfile = m_codeBlock->valueProfileForBytecodeOffset(m_bytecodeOffset);
450     }
451     
452     ASSERT(valueProfile);
453     
454     if (m_randomGenerator.getUint32() & 1)
455         add32(Imm32(1), bucketCounterRegister);
456     else
457         add32(Imm32(3), bucketCounterRegister);
458     and32(Imm32(ValueProfile::bucketIndexMask), bucketCounterRegister);
459     move(ImmPtr(valueProfile->m_buckets), scratch);
460     storePtr(value, BaseIndex(scratch, bucketCounterRegister, TimesEight));
461 }
462 #endif
463
464 #if USE(JSVALUE32_64)
465
466 inline void JIT::emitLoadTag(unsigned 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(unsigned 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(unsigned 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(unsigned index1, RegisterID tag1, RegisterID payload1, unsigned 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(unsigned 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(unsigned 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(unsigned 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(unsigned 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::emitStoreInt32(unsigned index, TrustedImm32 payload, bool indexIsInt32)
575 {
576     store32(payload, payloadFor(index, callFrameRegister));
577     if (!indexIsInt32)
578         store32(TrustedImm32(JSValue::Int32Tag), tagFor(index, callFrameRegister));
579 }
580
581 inline void JIT::emitStoreCell(unsigned index, RegisterID payload, bool indexIsCell)
582 {
583     store32(payload, payloadFor(index, callFrameRegister));
584     if (!indexIsCell)
585         store32(TrustedImm32(JSValue::CellTag), tagFor(index, callFrameRegister));
586 }
587
588 inline void JIT::emitStoreBool(unsigned index, RegisterID payload, bool indexIsBool)
589 {
590     store32(payload, payloadFor(index, callFrameRegister));
591     if (!indexIsBool)
592         store32(TrustedImm32(JSValue::BooleanTag), tagFor(index, callFrameRegister));
593 }
594
595 inline void JIT::emitStoreDouble(unsigned index, FPRegisterID value)
596 {
597     storeDouble(value, addressFor(index));
598 }
599
600 inline void JIT::emitStore(unsigned index, const JSValue constant, RegisterID base)
601 {
602     store32(Imm32(constant.payload()), payloadFor(index, base));
603     store32(Imm32(constant.tag()), tagFor(index, base));
604 }
605
606 ALWAYS_INLINE void JIT::emitInitRegister(unsigned dst)
607 {
608     emitStore(dst, jsUndefined());
609 }
610
611 inline bool JIT::isLabeled(unsigned bytecodeOffset)
612 {
613     for (size_t numberOfJumpTargets = m_codeBlock->numberOfJumpTargets(); m_jumpTargetIndex != numberOfJumpTargets; ++m_jumpTargetIndex) {
614         unsigned jumpTarget = m_codeBlock->jumpTarget(m_jumpTargetIndex);
615         if (jumpTarget == bytecodeOffset)
616             return true;
617         if (jumpTarget > bytecodeOffset)
618             return false;
619     }
620     return false;
621 }
622
623 inline void JIT::map(unsigned bytecodeOffset, unsigned virtualRegisterIndex, RegisterID tag, RegisterID payload)
624 {
625     if (isLabeled(bytecodeOffset))
626         return;
627
628     m_mappedBytecodeOffset = bytecodeOffset;
629     m_mappedVirtualRegisterIndex = virtualRegisterIndex;
630     m_mappedTag = tag;
631     m_mappedPayload = payload;
632 }
633
634 inline void JIT::unmap(RegisterID registerID)
635 {
636     if (m_mappedTag == registerID)
637         m_mappedTag = (RegisterID)-1;
638     else if (m_mappedPayload == registerID)
639         m_mappedPayload = (RegisterID)-1;
640 }
641
642 inline void JIT::unmap()
643 {
644     m_mappedBytecodeOffset = (unsigned)-1;
645     m_mappedVirtualRegisterIndex = (unsigned)-1;
646     m_mappedTag = (RegisterID)-1;
647     m_mappedPayload = (RegisterID)-1;
648 }
649
650 inline bool JIT::isMapped(unsigned virtualRegisterIndex)
651 {
652     if (m_mappedBytecodeOffset != m_bytecodeOffset)
653         return false;
654     if (m_mappedVirtualRegisterIndex != virtualRegisterIndex)
655         return false;
656     return true;
657 }
658
659 inline bool JIT::getMappedPayload(unsigned virtualRegisterIndex, RegisterID& payload)
660 {
661     if (m_mappedBytecodeOffset != m_bytecodeOffset)
662         return false;
663     if (m_mappedVirtualRegisterIndex != virtualRegisterIndex)
664         return false;
665     if (m_mappedPayload == (RegisterID)-1)
666         return false;
667     payload = m_mappedPayload;
668     return true;
669 }
670
671 inline bool JIT::getMappedTag(unsigned virtualRegisterIndex, RegisterID& tag)
672 {
673     if (m_mappedBytecodeOffset != m_bytecodeOffset)
674         return false;
675     if (m_mappedVirtualRegisterIndex != virtualRegisterIndex)
676         return false;
677     if (m_mappedTag == (RegisterID)-1)
678         return false;
679     tag = m_mappedTag;
680     return true;
681 }
682
683 inline void JIT::emitJumpSlowCaseIfNotJSCell(unsigned virtualRegisterIndex)
684 {
685     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) {
686         if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
687             addSlowCase(jump());
688         else
689             addSlowCase(emitJumpIfNotJSCell(virtualRegisterIndex));
690     }
691 }
692
693 inline void JIT::emitJumpSlowCaseIfNotJSCell(unsigned virtualRegisterIndex, RegisterID tag)
694 {
695     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) {
696         if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
697             addSlowCase(jump());
698         else
699             addSlowCase(branch32(NotEqual, tag, TrustedImm32(JSValue::CellTag)));
700     }
701 }
702
703 inline void JIT::linkSlowCaseIfNotJSCell(Vector<SlowCaseEntry>::iterator& iter, unsigned virtualRegisterIndex)
704 {
705     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex))
706         linkSlowCase(iter);
707 }
708
709 ALWAYS_INLINE bool JIT::isOperandConstantImmediateInt(unsigned src)
710 {
711     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32();
712 }
713
714 ALWAYS_INLINE bool JIT::getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant)
715 {
716     if (isOperandConstantImmediateInt(op1)) {
717         constant = getConstantOperand(op1).asInt32();
718         op = op2;
719         return true;
720     }
721
722     if (isOperandConstantImmediateInt(op2)) {
723         constant = getConstantOperand(op2).asInt32();
724         op = op1;
725         return true;
726     }
727     
728     return false;
729 }
730
731 #else // USE(JSVALUE32_64)
732
733 ALWAYS_INLINE void JIT::killLastResultRegister()
734 {
735     m_lastResultBytecodeRegister = std::numeric_limits<int>::max();
736 }
737
738 // get arg puts an arg from the SF register array into a h/w register
739 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, RegisterID dst)
740 {
741     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
742
743     // TODO: we want to reuse values that are already in registers if we can - add a register allocator!
744     if (m_codeBlock->isConstantRegisterIndex(src)) {
745         JSValue value = m_codeBlock->getConstant(src);
746         move(ImmPtr(JSValue::encode(value)), dst);
747         killLastResultRegister();
748         return;
749     }
750
751     if (src == m_lastResultBytecodeRegister && m_codeBlock->isTemporaryRegisterIndex(src) && !atJumpTarget()) {
752         // The argument we want is already stored in eax
753         if (dst != cachedResultRegister)
754             move(cachedResultRegister, dst);
755         killLastResultRegister();
756         return;
757     }
758
759     loadPtr(Address(callFrameRegister, src * sizeof(Register)), dst);
760     killLastResultRegister();
761 }
762
763 ALWAYS_INLINE void JIT::emitGetVirtualRegisters(int src1, RegisterID dst1, int src2, RegisterID dst2)
764 {
765     if (src2 == m_lastResultBytecodeRegister) {
766         emitGetVirtualRegister(src2, dst2);
767         emitGetVirtualRegister(src1, dst1);
768     } else {
769         emitGetVirtualRegister(src1, dst1);
770         emitGetVirtualRegister(src2, dst2);
771     }
772 }
773
774 ALWAYS_INLINE int32_t JIT::getConstantOperandImmediateInt(unsigned src)
775 {
776     return getConstantOperand(src).asInt32();
777 }
778
779 ALWAYS_INLINE bool JIT::isOperandConstantImmediateInt(unsigned src)
780 {
781     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32();
782 }
783
784 ALWAYS_INLINE void JIT::emitPutVirtualRegister(unsigned dst, RegisterID from)
785 {
786     storePtr(from, Address(callFrameRegister, dst * sizeof(Register)));
787     m_lastResultBytecodeRegister = (from == cachedResultRegister) ? static_cast<int>(dst) : std::numeric_limits<int>::max();
788 }
789
790 ALWAYS_INLINE void JIT::emitInitRegister(unsigned dst)
791 {
792     storePtr(TrustedImmPtr(JSValue::encode(jsUndefined())), Address(callFrameRegister, dst * sizeof(Register)));
793 }
794
795 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfJSCell(RegisterID reg)
796 {
797 #if USE(JSVALUE64)
798     return branchTestPtr(Zero, reg, tagMaskRegister);
799 #else
800     return branchTest32(Zero, reg, TrustedImm32(TagMask));
801 #endif
802 }
803
804 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfBothJSCells(RegisterID reg1, RegisterID reg2, RegisterID scratch)
805 {
806     move(reg1, scratch);
807     orPtr(reg2, scratch);
808     return emitJumpIfJSCell(scratch);
809 }
810
811 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfJSCell(RegisterID reg)
812 {
813     addSlowCase(emitJumpIfJSCell(reg));
814 }
815
816 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotJSCell(RegisterID reg)
817 {
818 #if USE(JSVALUE64)
819     return branchTestPtr(NonZero, reg, tagMaskRegister);
820 #else
821     return branchTest32(NonZero, reg, TrustedImm32(TagMask));
822 #endif
823 }
824
825 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg)
826 {
827     addSlowCase(emitJumpIfNotJSCell(reg));
828 }
829
830 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, int vReg)
831 {
832     if (!m_codeBlock->isKnownNotImmediate(vReg))
833         emitJumpSlowCaseIfNotJSCell(reg);
834 }
835
836 #if USE(JSVALUE64)
837
838 inline void JIT::emitLoadDouble(unsigned index, FPRegisterID value)
839 {
840     if (m_codeBlock->isConstantRegisterIndex(index)) {
841         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
842         loadDouble(&inConstantPool, value);
843     } else
844         loadDouble(addressFor(index), value);
845 }
846
847 inline void JIT::emitLoadInt32ToDouble(unsigned index, FPRegisterID value)
848 {
849     if (m_codeBlock->isConstantRegisterIndex(index)) {
850         ASSERT(isOperandConstantImmediateInt(index));
851         convertInt32ToDouble(Imm32(getConstantOperand(index).asInt32()), value);
852     } else
853         convertInt32ToDouble(addressFor(index), value);
854 }
855 #endif
856
857 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfImmediateInteger(RegisterID reg)
858 {
859 #if USE(JSVALUE64)
860     return branchPtr(AboveOrEqual, reg, tagTypeNumberRegister);
861 #else
862     return branchTest32(NonZero, reg, TrustedImm32(TagTypeNumber));
863 #endif
864 }
865
866 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateInteger(RegisterID reg)
867 {
868 #if USE(JSVALUE64)
869     return branchPtr(Below, reg, tagTypeNumberRegister);
870 #else
871     return branchTest32(Zero, reg, TrustedImm32(TagTypeNumber));
872 #endif
873 }
874
875 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateIntegers(RegisterID reg1, RegisterID reg2, RegisterID scratch)
876 {
877     move(reg1, scratch);
878     andPtr(reg2, scratch);
879     return emitJumpIfNotImmediateInteger(scratch);
880 }
881
882 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateInteger(RegisterID reg)
883 {
884     addSlowCase(emitJumpIfNotImmediateInteger(reg));
885 }
886
887 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateIntegers(RegisterID reg1, RegisterID reg2, RegisterID scratch)
888 {
889     addSlowCase(emitJumpIfNotImmediateIntegers(reg1, reg2, scratch));
890 }
891
892 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateNumber(RegisterID reg)
893 {
894     addSlowCase(emitJumpIfNotImmediateNumber(reg));
895 }
896
897 #if USE(JSVALUE32_64)
898 ALWAYS_INLINE void JIT::emitFastArithDeTagImmediate(RegisterID reg)
899 {
900     subPtr(TrustedImm32(TagTypeNumber), reg);
901 }
902
903 ALWAYS_INLINE JIT::Jump JIT::emitFastArithDeTagImmediateJumpIfZero(RegisterID reg)
904 {
905     return branchSubPtr(Zero, TrustedImm32(TagTypeNumber), reg);
906 }
907 #endif
908
909 ALWAYS_INLINE void JIT::emitFastArithReTagImmediate(RegisterID src, RegisterID dest)
910 {
911 #if USE(JSVALUE64)
912     emitFastArithIntToImmNoCheck(src, dest);
913 #else
914     if (src != dest)
915         move(src, dest);
916     addPtr(TrustedImm32(TagTypeNumber), dest);
917 #endif
918 }
919
920 // operand is int32_t, must have been zero-extended if register is 64-bit.
921 ALWAYS_INLINE void JIT::emitFastArithIntToImmNoCheck(RegisterID src, RegisterID dest)
922 {
923 #if USE(JSVALUE64)
924     if (src != dest)
925         move(src, dest);
926     orPtr(tagTypeNumberRegister, dest);
927 #else
928     signExtend32ToPtr(src, dest);
929     addPtr(dest, dest);
930     emitFastArithReTagImmediate(dest, dest);
931 #endif
932 }
933
934 ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg)
935 {
936     or32(TrustedImm32(static_cast<int32_t>(ValueFalse)), reg);
937 }
938
939 #endif // USE(JSVALUE32_64)
940
941 } // namespace JSC
942
943 #endif // ENABLE(JIT)
944
945 #endif