}
+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.
//
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<int>(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 {
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<int32_t*>(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<int32_t*>(buffer_ + pos);
+ *p += pc_delta;
}
DCHECK(!buffer_overflow());
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<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);
}
}
}
+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.
#ifndef V8_X87_ASSEMBLER_X87_H_
#define V8_X87_ASSEMBLER_X87_H_
+#include <deque>
+
#include "src/assembler.h"
#include "src/isolate.h"
#include "src/serialize.h"
int32_t disp,
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) {
return Operand(reinterpret_cast<int32_t>(ext.address()),
RelocInfo::EXTERNAL_REFERENCE);
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_); }
void int3();
void nop();
void ret(int imm16);
+ void ud2();
// Label operations & relative jumps (PPUM Appendix D)
//
// 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
void emit_operand(Register reg, const Operand& adr);
+ void emit_label(Label* label);
+
void emit_farith(int b1, int b2, int i);
// labels
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<int> internal_reference_positions_;
+
// code generation
RelocInfoWriter reloc_info_writer;
// 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";
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) {
}
+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 __