Source map in DebugInfo. IVM needs to port its stuff over eventually.
This commit is contained in:
parent
4609339c5a
commit
0cca23cdd7
|
@ -185,7 +185,8 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// --------------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
//UNIMPLEMENTED_SEQ();
|
||||
i = i->next;
|
||||
|
@ -206,8 +207,7 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
table->AddSequence(OPCODE_SOURCE_OFFSET, [](X64Emitter& e, Instr*& i) {
|
||||
// TODO(benvanik): translate source offsets for mapping? We're just passing
|
||||
// down the original offset - it may be nice to have two.
|
||||
//lb.SourceOffset(i->src1.offset);
|
||||
//UNIMPLEMENTED_SEQ();
|
||||
e.MarkSourceOffset(i);
|
||||
i = i->next;
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -70,12 +70,14 @@ int X64Assembler::Assemble(
|
|||
// Lower HIR -> x64.
|
||||
void* machine_code = 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);
|
||||
|
||||
// Stash generated machine code.
|
||||
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());
|
||||
string_buffer_.Reset();
|
||||
}
|
||||
|
@ -94,14 +96,31 @@ XECLEANUP:
|
|||
}
|
||||
|
||||
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;
|
||||
xe_zero_struct(&disasm, sizeof(disasm));
|
||||
disasm.Archi = 64;
|
||||
disasm.Options = BE::Tabulation + BE::MasmSyntax + BE::PrefixedNumeral;
|
||||
disasm.EIP = (BE::UIntPtr)machine_code;
|
||||
BE::UIntPtr eip_end = disasm.EIP + code_size;
|
||||
uint64_t prev_source_offset = 0;
|
||||
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);
|
||||
if (len == BE::UNKNOWN_OPCODE) {
|
||||
break;
|
||||
|
|
|
@ -38,7 +38,9 @@ public:
|
|||
runtime::Function** out_function);
|
||||
|
||||
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:
|
||||
X64Backend* x64_backend_;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <alloy/backend/x64/x64_code_cache.h>
|
||||
#include <alloy/backend/x64/lowering/lowering_table.h>
|
||||
#include <alloy/hir/hir_builder.h>
|
||||
#include <alloy/runtime/debug_info.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
|
@ -51,7 +52,15 @@ int X64Emitter::Initialize() {
|
|||
}
|
||||
|
||||
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.
|
||||
int result = Emit(builder);
|
||||
if (result) {
|
||||
|
@ -62,6 +71,13 @@ int X64Emitter::Emit(
|
|||
out_code_size = getSize();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -211,3 +227,11 @@ void X64Emitter::FindFreeRegs(
|
|||
FindFreeRegs(v2, v2_idx, v2_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_++;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
XEDECLARECLASS2(alloy, hir, HIRBuilder);
|
||||
XEDECLARECLASS2(alloy, hir, Instr);
|
||||
XEDECLARECLASS2(alloy, runtime, DebugInfo);
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
|
@ -45,6 +46,7 @@ public:
|
|||
int Initialize();
|
||||
|
||||
int Emit(hir::HIRBuilder* builder,
|
||||
uint32_t debug_info_flags, runtime::DebugInfo* debug_info,
|
||||
void*& out_code_address, size_t& out_code_size);
|
||||
|
||||
public:
|
||||
|
@ -132,6 +134,8 @@ public:
|
|||
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()); }
|
||||
|
||||
void MarkSourceOffset(hir::Instr* i);
|
||||
|
||||
private:
|
||||
void* Emplace(X64CodeCache* code_cache);
|
||||
int Emit(hir::HIRBuilder* builder);
|
||||
|
@ -150,6 +154,9 @@ private:
|
|||
// Current register values.
|
||||
hir::Value* reg_values[32];
|
||||
} reg_state_;
|
||||
|
||||
size_t source_map_count_;
|
||||
Arena source_map_arena_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -20,11 +20,12 @@ using namespace alloy::runtime;
|
|||
|
||||
|
||||
X64Function::X64Function(FunctionInfo* symbol_info) :
|
||||
machine_code_(0), code_size_(0),
|
||||
machine_code_(NULL), code_size_(0),
|
||||
GuestFunction(symbol_info) {
|
||||
}
|
||||
|
||||
X64Function::~X64Function() {
|
||||
// machine_code_ is freed by code cache.
|
||||
}
|
||||
|
||||
void X64Function::Setup(void* machine_code, size_t code_size) {
|
||||
|
|
|
@ -34,8 +34,8 @@ protected:
|
|||
uint64_t return_address);
|
||||
|
||||
private:
|
||||
void* machine_code_;
|
||||
size_t code_size_;
|
||||
void* machine_code_;
|
||||
size_t code_size_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -35,8 +35,11 @@ int FinalizationPass::Run(HIRBuilder* builder) {
|
|||
|
||||
auto arena = builder->arena();
|
||||
|
||||
uint32_t block_ordinal = 0;
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
block->ordinal = block_ordinal++;
|
||||
|
||||
// Ensure all labels have names.
|
||||
auto label = block->label_head;
|
||||
while (label) {
|
||||
|
@ -52,10 +55,10 @@ int FinalizationPass::Run(HIRBuilder* builder) {
|
|||
// ? remove useless jumps?
|
||||
|
||||
// Renumber all instructions to make liveness tracking easier.
|
||||
uint32_t n = 0;
|
||||
uint32_t instr_ordinal = 0;
|
||||
auto instr = block->instr_head;
|
||||
while (instr) {
|
||||
instr->ordinal = n++;
|
||||
instr->ordinal = instr_ordinal++;
|
||||
instr = instr->next;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@ public:
|
|||
|
||||
Instr* instr_head;
|
||||
Instr* instr_tail;
|
||||
|
||||
uint16_t ordinal;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -17,12 +17,56 @@ DebugInfo::DebugInfo() :
|
|||
source_disasm_(0),
|
||||
raw_hir_disasm_(0),
|
||||
hir_disasm_(0),
|
||||
machine_code_disasm_(0) {
|
||||
machine_code_disasm_(0),
|
||||
source_map_count_(0),
|
||||
source_map_(NULL) {
|
||||
}
|
||||
|
||||
DebugInfo::~DebugInfo() {
|
||||
xe_free(source_map_);
|
||||
xe_free(source_disasm_);
|
||||
xe_free(raw_hir_disasm_);
|
||||
xe_free(hir_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;
|
||||
}
|
||||
|
|
|
@ -25,10 +25,20 @@ enum DebugInfoFlags {
|
|||
DEBUG_INFO_HIR_DISASM = (1 << 3),
|
||||
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,
|
||||
};
|
||||
|
||||
|
||||
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 {
|
||||
public:
|
||||
DebugInfo();
|
||||
|
@ -43,16 +53,20 @@ public:
|
|||
const char* machine_code_disasm() const { return machine_code_disasm_; }
|
||||
void set_machine_code_disasm(char* value) { machine_code_disasm_ = value; }
|
||||
|
||||
// map functions: source addr -> hir index (raw?)
|
||||
// hir index (raw?) to lir index (raw?)
|
||||
// lir index (raw?) to machine code offset
|
||||
// source -> machine code offset
|
||||
void InitializeSourceMap(size_t source_map_count,
|
||||
SourceMapEntry* source_map);
|
||||
SourceMapEntry* LookupSourceOffset(uint64_t offset);
|
||||
SourceMapEntry* LookupHIROffset(uint64_t offset);
|
||||
SourceMapEntry* LookupCodeOffset(uint64_t offset);
|
||||
|
||||
private:
|
||||
char* source_disasm_;
|
||||
char* raw_hir_disasm_;
|
||||
char* hir_disasm_;
|
||||
char* machine_code_disasm_;
|
||||
|
||||
size_t source_map_count_;
|
||||
SourceMapEntry* source_map_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -250,7 +250,7 @@ int Runtime::DemandFunction(
|
|||
if (symbol_status == SymbolInfo::STATUS_NEW) {
|
||||
// Symbol is undefined, so define now.
|
||||
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) {
|
||||
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
||||
return result;
|
||||
|
|
Loading…
Reference in New Issue