Commit a10ed727 authored by chunyang.dai's avatar chunyang.dai Committed by Commit bot

X87: Assembler support for internal references.

port 5c119485 (r26478).

original commit message:

  Assembler support for internal references.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#26648}
parent a34ed972
...@@ -1202,6 +1202,13 @@ void Assembler::ret(int imm16) { ...@@ -1202,6 +1202,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.
// //
...@@ -1240,7 +1247,10 @@ void Assembler::bind_to(Label* L, int pos) { ...@@ -1240,7 +1247,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 {
...@@ -1938,15 +1948,10 @@ void Assembler::GrowBuffer() { ...@@ -1938,15 +1948,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());
...@@ -1996,7 +2001,21 @@ void Assembler::emit_operand(Register reg, const Operand& adr) { ...@@ -1996,7 +2001,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);
} }
} }
...@@ -2021,6 +2040,13 @@ void Assembler::dd(uint32_t data) { ...@@ -2021,6 +2040,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 @@ ...@@ -37,6 +37,8 @@
#ifndef V8_X87_ASSEMBLER_X87_H_ #ifndef V8_X87_ASSEMBLER_X87_H_
#define V8_X87_ASSEMBLER_X87_H_ #define V8_X87_ASSEMBLER_X87_H_
#include <deque>
#include "src/assembler.h" #include "src/assembler.h"
#include "src/isolate.h" #include "src/isolate.h"
#include "src/serialize.h" #include "src/serialize.h"
...@@ -349,6 +351,11 @@ class Operand BASE_EMBEDDED { ...@@ -349,6 +351,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);
...@@ -422,11 +429,7 @@ class Operand BASE_EMBEDDED { ...@@ -422,11 +429,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_); }
...@@ -788,6 +791,7 @@ class Assembler : public AssemblerBase { ...@@ -788,6 +791,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)
// //
...@@ -943,6 +947,7 @@ class Assembler : public AssemblerBase { ...@@ -943,6 +947,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
...@@ -1013,6 +1018,8 @@ class Assembler : public AssemblerBase { ...@@ -1013,6 +1018,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);
// labels // labels
...@@ -1031,6 +1038,11 @@ class Assembler : public AssemblerBase { ...@@ -1031,6 +1038,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;
......
...@@ -893,6 +893,8 @@ int DisassemblerX87::RegisterFPUInstruction(int escape_opcode, ...@@ -893,6 +893,8 @@ int DisassemblerX87::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";
...@@ -1057,7 +1059,7 @@ int DisassemblerX87::InstructionDecode(v8::internal::Vector<char> out_buffer, ...@@ -1057,7 +1059,7 @@ int DisassemblerX87::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) {
......
...@@ -312,4 +312,98 @@ TEST(AssemblerMultiByteNop) { ...@@ -312,4 +312,98 @@ TEST(AssemblerMultiByteNop) {
} }
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 __
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