diff --git a/include/js_protocol.pdl b/include/js_protocol.pdl index 7fd51df5ac..8d8211bf98 100644 --- a/include/js_protocol.pdl +++ b/include/js_protocol.pdl @@ -261,8 +261,8 @@ domain Debugger optional string streamId # The total number of lines in the disassembly text. integer totalNumberOfLines - # The offsets of all function bodies plus one additional entry pointing - # one by past the end of the last function. + # The offsets of all function bodies, in the format [start1, end1, + # start2, end2, ...] where all ends are exclusive. array of integer functionBodyOffsets # The first chunk of disassembly. WasmDisassemblyChunk chunk diff --git a/src/debug/debug-interface.cc b/src/debug/debug-interface.cc index 8ce4171409..fed94492ac 100644 --- a/src/debug/debug-interface.cc +++ b/src/debug/debug-interface.cc @@ -847,27 +847,8 @@ int WasmScript::GetContainingFunction(int byte_offset) const { return i::wasm::GetContainingWasmFunction(module, byte_offset); } -void WasmScript::GetAllFunctionStarts(std::vector& starts) const { - i::DisallowGarbageCollection no_gc; - i::Handle script = Utils::OpenHandle(this); - DCHECK_EQ(i::Script::TYPE_WASM, script->type()); - i::wasm::NativeModule* native_module = script->wasm_native_module(); - const i::wasm::WasmModule* module = native_module->module(); - size_t num_functions = module->functions.size(); - starts.resize(num_functions + 1); - for (size_t i = 0; i < num_functions; i++) { - const i::wasm::WasmFunction& f = module->functions[i]; - starts[i] = f.code.offset(); - } - if (num_functions > 0) { - starts[num_functions] = - module->functions[num_functions - 1].code.end_offset(); - } else { - starts[0] = 0; - } -} - -void WasmScript::Disassemble(DisassemblyCollector* collector) { +void WasmScript::Disassemble(DisassemblyCollector* collector, + std::vector* function_body_offsets) { i::DisallowGarbageCollection no_gc; i::Handle script = Utils::OpenHandle(this); DCHECK_EQ(i::Script::TYPE_WASM, script->type()); @@ -875,7 +856,7 @@ void WasmScript::Disassemble(DisassemblyCollector* collector) { const i::wasm::WasmModule* module = native_module->module(); i::wasm::ModuleWireBytes wire_bytes(native_module->wire_bytes()); i::wasm::Disassemble(module, wire_bytes, native_module->GetNamesProvider(), - collector); + collector, function_body_offsets); } uint32_t WasmScript::GetFunctionHash(int function_index) { diff --git a/src/debug/debug-interface.h b/src/debug/debug-interface.h index 821c99c60d..cc8cfa0706 100644 --- a/src/debug/debug-interface.h +++ b/src/debug/debug-interface.h @@ -258,11 +258,9 @@ class WasmScript : public Script { std::pair GetFunctionRange(int function_index) const; int GetContainingFunction(int byte_offset) const; - // For N functions, {starts} will have N+1 entries: the last is the offset of - // the first byte after the end of the last function. - void GetAllFunctionStarts(std::vector& starts) const; - void Disassemble(DisassemblyCollector* collector); + void Disassemble(DisassemblyCollector* collector, + std::vector* function_body_offsets); uint32_t GetFunctionHash(int function_index); diff --git a/src/inspector/v8-debugger-agent-impl.cc b/src/inspector/v8-debugger-agent-impl.cc index c516fae8c5..4b0ce20cf6 100644 --- a/src/inspector/v8-debugger-agent-impl.cc +++ b/src/inspector/v8-debugger-agent-impl.cc @@ -1214,11 +1214,10 @@ Response V8DebuggerAgentImpl::disassembleWasmModule( } std::unique_ptr collector = std::make_unique(); - script->Disassemble(collector.get()); + std::vector functionBodyOffsets; + script->Disassemble(collector.get(), &functionBodyOffsets); *out_totalNumberOfLines = static_cast(collector->total_number_of_lines()); - std::vector functionBodyOffsets; - script->GetAllFunctionStarts(functionBodyOffsets); *out_functionBodyOffsets = std::make_unique>(std::move(functionBodyOffsets)); // Even an empty module would disassemble to "(module)", never to zero lines. diff --git a/src/inspector/v8-debugger-script.cc b/src/inspector/v8-debugger-script.cc index 05a8879856..4634380c57 100644 --- a/src/inspector/v8-debugger-script.cc +++ b/src/inspector/v8-debugger-script.cc @@ -98,18 +98,13 @@ class ActualScript : public V8DebuggerScript { return v8::Just(String16(external_url.data(), external_url.size())); } - void GetAllFunctionStarts(std::vector& starts) const override { + void Disassemble(v8::debug::DisassemblyCollector* collector, + std::vector* function_body_offsets) const override { v8::HandleScope scope(m_isolate); v8::Local script = this->script(); DCHECK(script->IsWasm()); - v8::debug::WasmScript::Cast(*script)->GetAllFunctionStarts(starts); - } - - void Disassemble(v8::debug::DisassemblyCollector* collector) const override { - v8::HandleScope scope(m_isolate); - v8::Local script = this->script(); - DCHECK(script->IsWasm()); - v8::debug::WasmScript::Cast(*script)->Disassemble(collector); + v8::debug::WasmScript::Cast(*script)->Disassemble(collector, + function_body_offsets); } #endif // V8_ENABLE_WEBASSEMBLY diff --git a/src/inspector/v8-debugger-script.h b/src/inspector/v8-debugger-script.h index f0158d3c47..80b900c9be 100644 --- a/src/inspector/v8-debugger-script.h +++ b/src/inspector/v8-debugger-script.h @@ -105,9 +105,8 @@ class V8DebuggerScript { getDebugSymbolsType() const = 0; virtual v8::Maybe getExternalDebugSymbolsURL() const = 0; void removeWasmBreakpoint(int id); - virtual void GetAllFunctionStarts(std::vector& starts) const = 0; - virtual void Disassemble( - v8::debug::DisassemblyCollector* collector) const = 0; + virtual void Disassemble(v8::debug::DisassemblyCollector* collector, + std::vector* function_body_offsets) const = 0; #endif // V8_ENABLE_WEBASSEMBLY protected: diff --git a/src/wasm/wasm-disassembler-impl.h b/src/wasm/wasm-disassembler-impl.h index c9c59aca95..3530969218 100644 --- a/src/wasm/wasm-disassembler-impl.h +++ b/src/wasm/wasm-disassembler-impl.h @@ -90,7 +90,8 @@ class V8_EXPORT_PRIVATE FunctionBodyDisassembler names_(names) {} void DecodeAsWat(MultiLineStringBuilder& out, Indentation indentation, - FunctionHeader include_header = kPrintHeader); + FunctionHeader include_header = kPrintHeader, + uint32_t* first_instruction_offset = nullptr); void DecodeGlobalInitializer(StringBuilder& out); @@ -128,14 +129,13 @@ class V8_EXPORT_PRIVATE FunctionBodyDisassembler class ModuleDisassembler { public: - enum ByteOffsets { kSkipByteOffsets = false, kIncludeByteOffsets = true }; - - V8_EXPORT_PRIVATE ModuleDisassembler(MultiLineStringBuilder& out, - const WasmModule* module, - NamesProvider* names, - const ModuleWireBytes wire_bytes, - ByteOffsets byte_offsets, - AccountingAllocator* allocator); + V8_EXPORT_PRIVATE ModuleDisassembler( + MultiLineStringBuilder& out, const WasmModule* module, + NamesProvider* names, const ModuleWireBytes wire_bytes, + AccountingAllocator* allocator, + // When non-nullptr, doubles as a sentinel that bytecode offsets should be + // stored for each line of disassembly. + std::vector* function_body_offsets = nullptr); V8_EXPORT_PRIVATE ~ModuleDisassembler(); V8_EXPORT_PRIVATE void PrintTypeDefinition(uint32_t type_index, @@ -165,6 +165,7 @@ class ModuleDisassembler { const byte* start_; Zone zone_; std::unique_ptr offsets_; + std::vector* function_body_offsets_; }; } // namespace wasm diff --git a/src/wasm/wasm-disassembler.cc b/src/wasm/wasm-disassembler.cc index e513b31698..53512db10c 100644 --- a/src/wasm/wasm-disassembler.cc +++ b/src/wasm/wasm-disassembler.cc @@ -20,11 +20,12 @@ namespace wasm { void Disassemble(const WasmModule* module, ModuleWireBytes wire_bytes, NamesProvider* names, - v8::debug::DisassemblyCollector* collector) { + v8::debug::DisassemblyCollector* collector, + std::vector* function_body_offsets) { MultiLineStringBuilder out; AccountingAllocator allocator; - ModuleDisassembler md(out, module, names, wire_bytes, - ModuleDisassembler::kIncludeByteOffsets, &allocator); + ModuleDisassembler md(out, module, names, wire_bytes, &allocator, + function_body_offsets); md.PrintModule({0, 2}); out.ToDisassemblyCollector(collector); } @@ -149,7 +150,8 @@ void PrintSignatureOneLine(StringBuilder& out, const FunctionSig* sig, void FunctionBodyDisassembler::DecodeAsWat(MultiLineStringBuilder& out, Indentation indentation, - FunctionHeader include_header) { + FunctionHeader include_header, + uint32_t* first_instruction_offset) { out_ = &out; int base_indentation = indentation.current(); // Print header. @@ -184,6 +186,7 @@ void FunctionBodyDisassembler::DecodeAsWat(MultiLineStringBuilder& out, } consume_bytes(locals_length); out.set_current_line_bytecode_offset(pc_offset()); + if (first_instruction_offset) *first_instruction_offset = pc_offset(); // Main loop. while (pc_ < end_) { @@ -662,16 +665,17 @@ ModuleDisassembler::ModuleDisassembler(MultiLineStringBuilder& out, const WasmModule* module, NamesProvider* names, const ModuleWireBytes wire_bytes, - ByteOffsets byte_offsets, - AccountingAllocator* allocator) + AccountingAllocator* allocator, + std::vector* function_body_offsets) : out_(out), module_(module), names_(names), wire_bytes_(wire_bytes), start_(wire_bytes_.start()), zone_(allocator, "disassembler zone"), - offsets_(new OffsetsProvider()) { - if (byte_offsets == kIncludeByteOffsets) { + offsets_(new OffsetsProvider()), + function_body_offsets_(function_body_offsets) { + if (function_body_offsets != nullptr) { offsets_->CollectOffsets(module, wire_bytes_.start(), wire_bytes_.end(), allocator); } @@ -920,6 +924,11 @@ void ModuleDisassembler::PrintModule(Indentation indentation) { if (out_.length() != 0) out_.NextLine(0); // XI. Code / function bodies. + if (function_body_offsets_ != nullptr) { + size_t num_defined_functions = + module_->functions.size() - module_->num_imported_functions; + function_body_offsets_->reserve(num_defined_functions * 2); + } for (uint32_t i = module_->num_imported_functions; i < module_->functions.size(); i++) { const WasmFunction* func = &module_->functions[i]; @@ -935,7 +944,13 @@ void ModuleDisassembler::PrintModule(Indentation indentation) { FunctionBodyDisassembler d(&zone_, module_, i, &detected, func->sig, code.begin(), code.end(), func->code.offset(), names_); - d.DecodeAsWat(out_, indentation, FunctionBodyDisassembler::kSkipHeader); + uint32_t first_instruction_offset; + d.DecodeAsWat(out_, indentation, FunctionBodyDisassembler::kSkipHeader, + &first_instruction_offset); + if (function_body_offsets_ != nullptr) { + function_body_offsets_->push_back(first_instruction_offset); + function_body_offsets_->push_back(d.pc_offset()); + } } // XII. Data diff --git a/src/wasm/wasm-disassembler.h b/src/wasm/wasm-disassembler.h index b65e8500e4..b7aacc5bbb 100644 --- a/src/wasm/wasm-disassembler.h +++ b/src/wasm/wasm-disassembler.h @@ -24,7 +24,8 @@ class NamesProvider; void Disassemble(const WasmModule* module, ModuleWireBytes wire_bytes, NamesProvider* names, - v8::debug::DisassemblyCollector* collector); + v8::debug::DisassemblyCollector* collector, + std::vector* function_body_offsets); } // namespace wasm } // namespace internal diff --git a/test/inspector/debugger/wasm-scripts-disassembly-expected.txt b/test/inspector/debugger/wasm-scripts-disassembly-expected.txt index b7758ee9da..e928020430 100644 --- a/test/inspector/debugger/wasm-scripts-disassembly-expected.txt +++ b/test/inspector/debugger/wasm-scripts-disassembly-expected.txt @@ -14,7 +14,7 @@ bytecode: 0x02 0x66 0x32 0x02 0x08 0x01 0x00 0x01 ;; offset 72..79 0x01 0x03 0x78 0x79 0x7a streamid: undefined -functionBodyOffsets: 28,40,44 +functionBodyOffsets: 33,39,41,44 totalNumberOfLines: 13 lines: (module $moduleName diff --git a/tools/wasm/module-inspector.cc b/tools/wasm/module-inspector.cc index ebf6c404e3..4107875c62 100644 --- a/tools/wasm/module-inspector.cc +++ b/tools/wasm/module-inspector.cc @@ -795,8 +795,7 @@ class FormatConverter { // Print any types that were used by the function. out.NextLine(0); - ModuleDisassembler md(out, module(), names(), wire_bytes_, - ModuleDisassembler::kSkipByteOffsets, &allocator_); + ModuleDisassembler md(out, module(), names(), wire_bytes_, &allocator_); for (uint32_t type_index : d.used_types()) { md.PrintTypeDefinition(type_index, {0, 1}, NamesProvider::kIndexAsComment); @@ -805,8 +804,7 @@ class FormatConverter { void WatForModule(MultiLineStringBuilder& out) { DCHECK(ok_); - ModuleDisassembler md(out, module(), names(), wire_bytes_, - ModuleDisassembler::kSkipByteOffsets, &allocator_); + ModuleDisassembler md(out, module(), names(), wire_bytes_, &allocator_); md.PrintModule({0, 2}); }