diff --git a/src/xenia/base/arena.cc b/src/xenia/base/arena.cc index cca7048be..ef5e65a85 100644 --- a/src/xenia/base/arena.cc +++ b/src/xenia/base/arena.cc @@ -68,7 +68,7 @@ void* Arena::Alloc(size_t size) { void Arena::Rewind(size_t size) { active_chunk_->offset -= size; } -void* Arena::CloneContents() { +size_t Arena::CalculateSize() { size_t total_length = 0; Chunk* chunk = head_chunk_; while (chunk) { @@ -78,9 +78,14 @@ void* Arena::CloneContents() { } chunk = chunk->next; } + return total_length; +} + +void* Arena::CloneContents() { + size_t total_length = CalculateSize(); void* result = malloc(total_length); uint8_t* p = (uint8_t*)result; - chunk = head_chunk_; + Chunk* chunk = head_chunk_; while (chunk) { std::memcpy(p, chunk->buffer, chunk->offset); p += chunk->offset; @@ -92,6 +97,19 @@ void* Arena::CloneContents() { return result; } +void Arena::CloneContents(void* buffer, size_t buffer_length) { + uint8_t* p = (uint8_t*)buffer; + Chunk* chunk = head_chunk_; + while (chunk) { + std::memcpy(p, chunk->buffer, chunk->offset); + p += chunk->offset; + if (chunk == active_chunk_) { + break; + } + chunk = chunk->next; + } +} + Arena::Chunk::Chunk(size_t chunk_size) : next(nullptr), capacity(chunk_size), buffer(0), offset(0) { buffer = reinterpret_cast(malloc(capacity)); diff --git a/src/xenia/base/arena.h b/src/xenia/base/arena.h index 87ee0b856..706db4550 100644 --- a/src/xenia/base/arena.h +++ b/src/xenia/base/arena.h @@ -12,6 +12,7 @@ #include #include +#include namespace xe { @@ -31,6 +32,11 @@ class Arena { void Rewind(size_t size); void* CloneContents(); + template + void CloneContents(std::vector& buffer) { + buffer.resize(CalculateSize() / sizeof(T)); + CloneContents(buffer.data(), buffer.size() * sizeof(T)); + } private: class Chunk { @@ -45,7 +51,9 @@ class Arena { size_t offset; }; - private: + size_t CalculateSize(); + void CloneContents(void* buffer, size_t buffer_length); + size_t chunk_size_; Chunk* head_chunk_; Chunk* active_chunk_; diff --git a/src/xenia/cpu/backend/x64/x64_assembler.cc b/src/xenia/cpu/backend/x64/x64_assembler.cc index c9a7b83b6..4b83dbafc 100644 --- a/src/xenia/cpu/backend/x64/x64_assembler.cc +++ b/src/xenia/cpu/backend/x64/x64_assembler.cc @@ -75,17 +75,21 @@ bool X64Assembler::Assemble(FunctionInfo* symbol_info, HIRBuilder* builder, // Reset when we leave. xe::make_reset_scope(this); + // Create now, and populate as we go. + // We may throw it away if we fail. + auto fn = std::make_unique(symbol_info); + // Lower HIR -> x64. void* machine_code = nullptr; size_t code_size = 0; if (!emitter_->Emit(symbol_info, builder, debug_info_flags, debug_info.get(), - machine_code, code_size)) { + machine_code, code_size, fn->source_map())) { return false; } // Stash generated machine code. if (debug_info_flags & DebugInfoFlags::kDebugInfoDisasmMachineCode) { - DumpMachineCode(debug_info.get(), machine_code, code_size, &string_buffer_); + DumpMachineCode(machine_code, code_size, fn->source_map(), &string_buffer_); debug_info->set_machine_code_disasm(string_buffer_.ToString()); string_buffer_.Reset(); } @@ -98,21 +102,19 @@ bool X64Assembler::Assemble(FunctionInfo* symbol_info, HIRBuilder* builder, } } - X64Function* fn = new X64Function(symbol_info); fn->set_debug_info(std::move(debug_info)); fn->Setup(reinterpret_cast(machine_code), code_size); - *out_function = fn; - + // Pass back ownership. + *out_function = fn.release(); return true; } -void X64Assembler::DumpMachineCode(DebugInfo* debug_info, void* machine_code, - size_t code_size, StringBuffer* str) { - auto source_map_entries = debug_info->source_map_entries(); - auto source_map_count = debug_info->source_map_count(); +void X64Assembler::DumpMachineCode( + void* machine_code, size_t code_size, + const std::vector& source_map, StringBuffer* str) { auto source_map_index = 0; - uint32_t next_code_offset = source_map_entries[0].code_offset; + uint32_t next_code_offset = source_map[0].code_offset; const uint8_t* code_ptr = reinterpret_cast(machine_code); size_t remaining_code_size = code_size; @@ -125,11 +127,11 @@ void X64Assembler::DumpMachineCode(DebugInfo* debug_info, void* machine_code, auto code_offset = uint32_t(code_ptr - reinterpret_cast(machine_code)); if (code_offset >= next_code_offset && - source_map_index < source_map_count) { - auto& source_map_entry = source_map_entries[source_map_index]; + source_map_index < source_map.size()) { + auto& source_map_entry = source_map[source_map_index]; str->AppendFormat("%.8X ", source_map_entry.source_offset); ++source_map_index; - next_code_offset = source_map_entries[source_map_index].code_offset; + next_code_offset = source_map[source_map_index].code_offset; } else { str->Append(" "); } diff --git a/src/xenia/cpu/backend/x64/x64_assembler.h b/src/xenia/cpu/backend/x64/x64_assembler.h index f9cd307eb..82c6f86d7 100644 --- a/src/xenia/cpu/backend/x64/x64_assembler.h +++ b/src/xenia/cpu/backend/x64/x64_assembler.h @@ -11,9 +11,11 @@ #define XENIA_BACKEND_X64_X64_ASSEMBLER_H_ #include +#include #include "xenia/base/string_buffer.h" #include "xenia/cpu/backend/assembler.h" +#include "xenia/cpu/function.h" namespace xe { namespace cpu { @@ -39,8 +41,9 @@ class X64Assembler : public Assembler { Function** out_function) override; private: - void DumpMachineCode(DebugInfo* debug_info, void* machine_code, - size_t code_size, StringBuffer* str); + void DumpMachineCode(void* machine_code, size_t code_size, + const std::vector& source_map, + StringBuffer* str); private: X64Backend* x64_backend_; diff --git a/src/xenia/cpu/backend/x64/x64_emitter.cc b/src/xenia/cpu/backend/x64/x64_emitter.cc index 1086f1491..e9b5e1c58 100644 --- a/src/xenia/cpu/backend/x64/x64_emitter.cc +++ b/src/xenia/cpu/backend/x64/x64_emitter.cc @@ -67,13 +67,7 @@ X64Emitter::X64Emitter(X64Backend* backend, XbyakAllocator* allocator) processor_(backend->processor()), backend_(backend), code_cache_(backend->code_cache()), - allocator_(allocator), - feature_flags_(0), - current_instr_(0), - debug_info_(nullptr), - debug_info_flags_(0), - source_map_count_(0), - stack_size_(0) { + allocator_(allocator) { if (FLAGS_enable_haswell_instructions) { feature_flags_ |= cpu_.has(Xbyak::util::Cpu::tAVX2) ? kX64EmitAVX2 : 0; feature_flags_ |= cpu_.has(Xbyak::util::Cpu::tFMA) ? kX64EmitFMA : 0; @@ -95,16 +89,14 @@ X64Emitter::~X64Emitter() = default; bool X64Emitter::Emit(FunctionInfo* function_info, HIRBuilder* builder, uint32_t debug_info_flags, DebugInfo* debug_info, - void*& out_code_address, size_t& out_code_size) { + void*& out_code_address, size_t& out_code_size, + std::vector& out_source_map) { SCOPE_profile_cpu_f("cpu"); // Reset. debug_info_ = debug_info; debug_info_flags_ = debug_info_flags; - if (debug_info_flags_ & DebugInfoFlags::kDebugInfoSourceMap) { - source_map_count_ = 0; - source_map_arena_.Reset(); - } + source_map_arena_.Reset(); // Fill the generator with code. size_t stack_size = 0; @@ -117,10 +109,7 @@ bool X64Emitter::Emit(FunctionInfo* function_info, HIRBuilder* builder, out_code_address = Emplace(stack_size, function_info); // Stash source map. - if (debug_info_flags_ & DebugInfoFlags::kDebugInfoSourceMap) { - debug_info->InitializeSourceMap( - source_map_count_, (SourceMapEntry*)source_map_arena_.CloneContents()); - } + source_map_arena_.CloneContents(out_source_map); return true; } @@ -266,7 +255,6 @@ void X64Emitter::MarkSourceOffset(const Instr* i) { entry->source_offset = static_cast(i->src1.offset); entry->hir_offset = uint32_t(i->block->ordinal << 16) | i->ordinal; entry->code_offset = static_cast(getSize() + 1); - source_map_count_++; if (FLAGS_debug) { nop(); diff --git a/src/xenia/cpu/backend/x64/x64_emitter.h b/src/xenia/cpu/backend/x64/x64_emitter.h index 4614bd021..72bd62877 100644 --- a/src/xenia/cpu/backend/x64/x64_emitter.h +++ b/src/xenia/cpu/backend/x64/x64_emitter.h @@ -10,7 +10,10 @@ #ifndef XENIA_BACKEND_X64_X64_EMITTER_H_ #define XENIA_BACKEND_X64_X64_EMITTER_H_ +#include + #include "xenia/base/arena.h" +#include "xenia/cpu/function.h" #include "xenia/cpu/hir/hir_builder.h" #include "xenia/cpu/hir/instr.h" #include "xenia/cpu/hir/value.h" @@ -117,7 +120,8 @@ class X64Emitter : public Xbyak::CodeGenerator { bool Emit(FunctionInfo* function_info, hir::HIRBuilder* builder, uint32_t debug_info_flags, DebugInfo* debug_info, - void*& out_code_address, size_t& out_code_size); + void*& out_code_address, size_t& out_code_size, + std::vector& out_source_map); static uint32_t PlaceData(Memory* memory); @@ -201,23 +205,22 @@ class X64Emitter : public Xbyak::CodeGenerator { void EmitTraceUserCallReturn(); protected: - Processor* processor_; - X64Backend* backend_; - X64CodeCache* code_cache_; - XbyakAllocator* allocator_; + Processor* processor_ = nullptr; + X64Backend* backend_ = nullptr; + X64CodeCache* code_cache_ = nullptr; + XbyakAllocator* allocator_ = nullptr; Xbyak::util::Cpu cpu_; - uint32_t feature_flags_; + uint32_t feature_flags_ = 0; Xbyak::Label* epilog_label_ = nullptr; - hir::Instr* current_instr_; + hir::Instr* current_instr_ = nullptr; - DebugInfo* debug_info_; - uint32_t debug_info_flags_; - size_t source_map_count_; + DebugInfo* debug_info_ = nullptr; + uint32_t debug_info_flags_ = 0; Arena source_map_arena_; - size_t stack_size_; + size_t stack_size_ = 0; static const uint32_t gpr_reg_map_[GPR_COUNT]; static const uint32_t xmm_reg_map_[XMM_COUNT]; diff --git a/src/xenia/cpu/debug_info.cc b/src/xenia/cpu/debug_info.cc index 867f1edc8..d3c71f87a 100644 --- a/src/xenia/cpu/debug_info.cc +++ b/src/xenia/cpu/debug_info.cc @@ -18,59 +18,15 @@ DebugInfo::DebugInfo() : source_disasm_(nullptr), raw_hir_disasm_(nullptr), hir_disasm_(nullptr), - machine_code_disasm_(nullptr), - source_map_count_(0), - source_map_entries_(nullptr) {} + machine_code_disasm_(nullptr) {} DebugInfo::~DebugInfo() { - free(source_map_entries_); free(source_disasm_); free(raw_hir_disasm_); free(hir_disasm_); free(machine_code_disasm_); } -void DebugInfo::InitializeSourceMap(size_t source_map_count, - SourceMapEntry* source_map) { - source_map_count_ = source_map_count; - source_map_entries_ = source_map; - - // TODO(benvanik): ensure sorted in some way? MC offset? -} - -SourceMapEntry* DebugInfo::LookupSourceOffset(uint32_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_entries_[n]; - if (entry->source_offset == offset) { - return entry; - } - } - return nullptr; -} - -SourceMapEntry* DebugInfo::LookupHIROffset(uint32_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_entries_[n]; - if (entry->hir_offset >= offset) { - return entry; - } - } - return nullptr; -} - -SourceMapEntry* DebugInfo::LookupCodeOffset(uint32_t offset) { - // TODO(benvanik): binary search? We know the list is sorted by code order. - for (int64_t n = source_map_count_ - 1; n >= 0; n--) { - auto entry = &source_map_entries_[n]; - if (entry->code_offset <= offset) { - return entry; - } - } - return source_map_count_ ? &source_map_entries_[0] : nullptr; -} - void DebugInfo::Dump() { if (source_disasm_) { printf("PPC:\n%s\n", source_disasm_); diff --git a/src/xenia/cpu/debug_info.h b/src/xenia/cpu/debug_info.h index e3d80601a..2d13f694e 100644 --- a/src/xenia/cpu/debug_info.h +++ b/src/xenia/cpu/debug_info.h @@ -26,7 +26,6 @@ enum DebugInfoFlags : uint32_t { kDebugInfoDisasmMachineCode = (1 << 4), kDebugInfoAllDisasm = kDebugInfoDisasmSource | kDebugInfoDisasmRawHir | kDebugInfoDisasmHir | kDebugInfoDisasmMachineCode, - kDebugInfoSourceMap = (1 << 5), kDebugInfoTraceFunctions = (1 << 6), kDebugInfoTraceFunctionCoverage = (1 << 7) | kDebugInfoTraceFunctions, kDebugInfoTraceFunctionReferences = (1 << 8) | kDebugInfoTraceFunctions, @@ -38,12 +37,6 @@ enum DebugInfoFlags : uint32_t { kDebugInfoAll = 0xFFFFFFFF, }; -typedef struct SourceMapEntry_s { - uint32_t source_offset; // Original source address/offset. - uint32_t hir_offset; // Block ordinal (16b) | Instr ordinal (16b) - uint32_t code_offset; // Offset from emitted code start. -} SourceMapEntry; - class DebugInfo { public: DebugInfo(); @@ -71,13 +64,6 @@ class DebugInfo { const char* machine_code_disasm() const { return machine_code_disasm_; } void set_machine_code_disasm(char* value) { machine_code_disasm_ = value; } - size_t source_map_count() const { return source_map_count_; } - SourceMapEntry* source_map_entries() const { return source_map_entries_; } - void InitializeSourceMap(size_t source_map_count, SourceMapEntry* source_map); - SourceMapEntry* LookupSourceOffset(uint32_t offset); - SourceMapEntry* LookupHIROffset(uint32_t offset); - SourceMapEntry* LookupCodeOffset(uint32_t offset); - void Dump(); private: @@ -90,9 +76,6 @@ class DebugInfo { char* raw_hir_disasm_; char* hir_disasm_; char* machine_code_disasm_; - - size_t source_map_count_; - SourceMapEntry* source_map_entries_; }; } // namespace cpu diff --git a/src/xenia/cpu/function.cc b/src/xenia/cpu/function.cc index 83d3fbd58..e9f915b61 100644 --- a/src/xenia/cpu/function.cc +++ b/src/xenia/cpu/function.cc @@ -23,6 +23,39 @@ Function::Function(FunctionInfo* symbol_info) Function::~Function() = default; +const SourceMapEntry* Function::LookupSourceOffset(uint32_t offset) const { + // TODO(benvanik): binary search? We know the list is sorted by code order. + for (size_t i = 0; i < source_map_.size(); ++i) { + const auto& entry = source_map_[i]; + if (entry.source_offset == offset) { + return &entry; + } + } + return nullptr; +} + +const SourceMapEntry* Function::LookupHIROffset(uint32_t offset) const { + // TODO(benvanik): binary search? We know the list is sorted by code order. + for (size_t i = 0; i < source_map_.size(); ++i) { + const auto& entry = source_map_[i]; + if (entry.hir_offset >= offset) { + return &entry; + } + } + return nullptr; +} + +const SourceMapEntry* Function::LookupCodeOffset(uint32_t offset) const { + // TODO(benvanik): binary search? We know the list is sorted by code order. + for (int64_t i = source_map_.size() - 1; i >= 0; --i) { + const auto& entry = source_map_[i]; + if (entry.code_offset <= offset) { + return &entry; + } + } + return source_map_.empty() ? nullptr : &source_map_[0]; +} + bool Function::AddBreakpoint(Breakpoint* breakpoint) { std::lock_guard guard(lock_); bool found = false; diff --git a/src/xenia/cpu/function.h b/src/xenia/cpu/function.h index f93c23a03..74e758aaf 100644 --- a/src/xenia/cpu/function.h +++ b/src/xenia/cpu/function.h @@ -24,6 +24,12 @@ namespace cpu { class FunctionInfo; +struct SourceMapEntry { + uint32_t source_offset; // Original source address/offset. + uint32_t hir_offset; // Block ordinal (16b) | Instr ordinal (16b) + uint32_t code_offset; // Offset from emitted code start. +}; + class Function { public: Function(FunctionInfo* symbol_info); @@ -32,13 +38,18 @@ class Function { uint32_t address() const { return address_; } FunctionInfo* symbol_info() const { return symbol_info_; } + virtual uint8_t* machine_code() const = 0; + virtual size_t machine_code_length() const = 0; + DebugInfo* debug_info() const { return debug_info_.get(); } void set_debug_info(std::unique_ptr debug_info) { debug_info_ = std::move(debug_info); } + std::vector& source_map() { return source_map_; } - virtual uint8_t* machine_code() const = 0; - virtual size_t machine_code_length() const = 0; + const SourceMapEntry* LookupSourceOffset(uint32_t offset) const; + const SourceMapEntry* LookupHIROffset(uint32_t offset) const; + const SourceMapEntry* LookupCodeOffset(uint32_t offset) const; bool AddBreakpoint(debug::Breakpoint* breakpoint); bool RemoveBreakpoint(debug::Breakpoint* breakpoint); @@ -55,6 +66,7 @@ class Function { uint32_t address_; FunctionInfo* symbol_info_; std::unique_ptr debug_info_; + std::vector source_map_; // TODO(benvanik): move elsewhere? DebugData? xe::mutex lock_; diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index d914c2c29..3435660e2 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -62,7 +62,7 @@ Processor::~Processor() { bool Processor::Setup() { // TODO(benvanik): query mode from debugger? - debug_info_flags_ = DebugInfoFlags::kDebugInfoSourceMap; + debug_info_flags_ = 0; auto frontend = std::make_unique(this); // TODO(benvanik): set options/etc. diff --git a/src/xenia/cpu/stack_walker_win.cc b/src/xenia/cpu/stack_walker_win.cc index 9681e448d..06f2096b6 100644 --- a/src/xenia/cpu/stack_walker_win.cc +++ b/src/xenia/cpu/stack_walker_win.cc @@ -216,8 +216,7 @@ class Win32StackWalker : public StackWalker { uint32_t(frame.host_pc) - uint32_t(uint64_t(function_info->function()->machine_code())); auto entry = - function_info->function()->debug_info()->LookupCodeOffset( - host_displacement); + function_info->function()->LookupCodeOffset(host_displacement); frame.guest_pc = entry->source_offset; } else { frame.guest_symbol.function_info = nullptr; diff --git a/xenia-build b/xenia-build index c13c66114..e7457f48a 100755 --- a/xenia-build +++ b/xenia-build @@ -868,7 +868,9 @@ class LintCommand(Command): '--diff', ], throw_on_error=False, stdout_path=difftemp) with open(difftemp) as f: - not_modified = 'no modified files' in f.read() + contents = f.read() + not_modified = 'no modified files' in contents + not_modified = not_modified or 'did not modify' in contents f.close() if os.path.exists(difftemp): os.remove(difftemp) if not not_modified: