| OLD | NEW |
| 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. | 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. |
| 2 // All Rights Reserved. | 2 // All Rights Reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions | 5 // modification, are permitted provided that the following conditions |
| 6 // are met: | 6 // are met: |
| 7 // | 7 // |
| 8 // - Redistributions of source code must retain the above copyright notice, | 8 // - Redistributions of source code must retain the above copyright notice, |
| 9 // this list of conditions and the following disclaimer. | 9 // this list of conditions and the following disclaimer. |
| 10 // | 10 // |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 ASSERT(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) | 112 ASSERT(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) |
| 113 || rmode_ == EMBEDDED_OBJECT | 113 || rmode_ == EMBEDDED_OBJECT |
| 114 || rmode_ == EXTERNAL_REFERENCE); | 114 || rmode_ == EXTERNAL_REFERENCE); |
| 115 if (FLAG_enable_ool_constant_pool || | 115 if (FLAG_enable_ool_constant_pool || |
| 116 Assembler::IsMovW(Memory::int32_at(pc_))) { | 116 Assembler::IsMovW(Memory::int32_at(pc_))) { |
| 117 // We return the PC for ool constant pool since this function is used by the | 117 // We return the PC for ool constant pool since this function is used by the |
| 118 // serializerer and expects the address to reside within the code object. | 118 // serializerer and expects the address to reside within the code object. |
| 119 return reinterpret_cast<Address>(pc_); | 119 return reinterpret_cast<Address>(pc_); |
| 120 } else { | 120 } else { |
| 121 ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_))); | 121 ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_))); |
| 122 return Assembler::target_pointer_address_at(pc_); | 122 return constant_pool_entry_address(); |
| 123 } | 123 } |
| 124 } | 124 } |
| 125 | 125 |
| 126 | 126 |
| 127 Address RelocInfo::constant_pool_entry_address() { | 127 Address RelocInfo::constant_pool_entry_address() { |
| 128 ASSERT(IsInConstantPool()); | 128 ASSERT(IsInConstantPool()); |
| 129 if (FLAG_enable_ool_constant_pool) { | 129 return Assembler::constant_pool_entry_address(pc_, host_->constant_pool()); |
| 130 ASSERT(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(pc_))); | |
| 131 return Assembler::target_constant_pool_address_at(pc_, | |
| 132 host_->constant_pool()); | |
| 133 } else { | |
| 134 ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_))); | |
| 135 return Assembler::target_pointer_address_at(pc_); | |
| 136 } | |
| 137 } | 130 } |
| 138 | 131 |
| 139 | 132 |
| 140 int RelocInfo::target_address_size() { | 133 int RelocInfo::target_address_size() { |
| 141 return kPointerSize; | 134 return kPointerSize; |
| 142 } | 135 } |
| 143 | 136 |
| 144 | 137 |
| 145 void RelocInfo::set_target_address(Address target, | 138 void RelocInfo::set_target_address(Address target, |
| 146 WriteBarrierMode write_barrier_mode, | 139 WriteBarrierMode write_barrier_mode, |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 Assembler::set_target_address_at(pc_, host_, NULL); | 300 Assembler::set_target_address_at(pc_, host_, NULL); |
| 308 } | 301 } |
| 309 | 302 |
| 310 | 303 |
| 311 bool RelocInfo::IsPatchedReturnSequence() { | 304 bool RelocInfo::IsPatchedReturnSequence() { |
| 312 Instr current_instr = Assembler::instr_at(pc_); | 305 Instr current_instr = Assembler::instr_at(pc_); |
| 313 Instr next_instr = Assembler::instr_at(pc_ + Assembler::kInstrSize); | 306 Instr next_instr = Assembler::instr_at(pc_ + Assembler::kInstrSize); |
| 314 // A patched return sequence is: | 307 // A patched return sequence is: |
| 315 // ldr ip, [pc, #0] | 308 // ldr ip, [pc, #0] |
| 316 // blx ip | 309 // blx ip |
| 317 return ((current_instr & kLdrPCMask) == kLdrPCPattern) | 310 return Assembler::IsLdrPcImmediateOffset(current_instr) && |
| 318 && ((next_instr & kBlxRegMask) == kBlxRegPattern); | 311 Assembler::IsBlxReg(next_instr); |
| 319 } | 312 } |
| 320 | 313 |
| 321 | 314 |
| 322 bool RelocInfo::IsPatchedDebugBreakSlotSequence() { | 315 bool RelocInfo::IsPatchedDebugBreakSlotSequence() { |
| 323 Instr current_instr = Assembler::instr_at(pc_); | 316 Instr current_instr = Assembler::instr_at(pc_); |
| 324 return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP); | 317 return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP); |
| 325 } | 318 } |
| 326 | 319 |
| 327 | 320 |
| 328 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) { | 321 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) { |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 } | 414 } |
| 422 | 415 |
| 423 | 416 |
| 424 void Assembler::emit(Instr x) { | 417 void Assembler::emit(Instr x) { |
| 425 CheckBuffer(); | 418 CheckBuffer(); |
| 426 *reinterpret_cast<Instr*>(pc_) = x; | 419 *reinterpret_cast<Instr*>(pc_) = x; |
| 427 pc_ += kInstrSize; | 420 pc_ += kInstrSize; |
| 428 } | 421 } |
| 429 | 422 |
| 430 | 423 |
| 431 Address Assembler::target_pointer_address_at(Address pc) { | |
| 432 Instr instr = Memory::int32_at(pc); | |
| 433 return pc + GetLdrRegisterImmediateOffset(instr) + kPcLoadDelta; | |
| 434 } | |
| 435 | |
| 436 | |
| 437 Address Assembler::target_constant_pool_address_at( | |
| 438 Address pc, ConstantPoolArray* constant_pool) { | |
| 439 ASSERT(constant_pool != NULL); | |
| 440 ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc))); | |
| 441 Instr instr = Memory::int32_at(pc); | |
| 442 return reinterpret_cast<Address>(constant_pool) + | |
| 443 GetLdrRegisterImmediateOffset(instr); | |
| 444 } | |
| 445 | |
| 446 | |
| 447 Address Assembler::target_address_at(Address pc, | |
| 448 ConstantPoolArray* constant_pool) { | |
| 449 if (IsMovW(Memory::int32_at(pc))) { | |
| 450 ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize))); | |
| 451 Instruction* instr = Instruction::At(pc); | |
| 452 Instruction* next_instr = Instruction::At(pc + kInstrSize); | |
| 453 return reinterpret_cast<Address>( | |
| 454 (next_instr->ImmedMovwMovtValue() << 16) | | |
| 455 instr->ImmedMovwMovtValue()); | |
| 456 } else if (FLAG_enable_ool_constant_pool) { | |
| 457 ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc))); | |
| 458 return Memory::Address_at( | |
| 459 target_constant_pool_address_at(pc, constant_pool)); | |
| 460 } else { | |
| 461 ASSERT(IsLdrPcImmediateOffset(Memory::int32_at(pc))); | |
| 462 return Memory::Address_at(target_pointer_address_at(pc)); | |
| 463 } | |
| 464 } | |
| 465 | |
| 466 | |
| 467 Address Assembler::target_address_from_return_address(Address pc) { | 424 Address Assembler::target_address_from_return_address(Address pc) { |
| 468 // Returns the address of the call target from the return address that will | 425 // Returns the address of the call target from the return address that will |
| 469 // be returned to after a call. | 426 // be returned to after a call. |
| 470 // Call sequence on V7 or later is : | 427 // Call sequence on V7 or later is : |
| 471 // movw ip, #... @ call address low 16 | 428 // movw ip, #... @ call address low 16 |
| 472 // movt ip, #... @ call address high 16 | 429 // movt ip, #... @ call address high 16 |
| 473 // blx ip | 430 // blx ip |
| 474 // @ return address | 431 // @ return address |
| 475 // Or pre-V7 or cases that need frequent patching: | 432 // Or pre-V7 or cases that need frequent patching: |
| 476 // ldr ip, [pc, #...] @ call address | 433 // ldr ip, [pc, #...] @ call address |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 return ((immediate & 0xf000) << 4) | (immediate & 0xfff); | 473 return ((immediate & 0xf000) << 4) | (immediate & 0xfff); |
| 517 } | 474 } |
| 518 | 475 |
| 519 | 476 |
| 520 static Instr PatchMovwImmediate(Instr instruction, uint32_t immediate) { | 477 static Instr PatchMovwImmediate(Instr instruction, uint32_t immediate) { |
| 521 instruction &= ~EncodeMovwImmediate(0xffff); | 478 instruction &= ~EncodeMovwImmediate(0xffff); |
| 522 return instruction | EncodeMovwImmediate(immediate); | 479 return instruction | EncodeMovwImmediate(immediate); |
| 523 } | 480 } |
| 524 | 481 |
| 525 | 482 |
| 483 static bool IsConstantPoolLoad(Address pc) { |
| 484 return !Assembler::IsMovW(Memory::int32_at(pc)); |
| 485 } |
| 486 |
| 487 |
| 488 Address Assembler::constant_pool_entry_address( |
| 489 Address pc, ConstantPoolArray* constant_pool) { |
| 490 if (FLAG_enable_ool_constant_pool) { |
| 491 ASSERT(constant_pool != NULL); |
| 492 ASSERT(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(pc))); |
| 493 return reinterpret_cast<Address>(constant_pool) + |
| 494 GetLdrRegisterImmediateOffset(Memory::int32_at(pc)); |
| 495 } else { |
| 496 ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc))); |
| 497 Instr instr = Memory::int32_at(pc); |
| 498 return pc + GetLdrRegisterImmediateOffset(instr) + kPcLoadDelta; |
| 499 } |
| 500 } |
| 501 |
| 502 |
| 503 Address Assembler::target_address_at(Address pc, |
| 504 ConstantPoolArray* constant_pool) { |
| 505 if (IsConstantPoolLoad(pc)) { |
| 506 // This is a constant pool lookup. Return the value in the constant pool. |
| 507 return Memory::Address_at(constant_pool_entry_address(pc, constant_pool)); |
| 508 } else { |
| 509 // This is an movw_movt immediate load. Return the immediate. |
| 510 ASSERT(IsMovW(Memory::int32_at(pc)) && |
| 511 IsMovT(Memory::int32_at(pc + kInstrSize))); |
| 512 Instruction* movw_instr = Instruction::At(pc); |
| 513 Instruction* movt_instr = Instruction::At(pc + kInstrSize); |
| 514 return reinterpret_cast<Address>( |
| 515 (movt_instr->ImmedMovwMovtValue() << 16) | |
| 516 movw_instr->ImmedMovwMovtValue()); |
| 517 } |
| 518 } |
| 519 |
| 520 |
| 526 void Assembler::set_target_address_at(Address pc, | 521 void Assembler::set_target_address_at(Address pc, |
| 527 ConstantPoolArray* constant_pool, | 522 ConstantPoolArray* constant_pool, |
| 528 Address target, | 523 Address target, |
| 529 ICacheFlushMode icache_flush_mode) { | 524 ICacheFlushMode icache_flush_mode) { |
| 530 if (IsMovW(Memory::int32_at(pc))) { | 525 if (IsConstantPoolLoad(pc)) { |
| 526 // This is a constant pool lookup. Update the entry in the constant pool. |
| 527 Memory::Address_at(constant_pool_entry_address(pc, constant_pool)) = target; |
| 528 // Intuitively, we would think it is necessary to always flush the |
| 529 // instruction cache after patching a target address in the code as follows: |
| 530 // CPU::FlushICache(pc, sizeof(target)); |
| 531 // However, on ARM, no instruction is actually patched in the case |
| 532 // of embedded constants of the form: |
| 533 // ldr ip, [pp, #...] |
| 534 // since the instruction accessing this address in the constant pool remains |
| 535 // unchanged. |
| 536 } else { |
| 537 // This is an movw_movt immediate load. Patch the immediate embedded in the |
| 538 // instructions. |
| 539 ASSERT(IsMovW(Memory::int32_at(pc))); |
| 531 ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize))); | 540 ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize))); |
| 532 uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc); | 541 uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc); |
| 533 uint32_t immediate = reinterpret_cast<uint32_t>(target); | 542 uint32_t immediate = reinterpret_cast<uint32_t>(target); |
| 534 instr_ptr[0] = PatchMovwImmediate(instr_ptr[0], immediate & 0xFFFF); | 543 instr_ptr[0] = PatchMovwImmediate(instr_ptr[0], immediate & 0xFFFF); |
| 535 instr_ptr[1] = PatchMovwImmediate(instr_ptr[1], immediate >> 16); | 544 instr_ptr[1] = PatchMovwImmediate(instr_ptr[1], immediate >> 16); |
| 536 ASSERT(IsMovW(Memory::int32_at(pc))); | 545 ASSERT(IsMovW(Memory::int32_at(pc))); |
| 537 ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize))); | 546 ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize))); |
| 538 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { | 547 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { |
| 539 CPU::FlushICache(pc, 2 * kInstrSize); | 548 CPU::FlushICache(pc, 2 * kInstrSize); |
| 540 } | 549 } |
| 541 } else if (FLAG_enable_ool_constant_pool) { | |
| 542 ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc))); | |
| 543 Memory::Address_at( | |
| 544 target_constant_pool_address_at(pc, constant_pool)) = target; | |
| 545 } else { | |
| 546 ASSERT(IsLdrPcImmediateOffset(Memory::int32_at(pc))); | |
| 547 Memory::Address_at(target_pointer_address_at(pc)) = target; | |
| 548 // Intuitively, we would think it is necessary to always flush the | |
| 549 // instruction cache after patching a target address in the code as follows: | |
| 550 // CPU::FlushICache(pc, sizeof(target)); | |
| 551 // However, on ARM, no instruction is actually patched in the case | |
| 552 // of embedded constants of the form: | |
| 553 // ldr ip, [pc, #...] | |
| 554 // since the instruction accessing this address in the constant pool remains | |
| 555 // unchanged. | |
| 556 } | 550 } |
| 557 } | 551 } |
| 558 | 552 |
| 559 | 553 |
| 560 } } // namespace v8::internal | 554 } } // namespace v8::internal |
| 561 | 555 |
| 562 #endif // V8_ARM_ASSEMBLER_ARM_INL_H_ | 556 #endif // V8_ARM_ASSEMBLER_ARM_INL_H_ |
| OLD | NEW |