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 |