Source map in DebugInfo. IVM needs to port its stuff over eventually.

This commit is contained in:
Ben Vanik 2014-01-25 21:20:28 -08:00
parent 4609339c5a
commit 0cca23cdd7
12 changed files with 135 additions and 19 deletions

View File

@ -185,7 +185,8 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
table->AddSequence(OPCODE_COMMENT, [](X64Emitter& e, Instr*& i) { table->AddSequence(OPCODE_COMMENT, [](X64Emitter& e, Instr*& i) {
//char* str = (char*)i->src1.offset; // TODO(benvanik): pass through.
auto str = (const char*)i->src1.offset;
//lb.Comment(str); //lb.Comment(str);
//UNIMPLEMENTED_SEQ(); //UNIMPLEMENTED_SEQ();
i = i->next; i = i->next;
@ -206,8 +207,7 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
table->AddSequence(OPCODE_SOURCE_OFFSET, [](X64Emitter& e, Instr*& i) { table->AddSequence(OPCODE_SOURCE_OFFSET, [](X64Emitter& e, Instr*& i) {
// TODO(benvanik): translate source offsets for mapping? We're just passing // TODO(benvanik): translate source offsets for mapping? We're just passing
// down the original offset - it may be nice to have two. // down the original offset - it may be nice to have two.
//lb.SourceOffset(i->src1.offset); e.MarkSourceOffset(i);
//UNIMPLEMENTED_SEQ();
i = i->next; i = i->next;
return true; return true;
}); });

View File

@ -70,12 +70,14 @@ int X64Assembler::Assemble(
// Lower HIR -> x64. // Lower HIR -> x64.
void* machine_code = 0; void* machine_code = 0;
size_t code_size = 0; size_t code_size = 0;
result = emitter_->Emit(builder, machine_code, code_size); result = emitter_->Emit(builder,
debug_info_flags, debug_info,
machine_code, code_size);
XEEXPECTZERO(result); XEEXPECTZERO(result);
// Stash generated machine code. // Stash generated machine code.
if (debug_info_flags & DEBUG_INFO_MACHINE_CODE_DISASM) { if (debug_info_flags & DEBUG_INFO_MACHINE_CODE_DISASM) {
DumpMachineCode(machine_code, code_size, &string_buffer_); DumpMachineCode(debug_info, machine_code, code_size, &string_buffer_);
debug_info->set_machine_code_disasm(string_buffer_.ToString()); debug_info->set_machine_code_disasm(string_buffer_.ToString());
string_buffer_.Reset(); string_buffer_.Reset();
} }
@ -94,14 +96,31 @@ XECLEANUP:
} }
void X64Assembler::DumpMachineCode( void X64Assembler::DumpMachineCode(
void* machine_code, size_t code_size, StringBuffer* str) { DebugInfo* debug_info,
void* machine_code, size_t code_size,
StringBuffer* str) {
BE::DISASM disasm; BE::DISASM disasm;
xe_zero_struct(&disasm, sizeof(disasm)); xe_zero_struct(&disasm, sizeof(disasm));
disasm.Archi = 64; disasm.Archi = 64;
disasm.Options = BE::Tabulation + BE::MasmSyntax + BE::PrefixedNumeral; disasm.Options = BE::Tabulation + BE::MasmSyntax + BE::PrefixedNumeral;
disasm.EIP = (BE::UIntPtr)machine_code; disasm.EIP = (BE::UIntPtr)machine_code;
BE::UIntPtr eip_end = disasm.EIP + code_size; BE::UIntPtr eip_end = disasm.EIP + code_size;
uint64_t prev_source_offset = 0;
while (disasm.EIP < eip_end) { while (disasm.EIP < eip_end) {
// Look up source offset.
auto map_entry = debug_info->LookupCodeOffset(
disasm.EIP - (BE::UIntPtr)machine_code);
if (map_entry) {
if (map_entry->source_offset == prev_source_offset) {
str->Append(" ");
} else {
str->Append("%.8X ", map_entry->source_offset);
prev_source_offset = map_entry->source_offset;
}
} else {
str->Append("? ");
}
size_t len = BE::Disasm(&disasm); size_t len = BE::Disasm(&disasm);
if (len == BE::UNKNOWN_OPCODE) { if (len == BE::UNKNOWN_OPCODE) {
break; break;

View File

@ -38,7 +38,9 @@ public:
runtime::Function** out_function); runtime::Function** out_function);
private: private:
void DumpMachineCode(void* machine_code, size_t code_size, StringBuffer* str); void DumpMachineCode(runtime::DebugInfo* debug_info,
void* machine_code, size_t code_size,
StringBuffer* str);
private: private:
X64Backend* x64_backend_; X64Backend* x64_backend_;

View File

@ -13,6 +13,7 @@
#include <alloy/backend/x64/x64_code_cache.h> #include <alloy/backend/x64/x64_code_cache.h>
#include <alloy/backend/x64/lowering/lowering_table.h> #include <alloy/backend/x64/lowering/lowering_table.h>
#include <alloy/hir/hir_builder.h> #include <alloy/hir/hir_builder.h>
#include <alloy/runtime/debug_info.h>
using namespace alloy; using namespace alloy;
using namespace alloy::backend; using namespace alloy::backend;
@ -51,7 +52,15 @@ int X64Emitter::Initialize() {
} }
int X64Emitter::Emit( int X64Emitter::Emit(
HIRBuilder* builder, void*& out_code_address, size_t& out_code_size) { HIRBuilder* builder,
uint32_t debug_info_flags, runtime::DebugInfo* debug_info,
void*& out_code_address, size_t& out_code_size) {
// Reset.
if (debug_info_flags & DEBUG_INFO_SOURCE_MAP) {
source_map_count_ = 0;
source_map_arena_.Reset();
}
// Fill the generator with code. // Fill the generator with code.
int result = Emit(builder); int result = Emit(builder);
if (result) { if (result) {
@ -62,6 +71,13 @@ int X64Emitter::Emit(
out_code_size = getSize(); out_code_size = getSize();
out_code_address = Emplace(code_cache_); out_code_address = Emplace(code_cache_);
// Stash source map.
if (debug_info_flags & DEBUG_INFO_SOURCE_MAP) {
debug_info->InitializeSourceMap(
source_map_count_,
(SourceMapEntry*)source_map_arena_.CloneContents());
}
return 0; return 0;
} }
@ -211,3 +227,11 @@ void X64Emitter::FindFreeRegs(
FindFreeRegs(v2, v2_idx, v2_flags); FindFreeRegs(v2, v2_idx, v2_flags);
FindFreeRegs(v3, v3_idx, v3_flags); FindFreeRegs(v3, v3_idx, v3_flags);
} }
void X64Emitter::MarkSourceOffset(Instr* i) {
auto entry = source_map_arena_.Alloc<SourceMapEntry>();
entry->source_offset = i->src1.offset;
entry->hir_offset = uint32_t(i->block->ordinal << 16) | i->ordinal;
entry->code_offset = getSize();
source_map_count_++;
}

View File

@ -18,6 +18,7 @@
XEDECLARECLASS2(alloy, hir, HIRBuilder); XEDECLARECLASS2(alloy, hir, HIRBuilder);
XEDECLARECLASS2(alloy, hir, Instr); XEDECLARECLASS2(alloy, hir, Instr);
XEDECLARECLASS2(alloy, runtime, DebugInfo);
namespace alloy { namespace alloy {
namespace backend { namespace backend {
@ -45,6 +46,7 @@ public:
int Initialize(); int Initialize();
int Emit(hir::HIRBuilder* builder, int Emit(hir::HIRBuilder* builder,
uint32_t debug_info_flags, runtime::DebugInfo* debug_info,
void*& out_code_address, size_t& out_code_size); void*& out_code_address, size_t& out_code_size);
public: public:
@ -132,6 +134,8 @@ public:
static uint32_t GetRegBit(const Xbyak::Reg64& r) { return 1 << r.getIdx(); } static uint32_t GetRegBit(const Xbyak::Reg64& r) { return 1 << r.getIdx(); }
static uint32_t GetRegBit(const Xbyak::Xmm& r) { return 1 << (16 + r.getIdx()); } static uint32_t GetRegBit(const Xbyak::Xmm& r) { return 1 << (16 + r.getIdx()); }
void MarkSourceOffset(hir::Instr* i);
private: private:
void* Emplace(X64CodeCache* code_cache); void* Emplace(X64CodeCache* code_cache);
int Emit(hir::HIRBuilder* builder); int Emit(hir::HIRBuilder* builder);
@ -150,6 +154,9 @@ private:
// Current register values. // Current register values.
hir::Value* reg_values[32]; hir::Value* reg_values[32];
} reg_state_; } reg_state_;
size_t source_map_count_;
Arena source_map_arena_;
}; };

View File

@ -20,11 +20,12 @@ using namespace alloy::runtime;
X64Function::X64Function(FunctionInfo* symbol_info) : X64Function::X64Function(FunctionInfo* symbol_info) :
machine_code_(0), code_size_(0), machine_code_(NULL), code_size_(0),
GuestFunction(symbol_info) { GuestFunction(symbol_info) {
} }
X64Function::~X64Function() { X64Function::~X64Function() {
// machine_code_ is freed by code cache.
} }
void X64Function::Setup(void* machine_code, size_t code_size) { void X64Function::Setup(void* machine_code, size_t code_size) {

View File

@ -34,8 +34,8 @@ protected:
uint64_t return_address); uint64_t return_address);
private: private:
void* machine_code_; void* machine_code_;
size_t code_size_; size_t code_size_;
}; };

View File

@ -35,8 +35,11 @@ int FinalizationPass::Run(HIRBuilder* builder) {
auto arena = builder->arena(); auto arena = builder->arena();
uint32_t block_ordinal = 0;
auto block = builder->first_block(); auto block = builder->first_block();
while (block) { while (block) {
block->ordinal = block_ordinal++;
// Ensure all labels have names. // Ensure all labels have names.
auto label = block->label_head; auto label = block->label_head;
while (label) { while (label) {
@ -52,10 +55,10 @@ int FinalizationPass::Run(HIRBuilder* builder) {
// ? remove useless jumps? // ? remove useless jumps?
// Renumber all instructions to make liveness tracking easier. // Renumber all instructions to make liveness tracking easier.
uint32_t n = 0; uint32_t instr_ordinal = 0;
auto instr = block->instr_head; auto instr = block->instr_head;
while (instr) { while (instr) {
instr->ordinal = n++; instr->ordinal = instr_ordinal++;
instr = instr->next; instr = instr->next;
} }

View File

@ -33,6 +33,8 @@ public:
Instr* instr_head; Instr* instr_head;
Instr* instr_tail; Instr* instr_tail;
uint16_t ordinal;
}; };

View File

@ -17,12 +17,56 @@ DebugInfo::DebugInfo() :
source_disasm_(0), source_disasm_(0),
raw_hir_disasm_(0), raw_hir_disasm_(0),
hir_disasm_(0), hir_disasm_(0),
machine_code_disasm_(0) { machine_code_disasm_(0),
source_map_count_(0),
source_map_(NULL) {
} }
DebugInfo::~DebugInfo() { DebugInfo::~DebugInfo() {
xe_free(source_map_);
xe_free(source_disasm_); xe_free(source_disasm_);
xe_free(raw_hir_disasm_); xe_free(raw_hir_disasm_);
xe_free(hir_disasm_); xe_free(hir_disasm_);
xe_free(machine_code_disasm_); xe_free(machine_code_disasm_);
} }
void DebugInfo::InitializeSourceMap(size_t source_map_count,
SourceMapEntry* source_map) {
source_map_count_ = source_map_count;
source_map_ = source_map;
// TODO(benvanik): ensure sorted in some way? MC offset?
}
SourceMapEntry* DebugInfo::LookupSourceOffset(uint64_t offset) {
// TODO(benvanik): binary search? We know the list is sorted by code order.
for (size_t n = 0; n < source_map_count_; n++) {
auto entry = &source_map_[n];
if (entry->source_offset == offset) {
return entry;
}
}
return NULL;
}
SourceMapEntry* DebugInfo::LookupHIROffset(uint64_t offset) {
// TODO(benvanik): binary search? We know the list is sorted by code order.
for (size_t n = 0; n < source_map_count_; n++) {
auto entry = &source_map_[n];
if (entry->hir_offset >= offset) {
return entry;
}
}
return NULL;
}
SourceMapEntry* DebugInfo::LookupCodeOffset(uint64_t offset) {
// TODO(benvanik): binary search? We know the list is sorted by code order.
for (size_t n = 0; n < source_map_count_; n++) {
auto entry = &source_map_[n];
if (entry->code_offset >= offset) {
return entry;
}
}
return 0;
}

View File

@ -25,10 +25,20 @@ enum DebugInfoFlags {
DEBUG_INFO_HIR_DISASM = (1 << 3), DEBUG_INFO_HIR_DISASM = (1 << 3),
DEBUG_INFO_MACHINE_CODE_DISASM = (1 << 4), DEBUG_INFO_MACHINE_CODE_DISASM = (1 << 4),
DEBUG_INFO_SOURCE_MAP = (1 << 5),
DEBUG_INFO_DEFAULT = DEBUG_INFO_SOURCE_MAP,
DEBUG_INFO_ALL_DISASM = 0xFFFF, DEBUG_INFO_ALL_DISASM = 0xFFFF,
}; };
typedef struct SourceMapEntry_s {
uint64_t source_offset; // Original source address/offset.
uint64_t hir_offset; // Block ordinal (16b) | Instr ordinal (16b)
uint64_t code_offset; // Offset from emitted code start.
} SourceMapEntry;
class DebugInfo { class DebugInfo {
public: public:
DebugInfo(); DebugInfo();
@ -43,16 +53,20 @@ public:
const char* machine_code_disasm() const { return machine_code_disasm_; } const char* machine_code_disasm() const { return machine_code_disasm_; }
void set_machine_code_disasm(char* value) { machine_code_disasm_ = value; } void set_machine_code_disasm(char* value) { machine_code_disasm_ = value; }
// map functions: source addr -> hir index (raw?) void InitializeSourceMap(size_t source_map_count,
// hir index (raw?) to lir index (raw?) SourceMapEntry* source_map);
// lir index (raw?) to machine code offset SourceMapEntry* LookupSourceOffset(uint64_t offset);
// source -> machine code offset SourceMapEntry* LookupHIROffset(uint64_t offset);
SourceMapEntry* LookupCodeOffset(uint64_t offset);
private: private:
char* source_disasm_; char* source_disasm_;
char* raw_hir_disasm_; char* raw_hir_disasm_;
char* hir_disasm_; char* hir_disasm_;
char* machine_code_disasm_; char* machine_code_disasm_;
size_t source_map_count_;
SourceMapEntry* source_map_;
}; };

View File

@ -250,7 +250,7 @@ int Runtime::DemandFunction(
if (symbol_status == SymbolInfo::STATUS_NEW) { if (symbol_status == SymbolInfo::STATUS_NEW) {
// Symbol is undefined, so define now. // Symbol is undefined, so define now.
Function* function = NULL; Function* function = NULL;
int result = frontend_->DefineFunction(symbol_info, DEBUG_INFO_NONE, &function); int result = frontend_->DefineFunction(symbol_info, DEBUG_INFO_DEFAULT, &function);
if (result) { if (result) {
symbol_info->set_status(SymbolInfo::STATUS_FAILED); symbol_info->set_status(SymbolInfo::STATUS_FAILED);
return result; return result;