Commit 49cbe537 authored by Benedikt Meurer's avatar Benedikt Meurer

[arm] Assembler support for internal references.

BUG=v8:3872
LOG=n
R=verwaest@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#26475}
parent 39439935
...@@ -228,7 +228,8 @@ const char* DwVfpRegister::AllocationIndexToString(int index) { ...@@ -228,7 +228,8 @@ const char* DwVfpRegister::AllocationIndexToString(int index) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Implementation of RelocInfo // Implementation of RelocInfo
const int RelocInfo::kApplyMask = 0; // static
const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE;
bool RelocInfo::IsCodedSpecially() { bool RelocInfo::IsCodedSpecially() {
...@@ -796,14 +797,20 @@ int Assembler::target_at(int pos) { ...@@ -796,14 +797,20 @@ int Assembler::target_at(int pos) {
// Emitted link to a label, not part of a branch. // Emitted link to a label, not part of a branch.
return instr; return instr;
} }
DCHECK((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 if ((instr & 7 * B25) == 5 * B25) {
int imm26 = ((instr & kImm24Mask) << 8) >> 6; int imm26 = ((instr & kImm24Mask) << 8) >> 6;
if ((Instruction::ConditionField(instr) == kSpecialCondition) && // b, bl, or blx imm24
((instr & B24) != 0)) { if ((Instruction::ConditionField(instr) == kSpecialCondition) &&
// blx uses bit 24 to encode bit 2 of imm26 ((instr & B24) != 0)) {
imm26 += 2; // blx uses bit 24 to encode bit 2 of imm26
imm26 += 2;
}
return pos + kPcLoadDelta + imm26;
} }
return pos + kPcLoadDelta + imm26; // Internal reference to the label.
DCHECK_EQ(15 * B28 | 7 * B25 | 1 * B0, instr & (15 * B28 | 7 * B25 | 1 * B0));
int imm26 = (((instr >> 1) & kImm24Mask) << 8) >> 6;
return pos + imm26;
} }
...@@ -877,19 +884,25 @@ void Assembler::target_at_put(int pos, int target_pos) { ...@@ -877,19 +884,25 @@ void Assembler::target_at_put(int pos, int target_pos) {
} }
return; return;
} }
int imm26 = target_pos - (pos + kPcLoadDelta); if ((instr & 7 * B25) == 5 * B25) {
DCHECK((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 // b, bl, or blx imm24
if (Instruction::ConditionField(instr) == kSpecialCondition) { int imm26 = target_pos - (pos + kPcLoadDelta);
// blx uses bit 24 to encode bit 2 of imm26 if (Instruction::ConditionField(instr) == kSpecialCondition) {
DCHECK((imm26 & 1) == 0); // blx uses bit 24 to encode bit 2 of imm26
instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1)*B24; DCHECK((imm26 & 1) == 0);
} else { instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1) * B24;
DCHECK((imm26 & 3) == 0); } else {
instr &= ~kImm24Mask; DCHECK((imm26 & 3) == 0);
instr &= ~kImm24Mask;
}
int imm24 = imm26 >> 2;
DCHECK(is_int24(imm24));
instr_at_put(pos, instr | (imm24 & kImm24Mask));
return;
} }
int imm24 = imm26 >> 2; // Patch internal reference to label.
DCHECK(is_int24(imm24)); DCHECK_EQ(15 * B28 | 7 * B25 | 1 * B0, instr & (15 * B28 | 7 * B25 | 1 * B0));
instr_at_put(pos, instr | (imm24 & kImm24Mask)); instr_at_put(pos, reinterpret_cast<Instr>(buffer_ + target_pos));
} }
...@@ -3426,9 +3439,16 @@ void Assembler::GrowBuffer() { ...@@ -3426,9 +3439,16 @@ void Assembler::GrowBuffer() {
reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
reloc_info_writer.last_pc() + pc_delta); reloc_info_writer.last_pc() + pc_delta);
// None of our relocation types are pc relative pointing outside the code // Relocate internal references.
// buffer nor pc absolute pointing inside the code buffer, so there is no need for (RelocIterator it(desc); !it.done(); it.next()) {
// to relocate any emitted relocation entries. if (it.rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE) {
// Don't patch unbound internal references (bit 0 set); those are still
// hooked up in the Label chain and will be automatically patched once
// the label is bound.
int32_t* p = reinterpret_cast<int32_t*>(it.rinfo()->pc());
if ((*p & 1 * B0) == 0) *p += pc_delta;
}
}
// Relocate pending relocation entries. // Relocate pending relocation entries.
for (int i = 0; i < num_pending_32_bit_reloc_info_; i++) { for (int i = 0; i < num_pending_32_bit_reloc_info_; i++) {
...@@ -3472,6 +3492,37 @@ void Assembler::dd(uint32_t data) { ...@@ -3472,6 +3492,37 @@ void Assembler::dd(uint32_t data) {
} }
void Assembler::dd(Label* label) {
CheckBuffer();
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
if (label->is_bound()) {
uint32_t data = reinterpret_cast<uint32_t>(buffer_ + label->pos());
DCHECK_EQ(0u, data & 1 * B0);
*reinterpret_cast<uint32_t*>(pc_) = data;
pc_ += sizeof(uint32_t);
} else {
int target_pos;
if (label->is_linked()) {
// Point to previous instruction that uses the link.
target_pos = label->pos();
} else {
// First entry of the link chain points to itself.
target_pos = pc_offset();
}
label->link_to(pc_offset());
// Encode internal reference to unbound label. We set the least significant
// bit to distinguish unbound internal references in GrowBuffer() below.
int imm26 = target_pos - pc_offset();
DCHECK_EQ(0, imm26 & 3);
int imm24 = imm26 >> 2;
DCHECK(is_int24(imm24));
// We use bit pattern 1111111<imm24>1 because that doesn't match any branch
// or load that would also appear on the label chain.
emit(15 * B28 | 7 * B25 | ((imm24 & kImm24Mask) << 1) | 1 * B0);
}
}
void Assembler::emit_code_stub_address(Code* stub) { void Assembler::emit_code_stub_address(Code* stub) {
CheckBuffer(); CheckBuffer();
*reinterpret_cast<uint32_t*>(pc_) = *reinterpret_cast<uint32_t*>(pc_) =
......
...@@ -1427,6 +1427,7 @@ class Assembler : public AssemblerBase { ...@@ -1427,6 +1427,7 @@ class Assembler : public AssemblerBase {
// are not emitted as part of the tables generated. // are not emitted as part of the tables generated.
void db(uint8_t data); void db(uint8_t data);
void dd(uint32_t data); void dd(uint32_t data);
void dd(Label* label);
// Emits the address of the code stub's first instruction. // Emits the address of the code stub's first instruction.
void emit_code_stub_address(Code* stub); void emit_code_stub_address(Code* stub);
......
...@@ -172,6 +172,7 @@ enum { ...@@ -172,6 +172,7 @@ enum {
U = 1 << 23, // Positive (or negative) offset/index. U = 1 << 23, // Positive (or negative) offset/index.
P = 1 << 24, // Offset/pre-indexed addressing (or post-indexed addressing). P = 1 << 24, // Offset/pre-indexed addressing (or post-indexed addressing).
I = 1 << 25, // Immediate shifter operand (or not). I = 1 << 25, // Immediate shifter operand (or not).
B0 = 1 << 0,
B4 = 1 << 4, B4 = 1 << 4,
B5 = 1 << 5, B5 = 1 << 5,
B6 = 1 << 6, B6 = 1 << 6,
......
...@@ -1885,6 +1885,172 @@ TEST(code_relative_offset) { ...@@ -1885,6 +1885,172 @@ TEST(code_relative_offset) {
} }
TEST(jump_tables1) {
// Test jump tables with forward jumps.
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(isolate, nullptr, 0);
const int kNumCases = 512;
int values[kNumCases];
isolate->random_number_generator()->NextBytes(values, sizeof(values));
Label labels[kNumCases];
__ stm(db_w, sp, lr.bit());
Label done;
__ BlockConstPoolFor(kNumCases + 2);
{
PredictableCodeSizeScope predictable(
&assm, (kNumCases + 2) * Assembler::kInstrSize);
__ ldr(pc, MemOperand(pc, r0, LSL, 2));
__ nop();
for (int i = 0; i < kNumCases; ++i) {
__ dd(&labels[i]);
}
}
for (int i = 0; i < kNumCases; ++i) {
__ bind(&labels[i]);
__ mov(r0, Operand(values[i]));
__ b(&done);
}
__ bind(&done);
__ ldm(ia_w, sp, pc.bit());
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F1 f = FUNCTION_CAST<F1>(code->entry());
for (int i = 0; i < kNumCases; ++i) {
int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, i, 0, 0, 0, 0));
::printf("f(%d) = %d\n", i, res);
CHECK_EQ(values[i], res);
}
}
TEST(jump_tables2) {
// Test jump tables with backward jumps.
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(isolate, nullptr, 0);
const int kNumCases = 512;
int values[kNumCases];
isolate->random_number_generator()->NextBytes(values, sizeof(values));
Label labels[kNumCases];
__ stm(db_w, sp, lr.bit());
Label done, dispatch;
__ b(&dispatch);
for (int i = 0; i < kNumCases; ++i) {
__ bind(&labels[i]);
__ mov(r0, Operand(values[i]));
__ b(&done);
}
__ bind(&dispatch);
__ BlockConstPoolFor(kNumCases + 2);
{
PredictableCodeSizeScope predictable(
&assm, (kNumCases + 2) * Assembler::kInstrSize);
__ ldr(pc, MemOperand(pc, r0, LSL, 2));
__ nop();
for (int i = 0; i < kNumCases; ++i) {
__ dd(&labels[i]);
}
}
__ bind(&done);
__ ldm(ia_w, sp, pc.bit());
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F1 f = FUNCTION_CAST<F1>(code->entry());
for (int i = 0; i < kNumCases; ++i) {
int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, i, 0, 0, 0, 0));
::printf("f(%d) = %d\n", i, res);
CHECK_EQ(values[i], res);
}
}
TEST(jump_tables3) {
// Test jump tables with backward jumps and embedded heap objects.
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(isolate, nullptr, 0);
const int kNumCases = 256;
Handle<Object> values[kNumCases];
for (int i = 0; i < kNumCases; ++i) {
double value = isolate->random_number_generator()->NextDouble();
values[i] = isolate->factory()->NewHeapNumber(value, IMMUTABLE, TENURED);
}
Label labels[kNumCases];
__ stm(db_w, sp, lr.bit());
Label done, dispatch;
__ b(&dispatch);
for (int i = 0; i < kNumCases; ++i) {
__ bind(&labels[i]);
__ mov(r0, Operand(values[i]));
__ b(&done);
}
__ bind(&dispatch);
__ BlockConstPoolFor(kNumCases + 2);
{
PredictableCodeSizeScope predictable(
&assm, (kNumCases + 2) * Assembler::kInstrSize);
__ ldr(pc, MemOperand(pc, r0, LSL, 2));
__ nop();
for (int i = 0; i < kNumCases; ++i) {
__ dd(&labels[i]);
}
}
__ bind(&done);
__ ldm(ia_w, sp, pc.bit());
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F1 f = FUNCTION_CAST<F1>(code->entry());
for (int i = 0; i < kNumCases; ++i) {
Handle<Object> result(CALL_GENERATED_CODE(f, i, 0, 0, 0, 0), isolate);
#ifdef OBJECT_PRINT
::printf("f(%d) = ", i);
result->Print(std::cout);
::printf("\n");
#endif
CHECK(values[i].is_identical_to(result));
}
}
TEST(ARMv8_vrintX) { TEST(ARMv8_vrintX) {
// Test the vrintX floating point instructions. // Test the vrintX floating point instructions.
CcTest::InitializeVM(); CcTest::InitializeVM();
......
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