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