Index: src/arm/assembler-arm-inl.h |
diff --git a/src/arm/assembler-arm-inl.h b/src/arm/assembler-arm-inl.h |
index 2c44c78993f2d284c1ed07b8638ff77874654519..f5b901578e3a0e1d75d12dfb8ab64407e82d9360 100644 |
--- a/src/arm/assembler-arm-inl.h |
+++ b/src/arm/assembler-arm-inl.h |
@@ -429,8 +429,15 @@ Address Assembler::target_address_from_return_address(Address pc) { |
// movt ip, #... @ call address high 16 |
// blx ip |
// @ return address |
- // Or pre-V7 or cases that need frequent patching: |
- // ldr ip, [pc, #...] @ call address |
+ // Or pre-V7 or cases that need frequent patching, the address is in the |
+ // constant pool. It could be a small constant pool load: |
+ // ldr ip, [pc / pp, #...] @ call address |
+ // blx ip |
+ // @ return address |
+ // Or an extended constant pool load: |
+ // movw ip, #... |
+ // movt ip, #... |
+ // ldr ip, [pc, ip] @ call address |
// blx ip |
// @ return address |
Address candidate = pc - 2 * Assembler::kInstrSize; |
@@ -438,22 +445,35 @@ Address Assembler::target_address_from_return_address(Address pc) { |
if (IsLdrPcImmediateOffset(candidate_instr) | |
IsLdrPpImmediateOffset(candidate_instr)) { |
return candidate; |
+ } else if (IsLdrPpRegOffset(candidate_instr)) { |
+ candidate = pc - 4 * Assembler::kInstrSize; |
+ ASSERT(IsMovW(Memory::int32_at(candidate)) && |
+ IsMovT(Memory::int32_at(candidate + Assembler::kInstrSize))); |
+ return candidate; |
+ } else { |
+ candidate = pc - 3 * Assembler::kInstrSize; |
+ ASSERT(IsMovW(Memory::int32_at(candidate)) && |
+ IsMovT(Memory::int32_at(candidate + kInstrSize))); |
+ return candidate; |
} |
- candidate = pc - 3 * Assembler::kInstrSize; |
- ASSERT(IsMovW(Memory::int32_at(candidate)) && |
- IsMovT(Memory::int32_at(candidate + kInstrSize))); |
- return candidate; |
} |
Address Assembler::return_address_from_call_start(Address pc) { |
if (IsLdrPcImmediateOffset(Memory::int32_at(pc)) | |
IsLdrPpImmediateOffset(Memory::int32_at(pc))) { |
+ // Load from constant pool, small section. |
return pc + kInstrSize * 2; |
} else { |
ASSERT(IsMovW(Memory::int32_at(pc))); |
ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize))); |
- return pc + kInstrSize * 3; |
+ if (IsLdrPpRegOffset(Memory::int32_at(pc + kInstrSize))) { |
+ // Load from constant pool, extended section. |
+ return pc + kInstrSize * 4; |
+ } else { |
+ // A movw / movt load immediate. |
+ return pc + kInstrSize * 3; |
+ } |
} |
} |
@@ -468,20 +488,11 @@ void Assembler::deserialization_set_special_target_at( |
} |
-static Instr EncodeMovwImmediate(uint32_t immediate) { |
- ASSERT(immediate < 0x10000); |
- return ((immediate & 0xf000) << 4) | (immediate & 0xfff); |
-} |
- |
- |
-static Instr PatchMovwImmediate(Instr instruction, uint32_t immediate) { |
- instruction &= ~EncodeMovwImmediate(0xffff); |
- return instruction | EncodeMovwImmediate(immediate); |
-} |
- |
- |
-static bool IsConstantPoolLoad(Address pc) { |
- return !Assembler::IsMovW(Memory::int32_at(pc)); |
+bool Assembler::is_constant_pool_load(Address pc) { |
+ return !Assembler::IsMovW(Memory::int32_at(pc)) || |
+ (FLAG_enable_ool_constant_pool && |
+ Assembler::IsLdrPpRegOffset( |
+ Memory::int32_at(pc + 2 * Assembler::kInstrSize))); |
} |
@@ -489,9 +500,21 @@ Address Assembler::constant_pool_entry_address( |
Address pc, ConstantPoolArray* constant_pool) { |
if (FLAG_enable_ool_constant_pool) { |
ASSERT(constant_pool != NULL); |
- ASSERT(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(pc))); |
- return reinterpret_cast<Address>(constant_pool) + |
- GetLdrRegisterImmediateOffset(Memory::int32_at(pc)); |
+ int cp_offset; |
+ if (IsMovW(Memory::int32_at(pc))) { |
+ ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)) && |
+ IsLdrPpRegOffset(Memory::int32_at(pc + 2 * kInstrSize))); |
+ // This is an extended constant pool lookup. |
+ Instruction* movw_instr = Instruction::At(pc); |
+ Instruction* movt_instr = Instruction::At(pc + kInstrSize); |
+ cp_offset = (movt_instr->ImmedMovwMovtValue() << 16) | |
+ movw_instr->ImmedMovwMovtValue(); |
+ } else { |
+ // This is a small constant pool lookup. |
+ ASSERT(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(pc))); |
+ cp_offset = GetLdrRegisterImmediateOffset(Memory::int32_at(pc)); |
+ } |
+ return reinterpret_cast<Address>(constant_pool) + cp_offset; |
} else { |
ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc))); |
Instr instr = Memory::int32_at(pc); |
@@ -502,7 +525,7 @@ Address Assembler::constant_pool_entry_address( |
Address Assembler::target_address_at(Address pc, |
ConstantPoolArray* constant_pool) { |
- if (IsConstantPoolLoad(pc)) { |
+ if (is_constant_pool_load(pc)) { |
// This is a constant pool lookup. Return the value in the constant pool. |
return Memory::Address_at(constant_pool_entry_address(pc, constant_pool)); |
} else { |
@@ -522,7 +545,7 @@ void Assembler::set_target_address_at(Address pc, |
ConstantPoolArray* constant_pool, |
Address target, |
ICacheFlushMode icache_flush_mode) { |
- if (IsConstantPoolLoad(pc)) { |
+ if (is_constant_pool_load(pc)) { |
// This is a constant pool lookup. Update the entry in the constant pool. |
Memory::Address_at(constant_pool_entry_address(pc, constant_pool)) = target; |
// Intuitively, we would think it is necessary to always flush the |