[ia32] Assembler support for internal references.
BUG=v8:3872 LOG=n R=dcarney@chromium.org Review URL: https://codereview.chromium.org/900223006 Cr-Commit-Position: refs/heads/master@{#26478}
This commit is contained in:
parent
a3ac322a2a
commit
5c119485b4
@ -1340,6 +1340,13 @@ void Assembler::ret(int imm16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Assembler::ud2() {
|
||||||
|
EnsureSpace ensure_space(this);
|
||||||
|
EMIT(0x0F);
|
||||||
|
EMIT(0x0B);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Labels refer to positions in the (to be) generated code.
|
// Labels refer to positions in the (to be) generated code.
|
||||||
// There are bound, linked, and unused labels.
|
// There are bound, linked, and unused labels.
|
||||||
//
|
//
|
||||||
@ -1378,7 +1385,10 @@ void Assembler::bind_to(Label* L, int pos) {
|
|||||||
while (L->is_linked()) {
|
while (L->is_linked()) {
|
||||||
Displacement disp = disp_at(L);
|
Displacement disp = disp_at(L);
|
||||||
int fixup_pos = L->pos();
|
int fixup_pos = L->pos();
|
||||||
if (disp.type() == Displacement::CODE_RELATIVE) {
|
if (disp.type() == Displacement::CODE_ABSOLUTE) {
|
||||||
|
long_at_put(fixup_pos, reinterpret_cast<int>(buffer_ + pos));
|
||||||
|
internal_reference_positions_.push_back(fixup_pos);
|
||||||
|
} else if (disp.type() == Displacement::CODE_RELATIVE) {
|
||||||
// Relative to Code* heap object pointer.
|
// Relative to Code* heap object pointer.
|
||||||
long_at_put(fixup_pos, pos + Code::kHeaderSize - kHeapObjectTag);
|
long_at_put(fixup_pos, pos + Code::kHeaderSize - kHeapObjectTag);
|
||||||
} else {
|
} else {
|
||||||
@ -2690,15 +2700,10 @@ 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);
|
||||||
|
|
||||||
// Relocate runtime entries.
|
// Relocate internal references.
|
||||||
for (RelocIterator it(desc); !it.done(); it.next()) {
|
for (auto pos : internal_reference_positions_) {
|
||||||
RelocInfo::Mode rmode = it.rinfo()->rmode();
|
int32_t* p = reinterpret_cast<int32_t*>(buffer_ + pos);
|
||||||
if (rmode == RelocInfo::INTERNAL_REFERENCE) {
|
*p += pc_delta;
|
||||||
int32_t* p = reinterpret_cast<int32_t*>(it.rinfo()->pc());
|
|
||||||
if (*p != 0) { // 0 means uninitialized.
|
|
||||||
*p += pc_delta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DCHECK(!buffer_overflow());
|
DCHECK(!buffer_overflow());
|
||||||
@ -2748,7 +2753,21 @@ void Assembler::emit_operand(Register reg, const Operand& adr) {
|
|||||||
if (length >= sizeof(int32_t) && !RelocInfo::IsNone(adr.rmode_)) {
|
if (length >= sizeof(int32_t) && !RelocInfo::IsNone(adr.rmode_)) {
|
||||||
pc_ -= sizeof(int32_t); // pc_ must be *at* disp32
|
pc_ -= sizeof(int32_t); // pc_ must be *at* disp32
|
||||||
RecordRelocInfo(adr.rmode_);
|
RecordRelocInfo(adr.rmode_);
|
||||||
pc_ += sizeof(int32_t);
|
if (adr.rmode_ == RelocInfo::INTERNAL_REFERENCE) { // Fixup for labels
|
||||||
|
emit_label(*reinterpret_cast<Label**>(pc_));
|
||||||
|
} else {
|
||||||
|
pc_ += sizeof(int32_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Assembler::emit_label(Label* label) {
|
||||||
|
if (label->is_bound()) {
|
||||||
|
internal_reference_positions_.push_back(pc_offset());
|
||||||
|
emit(reinterpret_cast<uint32_t>(buffer_ + label->pos()));
|
||||||
|
} else {
|
||||||
|
emit_disp(label, Displacement::CODE_ABSOLUTE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2773,6 +2792,13 @@ void Assembler::dd(uint32_t data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Assembler::dd(Label* label) {
|
||||||
|
EnsureSpace ensure_space(this);
|
||||||
|
RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
|
||||||
|
emit_label(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
|
void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
|
||||||
DCHECK(!RelocInfo::IsNone(rmode));
|
DCHECK(!RelocInfo::IsNone(rmode));
|
||||||
// Don't record external references unless the heap will be serialized.
|
// Don't record external references unless the heap will be serialized.
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
#ifndef V8_IA32_ASSEMBLER_IA32_H_
|
#ifndef V8_IA32_ASSEMBLER_IA32_H_
|
||||||
#define V8_IA32_ASSEMBLER_IA32_H_
|
#define V8_IA32_ASSEMBLER_IA32_H_
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
#include "src/isolate.h"
|
#include "src/isolate.h"
|
||||||
#include "src/serialize.h"
|
#include "src/serialize.h"
|
||||||
|
|
||||||
@ -357,6 +359,11 @@ class Operand BASE_EMBEDDED {
|
|||||||
int32_t disp,
|
int32_t disp,
|
||||||
RelocInfo::Mode rmode = RelocInfo::NONE32);
|
RelocInfo::Mode rmode = RelocInfo::NONE32);
|
||||||
|
|
||||||
|
static Operand JumpTable(Register index, ScaleFactor scale, Label* table) {
|
||||||
|
return Operand(index, scale, reinterpret_cast<int32_t>(table),
|
||||||
|
RelocInfo::INTERNAL_REFERENCE);
|
||||||
|
}
|
||||||
|
|
||||||
static Operand StaticVariable(const ExternalReference& ext) {
|
static Operand StaticVariable(const ExternalReference& ext) {
|
||||||
return Operand(reinterpret_cast<int32_t>(ext.address()),
|
return Operand(reinterpret_cast<int32_t>(ext.address()),
|
||||||
RelocInfo::EXTERNAL_REFERENCE);
|
RelocInfo::EXTERNAL_REFERENCE);
|
||||||
@ -430,11 +437,7 @@ class Operand BASE_EMBEDDED {
|
|||||||
|
|
||||||
class Displacement BASE_EMBEDDED {
|
class Displacement BASE_EMBEDDED {
|
||||||
public:
|
public:
|
||||||
enum Type {
|
enum Type { UNCONDITIONAL_JUMP, CODE_RELATIVE, OTHER, CODE_ABSOLUTE };
|
||||||
UNCONDITIONAL_JUMP,
|
|
||||||
CODE_RELATIVE,
|
|
||||||
OTHER
|
|
||||||
};
|
|
||||||
|
|
||||||
int data() const { return data_; }
|
int data() const { return data_; }
|
||||||
Type type() const { return TypeField::decode(data_); }
|
Type type() const { return TypeField::decode(data_); }
|
||||||
@ -804,6 +807,7 @@ class Assembler : public AssemblerBase {
|
|||||||
void int3();
|
void int3();
|
||||||
void nop();
|
void nop();
|
||||||
void ret(int imm16);
|
void ret(int imm16);
|
||||||
|
void ud2();
|
||||||
|
|
||||||
// Label operations & relative jumps (PPUM Appendix D)
|
// Label operations & relative jumps (PPUM Appendix D)
|
||||||
//
|
//
|
||||||
@ -1268,6 +1272,7 @@ class Assembler : public AssemblerBase {
|
|||||||
// inline tables, e.g., jump-tables.
|
// inline tables, e.g., jump-tables.
|
||||||
void db(uint8_t data);
|
void db(uint8_t data);
|
||||||
void dd(uint32_t data);
|
void dd(uint32_t data);
|
||||||
|
void dd(Label* label);
|
||||||
|
|
||||||
// Check if there is less than kGap bytes available in the buffer.
|
// Check if there is less than kGap bytes available in the buffer.
|
||||||
// If this is the case, we need to grow the buffer before emitting
|
// If this is the case, we need to grow the buffer before emitting
|
||||||
@ -1343,6 +1348,8 @@ class Assembler : public AssemblerBase {
|
|||||||
|
|
||||||
void emit_operand(Register reg, const Operand& adr);
|
void emit_operand(Register reg, const Operand& adr);
|
||||||
|
|
||||||
|
void emit_label(Label* label);
|
||||||
|
|
||||||
void emit_farith(int b1, int b2, int i);
|
void emit_farith(int b1, int b2, int i);
|
||||||
|
|
||||||
// Emit vex prefix
|
// Emit vex prefix
|
||||||
@ -1369,6 +1376,11 @@ class Assembler : public AssemblerBase {
|
|||||||
friend class CodePatcher;
|
friend class CodePatcher;
|
||||||
friend class EnsureSpace;
|
friend class EnsureSpace;
|
||||||
|
|
||||||
|
// Internal reference positions, required for (potential) patching in
|
||||||
|
// GrowBuffer(); contains only those internal references whose labels
|
||||||
|
// are already bound.
|
||||||
|
std::deque<int> internal_reference_positions_;
|
||||||
|
|
||||||
// code generation
|
// code generation
|
||||||
RelocInfoWriter reloc_info_writer;
|
RelocInfoWriter reloc_info_writer;
|
||||||
|
|
||||||
|
@ -1035,6 +1035,8 @@ int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
|
|||||||
// Returns NULL if the instruction is not handled here.
|
// Returns NULL if the instruction is not handled here.
|
||||||
static const char* F0Mnem(byte f0byte) {
|
static const char* F0Mnem(byte f0byte) {
|
||||||
switch (f0byte) {
|
switch (f0byte) {
|
||||||
|
case 0x0B:
|
||||||
|
return "ud2";
|
||||||
case 0x18: return "prefetch";
|
case 0x18: return "prefetch";
|
||||||
case 0xA2: return "cpuid";
|
case 0xA2: return "cpuid";
|
||||||
case 0xBE: return "movsx_b";
|
case 0xBE: return "movsx_b";
|
||||||
@ -1215,7 +1217,7 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
|
|||||||
data[7] == 0) {
|
data[7] == 0) {
|
||||||
AppendToBuffer("nop"); // 8 byte nop.
|
AppendToBuffer("nop"); // 8 byte nop.
|
||||||
data += 8;
|
data += 8;
|
||||||
} else if (f0byte == 0xA2 || f0byte == 0x31) {
|
} else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
|
||||||
AppendToBuffer("%s", f0mnem);
|
AppendToBuffer("%s", f0mnem);
|
||||||
data += 2;
|
data += 2;
|
||||||
} else if (f0byte == 0x28) {
|
} else if (f0byte == 0x28) {
|
||||||
|
@ -1043,4 +1043,100 @@ TEST(AssemblerX64FMA_ss) {
|
|||||||
F10 f = FUNCTION_CAST<F10>(code->entry());
|
F10 f = FUNCTION_CAST<F10>(code->entry());
|
||||||
CHECK_EQ(0, f(9.26621069e-05f, -2.4607749f, -1.09587872f));
|
CHECK_EQ(0, f(9.26621069e-05f, -2.4607749f, -1.09587872f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(AssemblerIa32JumpTables1) {
|
||||||
|
// Test jump tables with forward jumps.
|
||||||
|
CcTest::InitializeVM();
|
||||||
|
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::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];
|
||||||
|
|
||||||
|
Label done, table;
|
||||||
|
__ mov(eax, Operand(esp, 4));
|
||||||
|
__ jmp(Operand::JumpTable(eax, times_4, &table));
|
||||||
|
__ ud2();
|
||||||
|
__ bind(&table);
|
||||||
|
for (int i = 0; i < kNumCases; ++i) {
|
||||||
|
__ dd(&labels[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < kNumCases; ++i) {
|
||||||
|
__ bind(&labels[i]);
|
||||||
|
__ mov(eax, Immediate(values[i]));
|
||||||
|
__ jmp(&done);
|
||||||
|
}
|
||||||
|
|
||||||
|
__ bind(&done);
|
||||||
|
__ ret(0);
|
||||||
|
|
||||||
|
CodeDesc desc;
|
||||||
|
assm.GetCode(&desc);
|
||||||
|
Handle<Code> code = isolate->factory()->NewCode(
|
||||||
|
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||||
|
#ifdef OBJECT_PRINT
|
||||||
|
OFStream os(stdout);
|
||||||
|
code->Print(os);
|
||||||
|
#endif
|
||||||
|
F1 f = FUNCTION_CAST<F1>(code->entry());
|
||||||
|
for (int i = 0; i < kNumCases; ++i) {
|
||||||
|
int res = f(i);
|
||||||
|
::printf("f(%d) = %d\n", i, res);
|
||||||
|
CHECK_EQ(values[i], res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(AssemblerIa32JumpTables2) {
|
||||||
|
// Test jump tables with backward jumps.
|
||||||
|
CcTest::InitializeVM();
|
||||||
|
Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::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];
|
||||||
|
|
||||||
|
Label done, table;
|
||||||
|
__ mov(eax, Operand(esp, 4));
|
||||||
|
__ jmp(Operand::JumpTable(eax, times_4, &table));
|
||||||
|
__ ud2();
|
||||||
|
|
||||||
|
for (int i = 0; i < kNumCases; ++i) {
|
||||||
|
__ bind(&labels[i]);
|
||||||
|
__ mov(eax, Immediate(values[i]));
|
||||||
|
__ jmp(&done);
|
||||||
|
}
|
||||||
|
|
||||||
|
__ bind(&table);
|
||||||
|
for (int i = 0; i < kNumCases; ++i) {
|
||||||
|
__ dd(&labels[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
__ bind(&done);
|
||||||
|
__ ret(0);
|
||||||
|
|
||||||
|
CodeDesc desc;
|
||||||
|
assm.GetCode(&desc);
|
||||||
|
Handle<Code> code = isolate->factory()->NewCode(
|
||||||
|
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||||
|
#ifdef OBJECT_PRINT
|
||||||
|
OFStream os(stdout);
|
||||||
|
code->Print(os);
|
||||||
|
#endif
|
||||||
|
F1 f = FUNCTION_CAST<F1>(code->entry());
|
||||||
|
for (int i = 0; i < kNumCases; ++i) {
|
||||||
|
int res = f(i);
|
||||||
|
::printf("f(%d) = %d\n", i, res);
|
||||||
|
CHECK_EQ(values[i], res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#undef __
|
#undef __
|
||||||
|
Loading…
Reference in New Issue
Block a user