Index: src/arm/assembler-arm.cc |
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc |
index ae6db3a9bc787af0eae41bd60dbf2f99d73bda10..dd90e4dcd7ae82f10ae8ea78a4dda1cc2c0b2a5e 100644 |
--- a/src/arm/assembler-arm.cc |
+++ b/src/arm/assembler-arm.cc |
@@ -39,6 +39,7 @@ |
#if V8_TARGET_ARCH_ARM |
#include "arm/assembler-arm-inl.h" |
+#include "macro-assembler.h" |
#include "serialize.h" |
namespace v8 { |
@@ -778,9 +779,9 @@ int Assembler::GetCmpImmediateRawImmediate(Instr instr) { |
int Assembler::target_at(int pos) { |
Instr instr = instr_at(pos); |
- if ((instr & ~kImm24Mask) == 0) { |
- // Emitted label constant, not part of a branch. |
- return instr - (Code::kHeaderSize - kHeapObjectTag); |
+ if (is_uint24(instr)) { |
+ // Emitted link to a label, not part of a branch. |
+ return instr; |
} |
ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 |
int imm26 = ((instr & kImm24Mask) << 8) >> 6; |
@@ -795,11 +796,72 @@ int Assembler::target_at(int pos) { |
void Assembler::target_at_put(int pos, int target_pos) { |
Instr instr = instr_at(pos); |
- if ((instr & ~kImm24Mask) == 0) { |
+ if (is_uint24(instr)) { |
ASSERT(target_pos == pos || target_pos >= 0); |
- // Emitted label constant, not part of a branch. |
- // Make label relative to Code* of generated Code object. |
- instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag)); |
+ // Emitted link to a label, not part of a branch. |
+ // Load the position of the label relative to the generated code object |
+ // pointer in a register. |
+ |
+ // Here are the instructions we need to emit: |
+ // For ARMv7: target24 => target16_1:target16_0 |
+ // movw dst, #target16_0 |
+ // movt dst, #target16_1 |
+ // For ARMv6: target24 => target8_2:target8_1:target8_0 |
+ // mov dst, #target8_0 |
+ // orr dst, dst, #target8_1 << 8 |
+ // orr dst, dst, #target8_2 << 16 |
+ |
+ // We extract the destination register from the emitted nop instruction. |
+ Register dst = Register::from_code( |
+ Instruction::RmValue(instr_at(pos + kInstrSize))); |
+ ASSERT(IsNop(instr_at(pos + kInstrSize), dst.code())); |
+ uint32_t target24 = target_pos + (Code::kHeaderSize - kHeapObjectTag); |
+ ASSERT(is_uint24(target24)); |
+ if (is_uint8(target24)) { |
+ // If the target fits in a byte then only patch with a mov |
+ // instruction. |
+ CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), |
+ 1, |
+ CodePatcher::DONT_FLUSH); |
+ patcher.masm()->mov(dst, Operand(target24)); |
+ } else { |
+ uint16_t target16_0 = target24 & kImm16Mask; |
+ uint16_t target16_1 = target24 >> 16; |
+ if (CpuFeatures::IsSupported(ARMv7)) { |
+ // Patch with movw/movt. |
+ if (target16_1 == 0) { |
+ CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), |
+ 1, |
+ CodePatcher::DONT_FLUSH); |
+ patcher.masm()->movw(dst, target16_0); |
+ } else { |
+ CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), |
+ 2, |
+ CodePatcher::DONT_FLUSH); |
+ patcher.masm()->movw(dst, target16_0); |
+ patcher.masm()->movt(dst, target16_1); |
+ } |
+ } else { |
+ // Patch with a sequence of mov/orr/orr instructions. |
+ uint8_t target8_0 = target16_0 & kImm8Mask; |
+ uint8_t target8_1 = target16_0 >> 8; |
+ uint8_t target8_2 = target16_1 & kImm8Mask; |
+ if (target8_2 == 0) { |
+ CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), |
+ 2, |
+ CodePatcher::DONT_FLUSH); |
+ patcher.masm()->mov(dst, Operand(target8_0)); |
+ patcher.masm()->orr(dst, dst, Operand(target8_1 << 8)); |
+ } else { |
+ CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), |
+ 3, |
+ CodePatcher::DONT_FLUSH); |
+ patcher.masm()->mov(dst, Operand(target8_0)); |
+ patcher.masm()->orr(dst, dst, Operand(target8_1 << 8)); |
+ patcher.masm()->orr(dst, dst, Operand(target8_2 << 16)); |
+ } |
+ } |
+ } |
return; |
} |
int imm26 = target_pos - (pos + kPcLoadDelta); |
@@ -1232,21 +1294,6 @@ int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) { |
} |
-void Assembler::label_at_put(Label* L, int at_offset) { |
- int target_pos; |
- ASSERT(!L->is_bound()); |
- if (L->is_linked()) { |
- // Point to previous instruction that uses the link. |
- target_pos = L->pos(); |
- } else { |
- // First entry of the link chain points to itself. |
- target_pos = at_offset; |
- } |
- L->link_to(at_offset); |
- instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag)); |
-} |
- |
- |
// Branch instructions. |
void Assembler::b(int branch_offset, Condition cond) { |
ASSERT((branch_offset & 3) == 0); |
@@ -1389,6 +1436,45 @@ void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) { |
} |
+void Assembler::mov_label_offset(Register dst, Label* label) { |
+ if (label->is_bound()) { |
+ mov(dst, Operand(label->pos() + (Code::kHeaderSize - kHeapObjectTag))); |
+ } else { |
+ // Emit the link to the label in the code stream followed by extra nop |
+ // instructions. |
+ // If the label is not linked, then start a new link chain by linking it to |
+ // itself, emitting pc_offset(). |
+ int link = label->is_linked() ? label->pos() : pc_offset(); |
+ label->link_to(pc_offset()); |
+ |
+ // When the label is bound, these instructions will be patched with a |
+ // sequence of movw/movt or mov/orr/orr instructions. They will load the |
+ // destination register with the position of the label from the beginning |
+ // of the code. |
+ // |
+ // The link will be extracted from the first instruction and the destination |
+ // register from the second. |
+ // For ARMv7: |
+ // link |
+ // mov dst, dst |
+ // For ARMv6: |
+ // link |
+ // mov dst, dst |
+ // mov dst, dst |
+ // |
+ // When the label gets bound: target_at extracts the link and target_at_put |
+ // patches the instructions. |
+ ASSERT(is_uint24(link)); |
+ BlockConstPoolScope block_const_pool(this); |
+ emit(link); |
+ nop(dst.code()); |
+ if (!CpuFeatures::IsSupported(ARMv7)) { |
+ nop(dst.code()); |
+ } |
+ } |
+} |
+ |
+ |
void Assembler::movw(Register reg, uint32_t immediate, Condition cond) { |
ASSERT(immediate < 0x10000); |
// May use movw if supported, but on unsupported platforms will try to use |