From a10ed727bcb610dab80950cc12dc5867c329d8c6 Mon Sep 17 00:00:00 2001 From: "chunyang.dai" Date: Sat, 14 Feb 2015 22:49:58 -0800 Subject: [PATCH] X87: Assembler support for internal references. port 5c119485b485a5c71155501613ae3c12be2863a8 (r26478). original commit message: Assembler support for internal references. BUG= Review URL: https://codereview.chromium.org/920503002 Cr-Commit-Position: refs/heads/master@{#26648} --- src/x87/assembler-x87.cc | 48 +++++++++++++++----- src/x87/assembler-x87.h | 22 ++++++--- src/x87/disasm-x87.cc | 4 +- test/cctest/test-assembler-x87.cc | 94 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 17 deletions(-) diff --git a/src/x87/assembler-x87.cc b/src/x87/assembler-x87.cc index 03e6268..f2db021 100644 --- a/src/x87/assembler-x87.cc +++ b/src/x87/assembler-x87.cc @@ -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. // There are bound, linked, and unused labels. // @@ -1240,7 +1247,10 @@ void Assembler::bind_to(Label* L, int pos) { while (L->is_linked()) { Displacement disp = disp_at(L); int fixup_pos = L->pos(); - if (disp.type() == Displacement::CODE_RELATIVE) { + if (disp.type() == Displacement::CODE_ABSOLUTE) { + long_at_put(fixup_pos, reinterpret_cast(buffer_ + pos)); + internal_reference_positions_.push_back(fixup_pos); + } else if (disp.type() == Displacement::CODE_RELATIVE) { // Relative to Code* heap object pointer. long_at_put(fixup_pos, pos + Code::kHeaderSize - kHeapObjectTag); } else { @@ -1938,15 +1948,10 @@ void Assembler::GrowBuffer() { reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, reloc_info_writer.last_pc() + pc_delta); - // Relocate runtime entries. - for (RelocIterator it(desc); !it.done(); it.next()) { - RelocInfo::Mode rmode = it.rinfo()->rmode(); - if (rmode == RelocInfo::INTERNAL_REFERENCE) { - int32_t* p = reinterpret_cast(it.rinfo()->pc()); - if (*p != 0) { // 0 means uninitialized. - *p += pc_delta; - } - } + // Relocate internal references. + for (auto pos : internal_reference_positions_) { + int32_t* p = reinterpret_cast(buffer_ + pos); + *p += pc_delta; } DCHECK(!buffer_overflow()); @@ -1996,7 +2001,21 @@ void Assembler::emit_operand(Register reg, const Operand& adr) { if (length >= sizeof(int32_t) && !RelocInfo::IsNone(adr.rmode_)) { pc_ -= sizeof(int32_t); // pc_ must be *at* disp32 RecordRelocInfo(adr.rmode_); - pc_ += sizeof(int32_t); + if (adr.rmode_ == RelocInfo::INTERNAL_REFERENCE) { // Fixup for labels + emit_label(*reinterpret_cast(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(buffer_ + label->pos())); + } else { + emit_disp(label, Displacement::CODE_ABSOLUTE); } } @@ -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) { DCHECK(!RelocInfo::IsNone(rmode)); // Don't record external references unless the heap will be serialized. diff --git a/src/x87/assembler-x87.h b/src/x87/assembler-x87.h index 6648391..0535964 100644 --- a/src/x87/assembler-x87.h +++ b/src/x87/assembler-x87.h @@ -37,6 +37,8 @@ #ifndef V8_X87_ASSEMBLER_X87_H_ #define V8_X87_ASSEMBLER_X87_H_ +#include + #include "src/assembler.h" #include "src/isolate.h" #include "src/serialize.h" @@ -349,6 +351,11 @@ class Operand BASE_EMBEDDED { int32_t disp, RelocInfo::Mode rmode = RelocInfo::NONE32); + static Operand JumpTable(Register index, ScaleFactor scale, Label* table) { + return Operand(index, scale, reinterpret_cast(table), + RelocInfo::INTERNAL_REFERENCE); + } + static Operand StaticVariable(const ExternalReference& ext) { return Operand(reinterpret_cast(ext.address()), RelocInfo::EXTERNAL_REFERENCE); @@ -422,11 +429,7 @@ class Operand BASE_EMBEDDED { class Displacement BASE_EMBEDDED { public: - enum Type { - UNCONDITIONAL_JUMP, - CODE_RELATIVE, - OTHER - }; + enum Type { UNCONDITIONAL_JUMP, CODE_RELATIVE, OTHER, CODE_ABSOLUTE }; int data() const { return data_; } Type type() const { return TypeField::decode(data_); } @@ -788,6 +791,7 @@ class Assembler : public AssemblerBase { void int3(); void nop(); void ret(int imm16); + void ud2(); // Label operations & relative jumps (PPUM Appendix D) // @@ -943,6 +947,7 @@ class Assembler : public AssemblerBase { // inline tables, e.g., jump-tables. void db(uint8_t data); void dd(uint32_t data); + void dd(Label* label); // 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 @@ -1013,6 +1018,8 @@ class Assembler : public AssemblerBase { void emit_operand(Register reg, const Operand& adr); + void emit_label(Label* label); + void emit_farith(int b1, int b2, int i); // labels @@ -1031,6 +1038,11 @@ class Assembler : public AssemblerBase { friend class CodePatcher; friend class EnsureSpace; + // Internal reference positions, required for (potential) patching in + // GrowBuffer(); contains only those internal references whose labels + // are already bound. + std::deque internal_reference_positions_; + // code generation RelocInfoWriter reloc_info_writer; diff --git a/src/x87/disasm-x87.cc b/src/x87/disasm-x87.cc index 8c77d77..7e0a075 100644 --- a/src/x87/disasm-x87.cc +++ b/src/x87/disasm-x87.cc @@ -893,6 +893,8 @@ int DisassemblerX87::RegisterFPUInstruction(int escape_opcode, // Returns NULL if the instruction is not handled here. static const char* F0Mnem(byte f0byte) { switch (f0byte) { + case 0x0B: + return "ud2"; case 0x18: return "prefetch"; case 0xA2: return "cpuid"; case 0xBE: return "movsx_b"; @@ -1057,7 +1059,7 @@ int DisassemblerX87::InstructionDecode(v8::internal::Vector out_buffer, data[7] == 0) { AppendToBuffer("nop"); // 8 byte nop. data += 8; - } else if (f0byte == 0xA2 || f0byte == 0x31) { + } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) { AppendToBuffer("%s", f0mnem); data += 2; } else if (f0byte == 0x28) { diff --git a/test/cctest/test-assembler-x87.cc b/test/cctest/test-assembler-x87.cc index 17ec2f2..c07be84 100644 --- a/test/cctest/test-assembler-x87.cc +++ b/test/cctest/test-assembler-x87.cc @@ -312,4 +312,98 @@ TEST(AssemblerMultiByteNop) { } +TEST(AssemblerIa32JumpTables1) { + // Test jump tables with forward jumps. + CcTest::InitializeVM(); + Isolate* isolate = reinterpret_cast(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 = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle()); +#ifdef OBJECT_PRINT + OFStream os(stdout); + code->Print(os); +#endif + F1 f = FUNCTION_CAST(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(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 = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle()); +#ifdef OBJECT_PRINT + OFStream os(stdout); + code->Print(os); +#endif + F1 f = FUNCTION_CAST(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 __ -- 2.7.4