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