ARM: remove the regexp specific literal pool.

It is replaced by a mov_label_offset(Register, Label*) instruction.

BUG=none
TEST=test/cctest/test-assembler-arm.cc
R=bmeurer@chromium.org

Review URL: https://codereview.chromium.org/23515007

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16676 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent e6d10e42
......@@ -39,6 +39,7 @@
#if V8_TARGET_ARCH_ARM
#include "arm/assembler-arm-inl.h"
#include "macro-assembler.h"
#include "serialize.h"
namespace v8 {
......@@ -775,9 +776,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;
......@@ -792,11 +793,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);
......@@ -1229,21 +1291,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);
......@@ -1386,6 +1433,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
......
......@@ -748,10 +748,6 @@ class Assembler : public AssemblerBase {
// Manages the jump elimination optimization if the second parameter is true.
int branch_offset(Label* L, bool jump_elimination_allowed);
// Puts a labels target address at the given position.
// The high 8 bits are set to zero.
void label_at_put(Label* L, int at_offset);
// 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));
......@@ -903,6 +899,10 @@ class Assembler : public AssemblerBase {
mov(dst, Operand(src), s, cond);
}
// Load the position of the label relative to the generated code object
// pointer in a register.
void mov_label_offset(Register dst, Label* label);
// ARMv7 instructions for loading a 32 bit immediate in two instructions.
// This may actually emit a different mov instruction, but on an ARMv7 it
// is guaranteed to only emit one instruction.
......@@ -1561,7 +1561,6 @@ class Assembler : public AssemblerBase {
void RecordRelocInfo(double data);
void RecordRelocInfoConstantPoolEntryHelper(const RelocInfo& rinfo);
friend class RegExpMacroAssemblerARM;
friend class RelocInfo;
friend class CodePatcher;
friend class BlockConstPoolScope;
......
......@@ -220,6 +220,8 @@ enum {
kCoprocessorMask = 15 << 8,
kOpCodeMask = 15 << 21, // In data-processing instructions.
kImm24Mask = (1 << 24) - 1,
kImm16Mask = (1 << 16) - 1,
kImm8Mask = (1 << 8) - 1,
kOff12Mask = (1 << 12) - 1,
kOff8Mask = (1 << 8) - 1
};
......
......@@ -3845,10 +3845,13 @@ bool AreAliased(Register reg1,
#endif
CodePatcher::CodePatcher(byte* address, int instructions)
CodePatcher::CodePatcher(byte* address,
int instructions,
FlushICache flush_cache)
: address_(address),
size_(instructions * Assembler::kInstrSize),
masm_(NULL, address, size_ + Assembler::kGap) {
masm_(NULL, address, size_ + Assembler::kGap),
flush_cache_(flush_cache) {
// Create a new macro assembler pointing to the address of the code to patch.
// The size is adjusted with kGap on order for the assembler to generate size
// bytes of instructions without failing with buffer size constraints.
......@@ -3858,7 +3861,9 @@ CodePatcher::CodePatcher(byte* address, int instructions)
CodePatcher::~CodePatcher() {
// Indicate that code has changed.
CPU::FlushICache(address_, size_);
if (flush_cache_ == FLUSH) {
CPU::FlushICache(address_, size_);
}
// Check that the code was patched as expected.
ASSERT(masm_.pc_ == address_ + size_);
......
......@@ -1429,7 +1429,14 @@ class MacroAssembler: public Assembler {
// an assertion to fail.
class CodePatcher {
public:
CodePatcher(byte* address, int instructions);
enum FlushICache {
FLUSH,
DONT_FLUSH
};
CodePatcher(byte* address,
int instructions,
FlushICache flush_cache = FLUSH);
virtual ~CodePatcher();
// Macro assembler to emit code.
......@@ -1449,6 +1456,7 @@ class CodePatcher {
byte* address_; // The address of the code being patched.
int size_; // Number of bytes of the expected patch size.
MacroAssembler masm_; // Macro assembler used to generate the code.
FlushICache flush_cache_; // Whether to flush the I cache after patching.
};
......
......@@ -134,7 +134,6 @@ RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(
exit_label_() {
ASSERT_EQ(0, registers_to_save % 2);
__ jmp(&entry_label_); // We'll write the entry code later.
EmitBacktrackConstantPool();
__ bind(&start_label_); // And then continue from here.
}
......@@ -938,37 +937,8 @@ void RegExpMacroAssemblerARM::PopRegister(int register_index) {
}
static bool is_valid_memory_offset(int value) {
if (value < 0) value = -value;
return value < (1<<12);
}
void RegExpMacroAssemblerARM::PushBacktrack(Label* label) {
if (label->is_bound()) {
int target = label->pos();
__ mov(r0, Operand(target + Code::kHeaderSize - kHeapObjectTag));
} else {
int constant_offset = GetBacktrackConstantPoolEntry();
masm_->label_at_put(label, constant_offset);
// Reading pc-relative is based on the address 8 bytes ahead of
// the current opcode.
unsigned int offset_of_pc_register_read =
masm_->pc_offset() + Assembler::kPcLoadDelta;
int pc_offset_of_constant =
constant_offset - offset_of_pc_register_read;
ASSERT(pc_offset_of_constant < 0);
if (is_valid_memory_offset(pc_offset_of_constant)) {
Assembler::BlockConstPoolScope block_const_pool(masm_);
__ ldr(r0, MemOperand(pc, pc_offset_of_constant));
} else {
// Not a 12-bit offset, so it needs to be loaded from the constant
// pool.
Assembler::BlockConstPoolScope block_const_pool(masm_);
__ mov(r0, Operand(pc_offset_of_constant + Assembler::kInstrSize));
__ ldr(r0, MemOperand(pc, r0));
}
}
__ mov_label_offset(r0, label);
Push(r0);
CheckStackLimit();
}
......@@ -1279,38 +1249,6 @@ void RegExpMacroAssemblerARM::CheckStackLimit() {
}
void RegExpMacroAssemblerARM::EmitBacktrackConstantPool() {
__ CheckConstPool(false, false);
Assembler::BlockConstPoolScope block_const_pool(masm_);
backtrack_constant_pool_offset_ = masm_->pc_offset();
for (int i = 0; i < kBacktrackConstantPoolSize; i++) {
__ emit(0);
}
backtrack_constant_pool_capacity_ = kBacktrackConstantPoolSize;
}
int RegExpMacroAssemblerARM::GetBacktrackConstantPoolEntry() {
while (backtrack_constant_pool_capacity_ > 0) {
int offset = backtrack_constant_pool_offset_;
backtrack_constant_pool_offset_ += kPointerSize;
backtrack_constant_pool_capacity_--;
if (masm_->pc_offset() - offset < 2 * KB) {
return offset;
}
}
Label new_pool_skip;
__ jmp(&new_pool_skip);
EmitBacktrackConstantPool();
__ bind(&new_pool_skip);
int offset = backtrack_constant_pool_offset_;
backtrack_constant_pool_offset_ += kPointerSize;
backtrack_constant_pool_capacity_--;
return offset;
}
bool RegExpMacroAssemblerARM::CanReadUnaligned() {
return CpuFeatures::IsSupported(UNALIGNED_ACCESSES) && !slow_safe();
}
......
......@@ -160,9 +160,6 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler {
// Check whether we are exceeding the stack limit on the backtrack stack.
void CheckStackLimit();
void EmitBacktrackConstantPool();
int GetBacktrackConstantPoolEntry();
// Generate a call to CheckStackGuardState.
void CallCheckStackGuardState(Register scratch);
......
......@@ -196,7 +196,6 @@ class Label BASE_EMBEDDED {
}
friend class Assembler;
friend class RegexpAssembler;
friend class Displacement;
friend class RegExpMacroAssemblerIrregexp;
};
......
......@@ -1439,4 +1439,75 @@ TEST(17) {
}
TEST(code_relative_offset) {
// Test extracting the offset of a label from the beginning of the code
// in a register.
CcTest::InitializeVM();
Isolate* isolate = Isolate::Current();
HandleScope scope(isolate);
// Initialize a code object that will contain the code.
Handle<Object> code_object(isolate->heap()->undefined_value(), isolate);
Assembler assm(isolate, NULL, 0);
Label start, target_away, target_faraway;
__ stm(db_w, sp, r4.bit() | r5.bit() | lr.bit());
// r3 is used as the address zero, the test will crash when we load it.
__ mov(r3, Operand::Zero());
// r5 will be a pointer to the start of the code.
__ mov(r5, Operand(code_object));
__ mov_label_offset(r4, &start);
__ mov_label_offset(r1, &target_faraway);
__ str(r1, MemOperand(sp, kPointerSize, NegPreIndex));
__ mov_label_offset(r1, &target_away);
// Jump straight to 'target_away' the first time and use the relative
// position the second time. This covers the case when extracting the
// position of a label which is linked.
__ mov(r2, Operand::Zero());
__ bind(&start);
__ cmp(r2, Operand::Zero());
__ b(eq, &target_away);
__ add(pc, r5, r1);
// Emit invalid instructions to push the label between 2^8 and 2^16
// instructions away. The test will crash if they are reached.
for (int i = 0; i < (1 << 10); i++) {
__ ldr(r3, MemOperand(r3));
}
__ bind(&target_away);
// This will be hit twice: r0 = r0 + 5 + 5.
__ add(r0, r0, Operand(5));
__ ldr(r1, MemOperand(sp, kPointerSize, PostIndex), ne);
__ add(pc, r5, r4, LeaveCC, ne);
__ mov(r2, Operand(1));
__ b(&start);
// Emit invalid instructions to push the label between 2^16 and 2^24
// instructions away. The test will crash if they are reached.
for (int i = 0; i < (1 << 21); i++) {
__ ldr(r3, MemOperand(r3));
}
__ bind(&target_faraway);
// r0 = r0 + 5 + 5 + 11
__ add(r0, r0, Operand(11));
__ ldm(ia_w, sp, r4.bit() | r5.bit() | pc.bit());
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(desc,
Code::ComputeFlags(Code::STUB), code_object);
CHECK(code->IsCode());
F1 f = FUNCTION_CAST<F1>(code->entry());
int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 21, 0, 0, 0, 0));
::printf("f() = %d\n", res);
CHECK_EQ(42, res);
}
#undef __
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment