Index: src/arm/assembler-arm-inl.h |
diff --git a/src/arm/assembler-arm-inl.h b/src/arm/assembler-arm-inl.h |
index 1cfe34b241fc1ab804032d2babe2126afec9eab2..8b5c4b8c5634b4bf33d2f010f46e82ae9063246d 100644 |
--- a/src/arm/assembler-arm-inl.h |
+++ b/src/arm/assembler-arm-inl.h |
@@ -423,36 +423,58 @@ void Assembler::emit(Instr x) { |
Address Assembler::target_address_from_return_address(Address pc) { |
// Returns the address of the call target from the return address that will |
// be returned to after a call. |
- // Call sequence on V7 or later is : |
+ // Call sequence on V7 or later is: |
// movw ip, #... @ call address low 16 |
// movt ip, #... @ call address high 16 |
// blx ip |
// @ return address |
- // Or pre-V7 or cases that need frequent patching, the address is in the |
+ // For V6 when the constant pool is unavailable, it is: |
+ // mov ip, #... @ call address low 8 |
+ // orr ip, ip, #... @ call address 2nd 8 |
+ // orr ip, ip, #... @ call address 3rd 8 |
+ // orr ip, ip, #... @ call address high 8 |
+ // blx ip |
+ // @ return address |
+ // In 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: |
+ // Or an extended constant pool load (ARMv7): |
// movw ip, #... |
// movt ip, #... |
// ldr ip, [pc, ip] @ call address |
// blx ip |
// @ return address |
+ // Or an extended constant pool load (ARMv6): |
+ // mov ip, #... |
+ // orr ip, ip, #... |
+ // orr ip, ip, #... |
+ // orr ip, ip, #... |
+ // ldr ip, [pc, ip] @ call address |
+ // blx ip |
+ // @ return address |
Address candidate = pc - 2 * Assembler::kInstrSize; |
Instr candidate_instr(Memory::int32_at(candidate)); |
if (IsLdrPcImmediateOffset(candidate_instr) | |
IsLdrPpImmediateOffset(candidate_instr)) { |
return candidate; |
- } else if (IsLdrPpRegOffset(candidate_instr)) { |
- candidate = pc - 4 * Assembler::kInstrSize; |
- DCHECK(IsMovW(Memory::int32_at(candidate)) && |
- IsMovT(Memory::int32_at(candidate + Assembler::kInstrSize))); |
- return candidate; |
} else { |
- candidate = pc - 3 * Assembler::kInstrSize; |
- DCHECK(IsMovW(Memory::int32_at(candidate)) && |
- IsMovT(Memory::int32_at(candidate + kInstrSize))); |
+ if (IsLdrPpRegOffset(candidate_instr)) { |
+ candidate -= Assembler::kInstrSize; |
+ } |
+ if (CpuFeatures::IsSupported(ARMv7)) { |
+ candidate -= 1 * Assembler::kInstrSize; |
+ DCHECK(IsMovW(Memory::int32_at(candidate)) && |
+ IsMovT(Memory::int32_at(candidate + Assembler::kInstrSize))); |
+ } else { |
+ candidate -= 3 * Assembler::kInstrSize; |
+ DCHECK( |
+ IsMovImmed(Memory::int32_at(candidate)) && |
+ IsOrrImmed(Memory::int32_at(candidate + Assembler::kInstrSize)) && |
+ IsOrrImmed(Memory::int32_at(candidate + 2 * Assembler::kInstrSize)) && |
+ IsOrrImmed(Memory::int32_at(candidate + 3 * Assembler::kInstrSize))); |
+ } |
return candidate; |
} |
} |
@@ -469,14 +491,28 @@ Address Assembler::return_address_from_call_start(Address pc) { |
// Load from constant pool, small section. |
return pc + kInstrSize * 2; |
} else { |
- DCHECK(IsMovW(Memory::int32_at(pc))); |
- DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize))); |
- if (IsLdrPpRegOffset(Memory::int32_at(pc + kInstrSize))) { |
- // Load from constant pool, extended section. |
- return pc + kInstrSize * 4; |
+ if (CpuFeatures::IsSupported(ARMv7)) { |
+ DCHECK(IsMovW(Memory::int32_at(pc))); |
+ DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize))); |
+ if (IsLdrPpRegOffset(Memory::int32_at(pc + 2 * kInstrSize))) { |
+ // Load from constant pool, extended section. |
+ return pc + kInstrSize * 4; |
+ } else { |
+ // A movw / movt load immediate. |
+ return pc + kInstrSize * 3; |
+ } |
} else { |
- // A movw / movt load immediate. |
- return pc + kInstrSize * 3; |
+ DCHECK(IsMovImmed(Memory::int32_at(pc))); |
+ DCHECK(IsOrrImmed(Memory::int32_at(pc + kInstrSize))); |
+ DCHECK(IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize))); |
+ DCHECK(IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize))); |
+ if (IsLdrPpRegOffset(Memory::int32_at(pc + 4 * kInstrSize))) { |
+ // Load from constant pool, extended section. |
+ return pc + kInstrSize * 6; |
+ } else { |
+ // A mov / orr load immediate. |
+ return pc + kInstrSize * 5; |
+ } |
} |
} |
} |
@@ -493,10 +529,17 @@ void Assembler::deserialization_set_special_target_at( |
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))); |
+ if (CpuFeatures::IsSupported(ARMv7)) { |
+ return !Assembler::IsMovW(Memory::int32_at(pc)) || |
+ (FLAG_enable_ool_constant_pool && |
+ Assembler::IsLdrPpRegOffset( |
+ Memory::int32_at(pc + 2 * Assembler::kInstrSize))); |
+ } else { |
+ return !Assembler::IsMovImmed(Memory::int32_at(pc)) || |
+ (FLAG_enable_ool_constant_pool && |
+ Assembler::IsLdrPpRegOffset( |
+ Memory::int32_at(pc + 4 * Assembler::kInstrSize))); |
+ } |
} |
@@ -505,10 +548,22 @@ Address Assembler::constant_pool_entry_address( |
if (FLAG_enable_ool_constant_pool) { |
DCHECK(constant_pool != NULL); |
int cp_offset; |
- if (IsMovW(Memory::int32_at(pc))) { |
+ if (!CpuFeatures::IsSupported(ARMv7) && IsMovImmed(Memory::int32_at(pc))) { |
+ DCHECK(IsOrrImmed(Memory::int32_at(pc + kInstrSize)) && |
+ IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) && |
+ IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)) && |
+ IsLdrPpRegOffset(Memory::int32_at(pc + 4 * kInstrSize))); |
+ // This is an extended constant pool lookup (ARMv6). |
+ Instr mov_instr = instr_at(pc); |
+ Instr orr_instr_1 = instr_at(pc + kInstrSize); |
+ Instr orr_instr_2 = instr_at(pc + 2 * kInstrSize); |
+ Instr orr_instr_3 = instr_at(pc + 3 * kInstrSize); |
+ cp_offset = DecodeShiftImm(mov_instr) | DecodeShiftImm(orr_instr_1) | |
+ DecodeShiftImm(orr_instr_2) | DecodeShiftImm(orr_instr_3); |
+ } else if (IsMovW(Memory::int32_at(pc))) { |
DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)) && |
IsLdrPpRegOffset(Memory::int32_at(pc + 2 * kInstrSize))); |
- // This is an extended constant pool lookup. |
+ // This is an extended constant pool lookup (ARMv7). |
Instruction* movw_instr = Instruction::At(pc); |
Instruction* movt_instr = Instruction::At(pc + kInstrSize); |
cp_offset = (movt_instr->ImmedMovwMovtValue() << 16) | |
@@ -532,8 +587,8 @@ Address Assembler::target_address_at(Address 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 { |
- // This is an movw_movt immediate load. Return the immediate. |
+ } else if (CpuFeatures::IsSupported(ARMv7)) { |
+ // This is an movw / movt immediate load. Return the immediate. |
DCHECK(IsMovW(Memory::int32_at(pc)) && |
IsMovT(Memory::int32_at(pc + kInstrSize))); |
Instruction* movw_instr = Instruction::At(pc); |
@@ -541,6 +596,20 @@ Address Assembler::target_address_at(Address pc, |
return reinterpret_cast<Address>( |
(movt_instr->ImmedMovwMovtValue() << 16) | |
movw_instr->ImmedMovwMovtValue()); |
+ } else { |
+ // This is an mov / orr immediate load. Return the immediate. |
+ DCHECK(IsMovImmed(Memory::int32_at(pc)) && |
+ IsOrrImmed(Memory::int32_at(pc + kInstrSize)) && |
+ IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) && |
+ IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize))); |
+ Instr mov_instr = instr_at(pc); |
+ Instr orr_instr_1 = instr_at(pc + kInstrSize); |
+ Instr orr_instr_2 = instr_at(pc + 2 * kInstrSize); |
+ Instr orr_instr_3 = instr_at(pc + 3 * kInstrSize); |
+ Address ret = reinterpret_cast<Address>( |
+ DecodeShiftImm(mov_instr) | DecodeShiftImm(orr_instr_1) | |
+ DecodeShiftImm(orr_instr_2) | DecodeShiftImm(orr_instr_3)); |
+ return ret; |
} |
} |
@@ -560,9 +629,9 @@ void Assembler::set_target_address_at(Address pc, |
// ldr ip, [pp, #...] |
// since the instruction accessing this address in the constant pool remains |
// unchanged. |
- } else { |
- // This is an movw_movt immediate load. Patch the immediate embedded in the |
- // instructions. |
+ } else if (CpuFeatures::IsSupported(ARMv7)) { |
+ // This is an movw / movt immediate load. Patch the immediate embedded in |
+ // the instructions. |
DCHECK(IsMovW(Memory::int32_at(pc))); |
DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize))); |
uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc); |
@@ -574,6 +643,26 @@ void Assembler::set_target_address_at(Address pc, |
if (icache_flush_mode != SKIP_ICACHE_FLUSH) { |
CpuFeatures::FlushICache(pc, 2 * kInstrSize); |
} |
+ } else { |
+ // This is an mov / orr immediate load. Patch the immediate embedded in |
+ // the instructions. |
+ DCHECK(IsMovImmed(Memory::int32_at(pc)) && |
+ IsOrrImmed(Memory::int32_at(pc + kInstrSize)) && |
+ IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) && |
+ IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize))); |
+ uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc); |
+ uint32_t immediate = reinterpret_cast<uint32_t>(target); |
+ instr_ptr[0] = PatchShiftImm(instr_ptr[0], immediate & kImm8Mask); |
+ instr_ptr[1] = PatchShiftImm(instr_ptr[1], immediate & (kImm8Mask << 8)); |
+ instr_ptr[2] = PatchShiftImm(instr_ptr[2], immediate & (kImm8Mask << 16)); |
+ instr_ptr[3] = PatchShiftImm(instr_ptr[3], immediate & (kImm8Mask << 24)); |
+ DCHECK(IsMovImmed(Memory::int32_at(pc)) && |
+ IsOrrImmed(Memory::int32_at(pc + kInstrSize)) && |
+ IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) && |
+ IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize))); |
+ if (icache_flush_mode != SKIP_ICACHE_FLUSH) { |
+ CpuFeatures::FlushICache(pc, 4 * kInstrSize); |
+ } |
} |
} |