return reinterpret_cast<Address>(pc_);
} else {
ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_)));
- return Assembler::target_pointer_address_at(pc_);
+ return constant_pool_entry_address();
}
}
Address RelocInfo::constant_pool_entry_address() {
ASSERT(IsInConstantPool());
- if (FLAG_enable_ool_constant_pool) {
- ASSERT(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(pc_)));
- return Assembler::target_constant_pool_address_at(pc_,
- host_->constant_pool());
- } else {
- ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_)));
- return Assembler::target_pointer_address_at(pc_);
- }
+ return Assembler::constant_pool_entry_address(pc_, host_->constant_pool());
}
// A patched return sequence is:
// ldr ip, [pc, #0]
// blx ip
- return ((current_instr & kLdrPCMask) == kLdrPCPattern)
- && ((next_instr & kBlxRegMask) == kBlxRegPattern);
+ return Assembler::IsLdrPcImmediateOffset(current_instr) &&
+ Assembler::IsBlxReg(next_instr);
}
}
-Address Assembler::target_pointer_address_at(Address pc) {
- Instr instr = Memory::int32_at(pc);
- return pc + GetLdrRegisterImmediateOffset(instr) + kPcLoadDelta;
-}
-
-
-Address Assembler::target_constant_pool_address_at(
- Address pc, ConstantPoolArray* constant_pool) {
- ASSERT(constant_pool != NULL);
- ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc)));
- Instr instr = Memory::int32_at(pc);
- return reinterpret_cast<Address>(constant_pool) +
- GetLdrRegisterImmediateOffset(instr);
-}
-
-
-Address Assembler::target_address_at(Address pc,
- ConstantPoolArray* constant_pool) {
- if (IsMovW(Memory::int32_at(pc))) {
- ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)));
- Instruction* instr = Instruction::At(pc);
- Instruction* next_instr = Instruction::At(pc + kInstrSize);
- return reinterpret_cast<Address>(
- (next_instr->ImmedMovwMovtValue() << 16) |
- instr->ImmedMovwMovtValue());
- } else if (FLAG_enable_ool_constant_pool) {
- ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc)));
- return Memory::Address_at(
- target_constant_pool_address_at(pc, constant_pool));
- } else {
- ASSERT(IsLdrPcImmediateOffset(Memory::int32_at(pc)));
- return Memory::Address_at(target_pointer_address_at(pc));
- }
-}
-
-
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.
}
+static bool IsConstantPoolLoad(Address pc) {
+ return !Assembler::IsMovW(Memory::int32_at(pc));
+}
+
+
+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));
+ } else {
+ ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc)));
+ Instr instr = Memory::int32_at(pc);
+ return pc + GetLdrRegisterImmediateOffset(instr) + kPcLoadDelta;
+ }
+}
+
+
+Address Assembler::target_address_at(Address pc,
+ ConstantPoolArray* constant_pool) {
+ if (IsConstantPoolLoad(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.
+ ASSERT(IsMovW(Memory::int32_at(pc)) &&
+ IsMovT(Memory::int32_at(pc + kInstrSize)));
+ Instruction* movw_instr = Instruction::At(pc);
+ Instruction* movt_instr = Instruction::At(pc + kInstrSize);
+ return reinterpret_cast<Address>(
+ (movt_instr->ImmedMovwMovtValue() << 16) |
+ movw_instr->ImmedMovwMovtValue());
+ }
+}
+
+
void Assembler::set_target_address_at(Address pc,
ConstantPoolArray* constant_pool,
Address target,
ICacheFlushMode icache_flush_mode) {
- if (IsMovW(Memory::int32_at(pc))) {
+ if (IsConstantPoolLoad(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
+ // instruction cache after patching a target address in the code as follows:
+ // CPU::FlushICache(pc, sizeof(target));
+ // However, on ARM, no instruction is actually patched in the case
+ // of embedded constants of the form:
+ // 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.
+ ASSERT(IsMovW(Memory::int32_at(pc)));
ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)));
uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
uint32_t immediate = reinterpret_cast<uint32_t>(target);
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
CPU::FlushICache(pc, 2 * kInstrSize);
}
- } else if (FLAG_enable_ool_constant_pool) {
- ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc)));
- Memory::Address_at(
- target_constant_pool_address_at(pc, constant_pool)) = target;
- } else {
- ASSERT(IsLdrPcImmediateOffset(Memory::int32_at(pc)));
- Memory::Address_at(target_pointer_address_at(pc)) = target;
- // Intuitively, we would think it is necessary to always flush the
- // instruction cache after patching a target address in the code as follows:
- // CPU::FlushICache(pc, sizeof(target));
- // However, on ARM, no instruction is actually patched in the case
- // of embedded constants of the form:
- // ldr ip, [pc, #...]
- // since the instruction accessing this address in the constant pool remains
- // unchanged.
}
}
// mov lr, pc
const Instr kMovLrPc = al | MOV | kRegister_pc_Code | kRegister_lr_Code * B12;
// ldr rd, [pc, #offset]
-const Instr kLdrPCMask = 15 * B24 | 7 * B20 | 15 * B16;
-const Instr kLdrPCPattern = 5 * B24 | L | kRegister_pc_Code * B16;
+const Instr kLdrPCImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
+const Instr kLdrPCImmedPattern = 5 * B24 | L | kRegister_pc_Code * B16;
// ldr rd, [pp, #offset]
-const Instr kLdrPpMask = 15 * B24 | 7 * B20 | 15 * B16;
-const Instr kLdrPpPattern = 5 * B24 | L | kRegister_r8_Code * B16;
+const Instr kLdrPpImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
+const Instr kLdrPpImmedPattern = 5 * B24 | L | kRegister_r8_Code * B16;
// vldr dd, [pc, #offset]
const Instr kVldrDPCMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8;
const Instr kVldrDPCPattern = 13 * B24 | L | kRegister_pc_Code * B16 | 11 * B8;
}
+Instr Assembler::GetConsantPoolLoadPattern() {
+ if (FLAG_enable_ool_constant_pool) {
+ return kLdrPpImmedPattern;
+ } else {
+ return kLdrPCImmedPattern;
+ }
+}
+
+
bool Assembler::IsPush(Instr instr) {
return ((instr & ~kRdMask) == kPushRegPattern);
}
bool Assembler::IsLdrPcImmediateOffset(Instr instr) {
// Check the instruction is indeed a
// ldr<cond> <Rd>, [pc +/- offset_12].
- return (instr & kLdrPCMask) == kLdrPCPattern;
+ return (instr & kLdrPCImmedMask) == kLdrPCImmedPattern;
}
bool Assembler::IsLdrPpImmediateOffset(Instr instr) {
// Check the instruction is indeed a
// ldr<cond> <Rd>, [pp +/- offset_12].
- return (instr & kLdrPpMask) == kLdrPpPattern;
+ return (instr & kLdrPpImmedMask) == kLdrPpImmedPattern;
}
}
+bool Assembler::IsBlxReg(Instr instr) {
+ // Check the instruction is indeed a
+ // blxcc <Rm>
+ return (instr & kBlxRegMask) == kBlxRegPattern;
+}
+
+
+bool Assembler::IsBlxIp(Instr instr) {
+ // Check the instruction is indeed a
+ // blx ip
+ return instr == kBlxIp;
+}
+
+
bool Assembler::IsTstImmediate(Instr instr) {
return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
(I | TST | S);
int count_of_32bit_;
};
-
-extern const Instr kMovLrPc;
-extern const Instr kLdrPCMask;
-extern const Instr kLdrPCPattern;
-extern const Instr kLdrPpMask;
-extern const Instr kLdrPpPattern;
-extern const Instr kBlxRegMask;
-extern const Instr kBlxRegPattern;
-extern const Instr kBlxIp;
-
-extern const Instr kMovMvnMask;
-extern const Instr kMovMvnPattern;
-extern const Instr kMovMvnFlip;
-
-extern const Instr kMovLeaveCCMask;
-extern const Instr kMovLeaveCCPattern;
-extern const Instr kMovwMask;
-extern const Instr kMovwPattern;
-extern const Instr kMovwLeaveCCFlip;
-
-extern const Instr kCmpCmnMask;
-extern const Instr kCmpCmnPattern;
-extern const Instr kCmpCmnFlip;
-extern const Instr kAddSubFlip;
-extern const Instr kAndBicFlip;
-
struct VmovIndex {
unsigned char index;
};
// Return the address in the constant pool of the code target address used by
// the branch/call instruction at pc, or the object in a mov.
- INLINE(static Address target_pointer_address_at(Address pc));
-
- // Return the address in the constant pool of the code target address used by
- // the branch/call instruction at pc, or the object in a mov.
- INLINE(static Address target_constant_pool_address_at(
+ INLINE(static Address constant_pool_entry_address(
Address pc, ConstantPoolArray* constant_pool));
// Read/Modify the code target address in the branch/call instruction at pc.
static int GetBranchOffset(Instr instr);
static bool IsLdrRegisterImmediate(Instr instr);
static bool IsVldrDRegisterImmediate(Instr instr);
+ static Instr GetConsantPoolLoadPattern();
static bool IsLdrPpImmediateOffset(Instr instr);
static bool IsVldrDPpImmediateOffset(Instr instr);
static int GetLdrRegisterImmediateOffset(Instr instr);
static bool IsLdrRegFpNegOffset(Instr instr);
static bool IsLdrPcImmediateOffset(Instr instr);
static bool IsVldrDPcImmediateOffset(Instr instr);
+ static bool IsBlxReg(Instr instr);
+ static bool IsBlxIp(Instr instr);
static bool IsTstImmediate(Instr instr);
static bool IsCmpRegister(Instr instr);
static bool IsCmpImmediate(Instr instr);
// -----------------------------------------------------------------------------
-// Specific instructions, constants, and masks.
-// These constants are declared in assembler-arm.cc, as they use named registers
-// and other constants.
-
-
-// add(sp, sp, 4) instruction (aka Pop())
-extern const Instr kPopInstruction;
-
-// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
-// register r is not encoded.
-extern const Instr kPushRegPattern;
-
-// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
-// register r is not encoded.
-extern const Instr kPopRegPattern;
-
-// mov lr, pc
-extern const Instr kMovLrPc;
-// ldr rd, [pc, #offset]
-extern const Instr kLdrPCMask;
-extern const Instr kLdrPCPattern;
-// vldr dd, [pc, #offset]
-extern const Instr kVldrDPCMask;
-extern const Instr kVldrDPCPattern;
-// blxcc rm
-extern const Instr kBlxRegMask;
-
-extern const Instr kBlxRegPattern;
-
-extern const Instr kMovMvnMask;
-extern const Instr kMovMvnPattern;
-extern const Instr kMovMvnFlip;
-extern const Instr kMovLeaveCCMask;
-extern const Instr kMovLeaveCCPattern;
-extern const Instr kMovwMask;
-extern const Instr kMovwPattern;
-extern const Instr kMovwLeaveCCFlip;
-extern const Instr kCmpCmnMask;
-extern const Instr kCmpCmnPattern;
-extern const Instr kCmpCmnFlip;
-extern const Instr kAddSubFlip;
-extern const Instr kAndBicFlip;
-
-// A mask for the Rd register for push, pop, ldr, str instructions.
-extern const Instr kLdrRegFpOffsetPattern;
-
-extern const Instr kStrRegFpOffsetPattern;
-
-extern const Instr kLdrRegFpNegOffsetPattern;
-
-extern const Instr kStrRegFpNegOffsetPattern;
-
-extern const Instr kLdrStrInstrTypeMask;
-extern const Instr kLdrStrInstrArgumentMask;
-extern const Instr kLdrStrOffsetMask;
-
-
-// -----------------------------------------------------------------------------
// Instruction abstraction.
// The class Instruction enables access to individual fields defined in the ARM
Address pc,
BackEdgeState target_state,
Code* replacement_code) {
- static const int kInstrSize = Assembler::kInstrSize;
Address pc_immediate_load_address = GetInterruptImmediateLoadAddress(pc);
- Address branch_address = pc_immediate_load_address - kInstrSize;
+ Address branch_address = pc_immediate_load_address - Assembler::kInstrSize;
CodePatcher patcher(branch_address, 1);
switch (target_state) {
case INTERRUPT:
// Calculate branch offet to the ok-label - this is the difference between
// the branch address and |pc| (which points at <blx ip>) plus one instr.
- int branch_offset = pc + kInstrSize - branch_address;
+ int branch_offset = pc + Assembler::kInstrSize - branch_address;
patcher.masm()->b(branch_offset, pl);
break;
}
Isolate* isolate,
Code* unoptimized_code,
Address pc) {
- static const int kInstrSize = Assembler::kInstrSize;
- ASSERT(Memory::int32_at(pc - kInstrSize) == kBlxIp);
+ ASSERT(Assembler::IsBlxIp(Memory::int32_at(pc - Assembler::kInstrSize)));
Address pc_immediate_load_address = GetInterruptImmediateLoadAddress(pc);
- Address branch_address = pc_immediate_load_address - kInstrSize;
+ Address branch_address = pc_immediate_load_address - Assembler::kInstrSize;
Address interrupt_address = Assembler::target_address_at(
pc_immediate_load_address, unoptimized_code);
ldr(result, MemOperand(ldr_location));
if (emit_debug_code()) {
// Check that the instruction is a ldr reg, [<pc or pp> + offset] .
- if (FLAG_enable_ool_constant_pool) {
- and_(result, result, Operand(kLdrPpPattern));
- cmp(result, Operand(kLdrPpPattern));
- Check(eq, kTheInstructionToPatchShouldBeALoadFromPp);
- } else {
- and_(result, result, Operand(kLdrPCPattern));
- cmp(result, Operand(kLdrPCPattern));
- Check(eq, kTheInstructionToPatchShouldBeALoadFromPc);
- }
+ and_(result, result, Operand(GetConsantPoolLoadPattern()));
+ cmp(result, Operand(GetConsantPoolLoadPattern()));
+ Check(eq, kTheInstructionToPatchShouldBeALoadFromConstantPool);
// Result was clobbered. Restore it.
ldr(result, MemOperand(ldr_location));
}
"The current stack pointer is below csp") \
V(kTheInstructionShouldBeALui, "The instruction should be a lui") \
V(kTheInstructionShouldBeAnOri, "The instruction should be an ori") \
- V(kTheInstructionToPatchShouldBeALoadFromPc, \
- "The instruction to patch should be a load from pc") \
- V(kTheInstructionToPatchShouldBeALoadFromPp, \
- "The instruction to patch should be a load from pp") \
+ V(kTheInstructionToPatchShouldBeALoadFromConstantPool, \
+ "The instruction to patch should be a load from the constant pool") \
V(kTheInstructionToPatchShouldBeAnLdrLiteral, \
"The instruction to patch should be a ldr literal") \
V(kTheInstructionToPatchShouldBeALui, \