Home | History | Annotate | Download | only in jit
      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 #if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
    113 
    114 ALWAYS_INLINE void JIT::beginUninterruptedSequence(int insnSpace, int constSpace)
    115 {
    116     JSInterfaceJIT::beginUninterruptedSequence();
    117 #if CPU(ARM_TRADITIONAL)
    118 #ifndef NDEBUG
    119     // Ensure the label after the sequence can also fit
    120     insnSpace += sizeof(ARMWord);
    121     constSpace += sizeof(uint64_t);
    122 #endif
    123 
    124     ensureSpace(insnSpace, constSpace);
    125 
    126 #elif CPU(SH4)
    127 #ifndef NDEBUG
    128     insnSpace += sizeof(SH4Word);
    129     constSpace += sizeof(uint64_t);
    130 #endif
    131 
    132     m_assembler.ensureSpace(insnSpace + m_assembler.maxInstructionSize + 2, constSpace + 8);
    133 #endif
    134 
    135 #if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
    136 #ifndef NDEBUG
    137     m_uninterruptedInstructionSequenceBegin = label();
    138     m_uninterruptedConstantSequenceBegin = sizeOfConstantPool();
    139 #endif
    140 #endif
    141 }
    142 
    143 ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace, int dst)
    144 {
    145     UNUSED_PARAM(dst);
    146 #if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
    147     /* There are several cases when the uninterrupted sequence is larger than
    148      * maximum required offset for pathing the same sequence. Eg.: if in a
    149      * uninterrupted sequence the last macroassembler's instruction is a stub
    150      * call, it emits store instruction(s) which should not be included in the
    151      * calculation of length of uninterrupted sequence. So, the insnSpace and
    152      * constSpace should be upper limit instead of hard limit.
    153      */
    154 #if CPU(SH4)
    155     if ((dst > 15) || (dst < -16)) {
    156         insnSpace += 8;
    157         constSpace += 2;
    158     }
    159 
    160     if (((dst >= -16) && (dst < 0)) || ((dst > 7) && (dst <= 15)))
    161         insnSpace += 8;
    162 #endif
    163     ASSERT(differenceBetween(m_uninterruptedInstructionSequenceBegin, label()) <= insnSpace);
    164     ASSERT(sizeOfConstantPool() - m_uninterruptedConstantSequenceBegin <= constSpace);
    165 #endif
    166     JSInterfaceJIT::endUninterruptedSequence();
    167 }
    168 
    169 #endif
    170 
    171 #if CPU(ARM)
    172 
    173 ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg)
    174 {
    175     move(linkRegister, reg);
    176 }
    177 
    178 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg)
    179 {
    180     move(reg, linkRegister);
    181 }
    182 
    183 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address)
    184 {
    185     loadPtr(address, linkRegister);
    186 }
    187 #elif CPU(SH4)
    188 
    189 ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg)
    190 {
    191     m_assembler.stspr(reg);
    192 }
    193 
    194 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg)
    195 {
    196     m_assembler.ldspr(reg);
    197 }
    198 
    199 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address)
    200 {
    201     loadPtrLinkReg(address);
    202 }
    203 
    204 #elif CPU(MIPS)
    205 
    206 ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg)
    207 {
    208     move(returnAddressRegister, reg);
    209 }
    210 
    211 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg)
    212 {
    213     move(reg, returnAddressRegister);
    214 }
    215 
    216 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address)
    217 {
    218     loadPtr(address, returnAddressRegister);
    219 }
    220 
    221 #else // CPU(X86) || CPU(X86_64)
    222 
    223 ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg)
    224 {
    225     pop(reg);
    226 }
    227 
    228 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg)
    229 {
    230     push(reg);
    231 }
    232 
    233 ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address)
    234 {
    235     push(address);
    236 }
    237 
    238 #endif
    239 
    240 ALWAYS_INLINE void JIT::restoreArgumentReference()
    241 {
    242     move(stackPointerRegister, firstArgumentRegister);
    243     poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
    244 }
    245 
    246 ALWAYS_INLINE void JIT::restoreArgumentReferenceForTrampoline()
    247 {
    248 #if CPU(X86)
    249     // Within a trampoline the return address will be on the stack at this point.
    250     addPtr(TrustedImm32(sizeof(void*)), stackPointerRegister, firstArgumentRegister);
    251 #elif CPU(ARM)
    252     move(stackPointerRegister, firstArgumentRegister);
    253 #elif CPU(SH4)
    254     move(stackPointerRegister, firstArgumentRegister);
    255 #endif
    256     // In the trampoline on x86-64, the first argument register is not overwritten.
    257 }
    258 
    259 ALWAYS_INLINE JIT::Jump JIT::checkStructure(RegisterID reg, Structure* structure)
    260 {
    261     return branchPtr(NotEqual, Address(reg, JSCell::structureOffset()), TrustedImmPtr(structure));
    262 }
    263 
    264 ALWAYS_INLINE void JIT::linkSlowCaseIfNotJSCell(Vector<SlowCaseEntry>::iterator& iter, int vReg)
    265 {
    266     if (!m_codeBlock->isKnownNotImmediate(vReg))
    267         linkSlowCase(iter);
    268 }
    269 
    270 ALWAYS_INLINE void JIT::addSlowCase(Jump jump)
    271 {
    272     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
    273 
    274     m_slowCases.append(SlowCaseEntry(jump, m_bytecodeOffset));
    275 }
    276 
    277 ALWAYS_INLINE void JIT::addSlowCase(JumpList jumpList)
    278 {
    279     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
    280 
    281     const JumpList::JumpVector& jumpVector = jumpList.jumps();
    282     size_t size = jumpVector.size();
    283     for (size_t i = 0; i < size; ++i)
    284         m_slowCases.append(SlowCaseEntry(jumpVector[i], m_bytecodeOffset));
    285 }
    286 
    287 ALWAYS_INLINE void JIT::addJump(Jump jump, int relativeOffset)
    288 {
    289     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
    290 
    291     m_jmpTable.append(JumpTable(jump, m_bytecodeOffset + relativeOffset));
    292 }
    293 
    294 ALWAYS_INLINE void JIT::emitJumpSlowToHot(Jump jump, int relativeOffset)
    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     jump.linkTo(m_labels[m_bytecodeOffset + relativeOffset], this);
    299 }
    300 
    301 #if ENABLE(SAMPLING_FLAGS)
    302 ALWAYS_INLINE void JIT::setSamplingFlag(int32_t flag)
    303 {
    304     ASSERT(flag >= 1);
    305     ASSERT(flag <= 32);
    306     or32(TrustedImm32(1u << (flag - 1)), AbsoluteAddress(&SamplingFlags::s_flags));
    307 }
    308 
    309 ALWAYS_INLINE void JIT::clearSamplingFlag(int32_t flag)
    310 {
    311     ASSERT(flag >= 1);
    312     ASSERT(flag <= 32);
    313     and32(TrustedImm32(~(1u << (flag - 1))), AbsoluteAddress(&SamplingFlags::s_flags));
    314 }
    315 #endif
    316 
    317 #if ENABLE(SAMPLING_COUNTERS)
    318 ALWAYS_INLINE void JIT::emitCount(AbstractSamplingCounter& counter, uint32_t count)
    319 {
    320 #if CPU(X86_64) // Or any other 64-bit plattform.
    321     addPtr(TrustedImm32(count), AbsoluteAddress(counter.addressOfCounter()));
    322 #elif CPU(X86) // Or any other little-endian 32-bit plattform.
    323     intptr_t hiWord = reinterpret_cast<intptr_t>(counter.addressOfCounter()) + sizeof(int32_t);
    324     add32(TrustedImm32(count), AbsoluteAddress(counter.addressOfCounter()));
    325     addWithCarry32(TrustedImm32(0), AbsoluteAddress(reinterpret_cast<void*>(hiWord)));
    326 #else
    327 #error "SAMPLING_FLAGS not implemented on this platform."
    328 #endif
    329 }
    330 #endif
    331 
    332 #if ENABLE(OPCODE_SAMPLING)
    333 #if CPU(X86_64)
    334 ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction)
    335 {
    336     move(TrustedImmPtr(m_interpreter->sampler()->sampleSlot()), X86Registers::ecx);
    337     storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), X86Registers::ecx);
    338 }
    339 #else
    340 ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction)
    341 {
    342     storePtr(TrustedImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), m_interpreter->sampler()->sampleSlot());
    343 }
    344 #endif
    345 #endif
    346 
    347 #if ENABLE(CODEBLOCK_SAMPLING)
    348 #if CPU(X86_64)
    349 ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock)
    350 {
    351     move(TrustedImmPtr(m_interpreter->sampler()->codeBlockSlot()), X86Registers::ecx);
    352     storePtr(TrustedImmPtr(codeBlock), X86Registers::ecx);
    353 }
    354 #else
    355 ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock)
    356 {
    357     storePtr(TrustedImmPtr(codeBlock), m_interpreter->sampler()->codeBlockSlot());
    358 }
    359 #endif
    360 #endif
    361 
    362 ALWAYS_INLINE bool JIT::isOperandConstantImmediateChar(unsigned src)
    363 {
    364     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isString() && asString(getConstantOperand(src).asCell())->length() == 1;
    365 }
    366 
    367 #if USE(JSVALUE32_64)
    368 
    369 inline void JIT::emitLoadTag(unsigned index, RegisterID tag)
    370 {
    371     RegisterID mappedTag;
    372     if (getMappedTag(index, mappedTag)) {
    373         move(mappedTag, tag);
    374         unmap(tag);
    375         return;
    376     }
    377 
    378     if (m_codeBlock->isConstantRegisterIndex(index)) {
    379         move(Imm32(getConstantOperand(index).tag()), tag);
    380         unmap(tag);
    381         return;
    382     }
    383 
    384     load32(tagFor(index), tag);
    385     unmap(tag);
    386 }
    387 
    388 inline void JIT::emitLoadPayload(unsigned index, RegisterID payload)
    389 {
    390     RegisterID mappedPayload;
    391     if (getMappedPayload(index, mappedPayload)) {
    392         move(mappedPayload, payload);
    393         unmap(payload);
    394         return;
    395     }
    396 
    397     if (m_codeBlock->isConstantRegisterIndex(index)) {
    398         move(Imm32(getConstantOperand(index).payload()), payload);
    399         unmap(payload);
    400         return;
    401     }
    402 
    403     load32(payloadFor(index), payload);
    404     unmap(payload);
    405 }
    406 
    407 inline void JIT::emitLoad(const JSValue& v, RegisterID tag, RegisterID payload)
    408 {
    409     move(Imm32(v.payload()), payload);
    410     move(Imm32(v.tag()), tag);
    411 }
    412 
    413 inline void JIT::emitLoad(unsigned index, RegisterID tag, RegisterID payload, RegisterID base)
    414 {
    415     ASSERT(tag != payload);
    416 
    417     if (base == callFrameRegister) {
    418         ASSERT(payload != base);
    419         emitLoadPayload(index, payload);
    420         emitLoadTag(index, tag);
    421         return;
    422     }
    423 
    424     if (payload == base) { // avoid stomping base
    425         load32(tagFor(index, base), tag);
    426         load32(payloadFor(index, base), payload);
    427         return;
    428     }
    429 
    430     load32(payloadFor(index, base), payload);
    431     load32(tagFor(index, base), tag);
    432 }
    433 
    434 inline void JIT::emitLoad2(unsigned index1, RegisterID tag1, RegisterID payload1, unsigned index2, RegisterID tag2, RegisterID payload2)
    435 {
    436     if (isMapped(index1)) {
    437         emitLoad(index1, tag1, payload1);
    438         emitLoad(index2, tag2, payload2);
    439         return;
    440     }
    441     emitLoad(index2, tag2, payload2);
    442     emitLoad(index1, tag1, payload1);
    443 }
    444 
    445 inline void JIT::emitLoadDouble(unsigned index, FPRegisterID value)
    446 {
    447     if (m_codeBlock->isConstantRegisterIndex(index)) {
    448         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
    449         loadDouble(&inConstantPool, value);
    450     } else
    451         loadDouble(addressFor(index), value);
    452 }
    453 
    454 inline void JIT::emitLoadInt32ToDouble(unsigned index, FPRegisterID value)
    455 {
    456     if (m_codeBlock->isConstantRegisterIndex(index)) {
    457         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
    458         char* bytePointer = reinterpret_cast<char*>(&inConstantPool);
    459         convertInt32ToDouble(AbsoluteAddress(bytePointer + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), value);
    460     } else
    461         convertInt32ToDouble(payloadFor(index), value);
    462 }
    463 
    464 inline void JIT::emitStore(unsigned index, RegisterID tag, RegisterID payload, RegisterID base)
    465 {
    466     store32(payload, payloadFor(index, base));
    467     store32(tag, tagFor(index, base));
    468 }
    469 
    470 inline void JIT::emitStoreInt32(unsigned index, RegisterID payload, bool indexIsInt32)
    471 {
    472     store32(payload, payloadFor(index, callFrameRegister));
    473     if (!indexIsInt32)
    474         store32(TrustedImm32(JSValue::Int32Tag), tagFor(index, callFrameRegister));
    475 }
    476 
    477 inline void JIT::emitStoreInt32(unsigned index, TrustedImm32 payload, bool indexIsInt32)
    478 {
    479     store32(payload, payloadFor(index, callFrameRegister));
    480     if (!indexIsInt32)
    481         store32(TrustedImm32(JSValue::Int32Tag), tagFor(index, callFrameRegister));
    482 }
    483 
    484 inline void JIT::emitStoreCell(unsigned index, RegisterID payload, bool indexIsCell)
    485 {
    486     store32(payload, payloadFor(index, callFrameRegister));
    487     if (!indexIsCell)
    488         store32(TrustedImm32(JSValue::CellTag), tagFor(index, callFrameRegister));
    489 }
    490 
    491 inline void JIT::emitStoreBool(unsigned index, RegisterID payload, bool indexIsBool)
    492 {
    493     store32(payload, payloadFor(index, callFrameRegister));
    494     if (!indexIsBool)
    495         store32(TrustedImm32(JSValue::BooleanTag), tagFor(index, callFrameRegister));
    496 }
    497 
    498 inline void JIT::emitStoreDouble(unsigned index, FPRegisterID value)
    499 {
    500     storeDouble(value, addressFor(index));
    501 }
    502 
    503 inline void JIT::emitStore(unsigned index, const JSValue constant, RegisterID base)
    504 {
    505     store32(Imm32(constant.payload()), payloadFor(index, base));
    506     store32(Imm32(constant.tag()), tagFor(index, base));
    507 }
    508 
    509 ALWAYS_INLINE void JIT::emitInitRegister(unsigned dst)
    510 {
    511     emitStore(dst, jsUndefined());
    512 }
    513 
    514 inline bool JIT::isLabeled(unsigned bytecodeOffset)
    515 {
    516     for (size_t numberOfJumpTargets = m_codeBlock->numberOfJumpTargets(); m_jumpTargetIndex != numberOfJumpTargets; ++m_jumpTargetIndex) {
    517         unsigned jumpTarget = m_codeBlock->jumpTarget(m_jumpTargetIndex);
    518         if (jumpTarget == bytecodeOffset)
    519             return true;
    520         if (jumpTarget > bytecodeOffset)
    521             return false;
    522     }
    523     return false;
    524 }
    525 
    526 inline void JIT::map(unsigned bytecodeOffset, unsigned virtualRegisterIndex, RegisterID tag, RegisterID payload)
    527 {
    528     if (isLabeled(bytecodeOffset))
    529         return;
    530 
    531     m_mappedBytecodeOffset = bytecodeOffset;
    532     m_mappedVirtualRegisterIndex = virtualRegisterIndex;
    533     m_mappedTag = tag;
    534     m_mappedPayload = payload;
    535 }
    536 
    537 inline void JIT::unmap(RegisterID registerID)
    538 {
    539     if (m_mappedTag == registerID)
    540         m_mappedTag = (RegisterID)-1;
    541     else if (m_mappedPayload == registerID)
    542         m_mappedPayload = (RegisterID)-1;
    543 }
    544 
    545 inline void JIT::unmap()
    546 {
    547     m_mappedBytecodeOffset = (unsigned)-1;
    548     m_mappedVirtualRegisterIndex = (unsigned)-1;
    549     m_mappedTag = (RegisterID)-1;
    550     m_mappedPayload = (RegisterID)-1;
    551 }
    552 
    553 inline bool JIT::isMapped(unsigned virtualRegisterIndex)
    554 {
    555     if (m_mappedBytecodeOffset != m_bytecodeOffset)
    556         return false;
    557     if (m_mappedVirtualRegisterIndex != virtualRegisterIndex)
    558         return false;
    559     return true;
    560 }
    561 
    562 inline bool JIT::getMappedPayload(unsigned virtualRegisterIndex, RegisterID& payload)
    563 {
    564     if (m_mappedBytecodeOffset != m_bytecodeOffset)
    565         return false;
    566     if (m_mappedVirtualRegisterIndex != virtualRegisterIndex)
    567         return false;
    568     if (m_mappedPayload == (RegisterID)-1)
    569         return false;
    570     payload = m_mappedPayload;
    571     return true;
    572 }
    573 
    574 inline bool JIT::getMappedTag(unsigned virtualRegisterIndex, RegisterID& tag)
    575 {
    576     if (m_mappedBytecodeOffset != m_bytecodeOffset)
    577         return false;
    578     if (m_mappedVirtualRegisterIndex != virtualRegisterIndex)
    579         return false;
    580     if (m_mappedTag == (RegisterID)-1)
    581         return false;
    582     tag = m_mappedTag;
    583     return true;
    584 }
    585 
    586 inline void JIT::emitJumpSlowCaseIfNotJSCell(unsigned virtualRegisterIndex)
    587 {
    588     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) {
    589         if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
    590             addSlowCase(jump());
    591         else
    592             addSlowCase(emitJumpIfNotJSCell(virtualRegisterIndex));
    593     }
    594 }
    595 
    596 inline void JIT::emitJumpSlowCaseIfNotJSCell(unsigned virtualRegisterIndex, RegisterID tag)
    597 {
    598     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex)) {
    599         if (m_codeBlock->isConstantRegisterIndex(virtualRegisterIndex))
    600             addSlowCase(jump());
    601         else
    602             addSlowCase(branch32(NotEqual, tag, TrustedImm32(JSValue::CellTag)));
    603     }
    604 }
    605 
    606 inline void JIT::linkSlowCaseIfNotJSCell(Vector<SlowCaseEntry>::iterator& iter, unsigned virtualRegisterIndex)
    607 {
    608     if (!m_codeBlock->isKnownNotImmediate(virtualRegisterIndex))
    609         linkSlowCase(iter);
    610 }
    611 
    612 ALWAYS_INLINE bool JIT::isOperandConstantImmediateInt(unsigned src)
    613 {
    614     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32();
    615 }
    616 
    617 ALWAYS_INLINE bool JIT::getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant)
    618 {
    619     if (isOperandConstantImmediateInt(op1)) {
    620         constant = getConstantOperand(op1).asInt32();
    621         op = op2;
    622         return true;
    623     }
    624 
    625     if (isOperandConstantImmediateInt(op2)) {
    626         constant = getConstantOperand(op2).asInt32();
    627         op = op1;
    628         return true;
    629     }
    630 
    631     return false;
    632 }
    633 
    634 #else // USE(JSVALUE32_64)
    635 
    636 ALWAYS_INLINE void JIT::killLastResultRegister()
    637 {
    638     m_lastResultBytecodeRegister = std::numeric_limits<int>::max();
    639 }
    640 
    641 // get arg puts an arg from the SF register array into a h/w register
    642 ALWAYS_INLINE void JIT::emitGetVirtualRegister(int src, RegisterID dst)
    643 {
    644     ASSERT(m_bytecodeOffset != (unsigned)-1); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
    645 
    646     // TODO: we want to reuse values that are already in registers if we can - add a register allocator!
    647     if (m_codeBlock->isConstantRegisterIndex(src)) {
    648         JSValue value = m_codeBlock->getConstant(src);
    649         move(ImmPtr(JSValue::encode(value)), dst);
    650         killLastResultRegister();
    651         return;
    652     }
    653 
    654     if (src == m_lastResultBytecodeRegister && m_codeBlock->isTemporaryRegisterIndex(src)) {
    655         bool atJumpTarget = false;
    656         while (m_jumpTargetsPosition < m_codeBlock->numberOfJumpTargets() && m_codeBlock->jumpTarget(m_jumpTargetsPosition) <= m_bytecodeOffset) {
    657             if (m_codeBlock->jumpTarget(m_jumpTargetsPosition) == m_bytecodeOffset)
    658                 atJumpTarget = true;
    659             ++m_jumpTargetsPosition;
    660         }
    661 
    662         if (!atJumpTarget) {
    663             // The argument we want is already stored in eax
    664             if (dst != cachedResultRegister)
    665                 move(cachedResultRegister, dst);
    666             killLastResultRegister();
    667             return;
    668         }
    669     }
    670 
    671     loadPtr(Address(callFrameRegister, src * sizeof(Register)), dst);
    672     killLastResultRegister();
    673 }
    674 
    675 ALWAYS_INLINE void JIT::emitGetVirtualRegisters(int src1, RegisterID dst1, int src2, RegisterID dst2)
    676 {
    677     if (src2 == m_lastResultBytecodeRegister) {
    678         emitGetVirtualRegister(src2, dst2);
    679         emitGetVirtualRegister(src1, dst1);
    680     } else {
    681         emitGetVirtualRegister(src1, dst1);
    682         emitGetVirtualRegister(src2, dst2);
    683     }
    684 }
    685 
    686 ALWAYS_INLINE int32_t JIT::getConstantOperandImmediateInt(unsigned src)
    687 {
    688     return getConstantOperand(src).asInt32();
    689 }
    690 
    691 ALWAYS_INLINE bool JIT::isOperandConstantImmediateInt(unsigned src)
    692 {
    693     return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isInt32();
    694 }
    695 
    696 ALWAYS_INLINE void JIT::emitPutVirtualRegister(unsigned dst, RegisterID from)
    697 {
    698     storePtr(from, Address(callFrameRegister, dst * sizeof(Register)));
    699     m_lastResultBytecodeRegister = (from == cachedResultRegister) ? static_cast<int>(dst) : std::numeric_limits<int>::max();
    700 }
    701 
    702 ALWAYS_INLINE void JIT::emitInitRegister(unsigned dst)
    703 {
    704     storePtr(TrustedImmPtr(JSValue::encode(jsUndefined())), Address(callFrameRegister, dst * sizeof(Register)));
    705 }
    706 
    707 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfJSCell(RegisterID reg)
    708 {
    709 #if USE(JSVALUE64)
    710     return branchTestPtr(Zero, reg, tagMaskRegister);
    711 #else
    712     return branchTest32(Zero, reg, TrustedImm32(TagMask));
    713 #endif
    714 }
    715 
    716 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfBothJSCells(RegisterID reg1, RegisterID reg2, RegisterID scratch)
    717 {
    718     move(reg1, scratch);
    719     orPtr(reg2, scratch);
    720     return emitJumpIfJSCell(scratch);
    721 }
    722 
    723 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfJSCell(RegisterID reg)
    724 {
    725     addSlowCase(emitJumpIfJSCell(reg));
    726 }
    727 
    728 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotJSCell(RegisterID reg)
    729 {
    730 #if USE(JSVALUE64)
    731     return branchTestPtr(NonZero, reg, tagMaskRegister);
    732 #else
    733     return branchTest32(NonZero, reg, TrustedImm32(TagMask));
    734 #endif
    735 }
    736 
    737 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg)
    738 {
    739     addSlowCase(emitJumpIfNotJSCell(reg));
    740 }
    741 
    742 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotJSCell(RegisterID reg, int vReg)
    743 {
    744     if (!m_codeBlock->isKnownNotImmediate(vReg))
    745         emitJumpSlowCaseIfNotJSCell(reg);
    746 }
    747 
    748 #if USE(JSVALUE64)
    749 
    750 inline void JIT::emitLoadDouble(unsigned index, FPRegisterID value)
    751 {
    752     if (m_codeBlock->isConstantRegisterIndex(index)) {
    753         WriteBarrier<Unknown>& inConstantPool = m_codeBlock->constantRegister(index);
    754         loadDouble(&inConstantPool, value);
    755     } else
    756         loadDouble(addressFor(index), value);
    757 }
    758 
    759 inline void JIT::emitLoadInt32ToDouble(unsigned index, FPRegisterID value)
    760 {
    761     if (m_codeBlock->isConstantRegisterIndex(index)) {
    762         ASSERT(isOperandConstantImmediateInt(index));
    763         convertInt32ToDouble(Imm32(getConstantOperand(index).asInt32()), value);
    764     } else
    765         convertInt32ToDouble(addressFor(index), value);
    766 }
    767 #endif
    768 
    769 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfImmediateInteger(RegisterID reg)
    770 {
    771 #if USE(JSVALUE64)
    772     return branchPtr(AboveOrEqual, reg, tagTypeNumberRegister);
    773 #else
    774     return branchTest32(NonZero, reg, TrustedImm32(TagTypeNumber));
    775 #endif
    776 }
    777 
    778 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateInteger(RegisterID reg)
    779 {
    780 #if USE(JSVALUE64)
    781     return branchPtr(Below, reg, tagTypeNumberRegister);
    782 #else
    783     return branchTest32(Zero, reg, TrustedImm32(TagTypeNumber));
    784 #endif
    785 }
    786 
    787 ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateIntegers(RegisterID reg1, RegisterID reg2, RegisterID scratch)
    788 {
    789     move(reg1, scratch);
    790     andPtr(reg2, scratch);
    791     return emitJumpIfNotImmediateInteger(scratch);
    792 }
    793 
    794 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateInteger(RegisterID reg)
    795 {
    796     addSlowCase(emitJumpIfNotImmediateInteger(reg));
    797 }
    798 
    799 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateIntegers(RegisterID reg1, RegisterID reg2, RegisterID scratch)
    800 {
    801     addSlowCase(emitJumpIfNotImmediateIntegers(reg1, reg2, scratch));
    802 }
    803 
    804 ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateNumber(RegisterID reg)
    805 {
    806     addSlowCase(emitJumpIfNotImmediateNumber(reg));
    807 }
    808 
    809 #if USE(JSVALUE32_64)
    810 ALWAYS_INLINE void JIT::emitFastArithDeTagImmediate(RegisterID reg)
    811 {
    812     subPtr(TrustedImm32(TagTypeNumber), reg);
    813 }
    814 
    815 ALWAYS_INLINE JIT::Jump JIT::emitFastArithDeTagImmediateJumpIfZero(RegisterID reg)
    816 {
    817     return branchSubPtr(Zero, TrustedImm32(TagTypeNumber), reg);
    818 }
    819 #endif
    820 
    821 ALWAYS_INLINE void JIT::emitFastArithReTagImmediate(RegisterID src, RegisterID dest)
    822 {
    823 #if USE(JSVALUE64)
    824     emitFastArithIntToImmNoCheck(src, dest);
    825 #else
    826     if (src != dest)
    827         move(src, dest);
    828     addPtr(TrustedImm32(TagTypeNumber), dest);
    829 #endif
    830 }
    831 
    832 // operand is int32_t, must have been zero-extended if register is 64-bit.
    833 ALWAYS_INLINE void JIT::emitFastArithIntToImmNoCheck(RegisterID src, RegisterID dest)
    834 {
    835 #if USE(JSVALUE64)
    836     if (src != dest)
    837         move(src, dest);
    838     orPtr(tagTypeNumberRegister, dest);
    839 #else
    840     signExtend32ToPtr(src, dest);
    841     addPtr(dest, dest);
    842     emitFastArithReTagImmediate(dest, dest);
    843 #endif
    844 }
    845 
    846 ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg)
    847 {
    848     or32(TrustedImm32(static_cast<int32_t>(ValueFalse)), reg);
    849 }
    850 
    851 #endif // USE(JSVALUE32_64)
    852 
    853 } // namespace JSC
    854 
    855 #endif // ENABLE(JIT)
    856 
    857 #endif
    858