| 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
|
|
|