[wasm-debug] Let wasm scripts report correct column information.
In the debugger, wasm scripts currently do not contain meaningful column informations. Fix that by keeping track of the offset and size of the wasm code section inthe module and reporting that to the debugger. Bug: chromium:1042636 Change-Id: Ie2b5d3a50952a467d256f815c16e459cb0ae600e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2011083 Commit-Queue: Philip Pfaffe <pfaffe@chromium.org> Reviewed-by: Simon Zünd <szuend@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#65913}
This commit is contained in:
parent
e56a7edbed
commit
827107a7dc
@ -9731,6 +9731,26 @@ uint32_t debug::WasmScript::GetFunctionHash(int function_index) {
|
||||
function_bytes.length(), 0);
|
||||
}
|
||||
|
||||
int debug::WasmScript::CodeOffset() const {
|
||||
i::DisallowHeapAllocation no_gc;
|
||||
i::Handle<i::Script> 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();
|
||||
|
||||
return module->code.offset();
|
||||
}
|
||||
|
||||
int debug::WasmScript::CodeLength() const {
|
||||
i::DisallowHeapAllocation no_gc;
|
||||
i::Handle<i::Script> 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();
|
||||
|
||||
return module->code.length();
|
||||
}
|
||||
|
||||
debug::Location::Location(int line_number, int column_number)
|
||||
: line_number_(line_number),
|
||||
column_number_(column_number),
|
||||
|
@ -174,6 +174,9 @@ class WasmScript : public Script {
|
||||
int GetContainingFunction(int byte_offset) const;
|
||||
|
||||
uint32_t GetFunctionHash(int function_index);
|
||||
|
||||
int CodeOffset() const;
|
||||
int CodeLength() const;
|
||||
};
|
||||
|
||||
V8_EXPORT_PRIVATE void GetLoadedScripts(
|
||||
|
@ -121,9 +121,20 @@ class ActualScript : public V8DebuggerScript {
|
||||
return v8::Just(v8::debug::WasmScript::Cast(*script)->Bytecode());
|
||||
}
|
||||
int startLine() const override { return m_startLine; }
|
||||
int startColumn() const override { return m_startColumn; }
|
||||
int startColumn() const override {
|
||||
v8::HandleScope scope(m_isolate);
|
||||
auto script = this->script();
|
||||
if (!script->IsWasm()) return m_startColumn;
|
||||
return v8::debug::WasmScript::Cast(*script)->CodeOffset();
|
||||
}
|
||||
int endLine() const override { return m_endLine; }
|
||||
int endColumn() const override { return m_endColumn; }
|
||||
int endColumn() const override {
|
||||
v8::HandleScope scope(m_isolate);
|
||||
auto script = this->script();
|
||||
if (!script->IsWasm()) return m_endColumn;
|
||||
return v8::debug::WasmScript::Cast(*script)->CodeOffset() +
|
||||
v8::debug::WasmScript::Cast(*script)->CodeLength();
|
||||
}
|
||||
bool isSourceLoadedLazily() const override { return false; }
|
||||
int length() const override {
|
||||
v8::HandleScope scope(m_isolate);
|
||||
|
@ -2079,6 +2079,7 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
|
||||
int num_functions, uint32_t offset,
|
||||
std::shared_ptr<WireBytesStorage> wire_bytes_storage,
|
||||
int code_section_length) {
|
||||
DCHECK_GE(code_section_length, 0);
|
||||
TRACE_STREAMING("Start the code section with %d functions...\n",
|
||||
num_functions);
|
||||
if (!decoder_.CheckFunctionsCount(static_cast<uint32_t>(num_functions),
|
||||
@ -2098,6 +2099,8 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
|
||||
uses_liftoff);
|
||||
job_->DoImmediately<AsyncCompileJob::PrepareAndStartCompile>(
|
||||
decoder_.shared_module(), false, code_size_estimate);
|
||||
|
||||
decoder_.set_code_section(offset, static_cast<uint32_t>(code_section_length));
|
||||
auto* compilation_state = Impl(job_->native_module_->compilation_state());
|
||||
compilation_state->SetWireBytesStorage(std::move(wire_bytes_storage));
|
||||
DCHECK_EQ(job_->native_module_->module()->origin, kWasmOrigin);
|
||||
|
@ -869,6 +869,8 @@ class ModuleDecoderImpl : public Decoder {
|
||||
if (failed()) break;
|
||||
DecodeFunctionBody(i, size, offset, verify_functions);
|
||||
}
|
||||
DCHECK_GE(pc_offset(), pos);
|
||||
set_code_section(pos, pc_offset() - pos);
|
||||
}
|
||||
|
||||
bool CheckFunctionsCount(uint32_t functions_count, uint32_t offset) {
|
||||
@ -1126,6 +1128,10 @@ class ModuleDecoderImpl : public Decoder {
|
||||
return result;
|
||||
}
|
||||
|
||||
void set_code_section(uint32_t offset, uint32_t size) {
|
||||
module_->code = {offset, size};
|
||||
}
|
||||
|
||||
// Decodes an entire module.
|
||||
ModuleResult DecodeModule(Counters* counters, AccountingAllocator* allocator,
|
||||
bool verify_functions = true) {
|
||||
@ -1958,6 +1964,10 @@ ModuleResult ModuleDecoder::FinishDecoding(bool verify_functions) {
|
||||
return impl_->FinishDecoding(verify_functions);
|
||||
}
|
||||
|
||||
void ModuleDecoder::set_code_section(uint32_t offset, uint32_t size) {
|
||||
return impl_->set_code_section(offset, size);
|
||||
}
|
||||
|
||||
SectionCode ModuleDecoder::IdentifyUnknownSection(Decoder* decoder,
|
||||
const byte* end) {
|
||||
WireBytesRef string = consume_string(decoder, true, "section name");
|
||||
|
@ -192,6 +192,8 @@ class ModuleDecoder {
|
||||
|
||||
ModuleResult FinishDecoding(bool verify_functions = true);
|
||||
|
||||
void set_code_section(uint32_t offset, uint32_t size);
|
||||
|
||||
const std::shared_ptr<WasmModule>& shared_module() const;
|
||||
WasmModule* module() const { return shared_module().get(); }
|
||||
|
||||
|
@ -238,6 +238,7 @@ struct V8_EXPORT_PRIVATE WasmModule {
|
||||
uint32_t num_declared_functions = 0; // excluding imported
|
||||
uint32_t num_exported_functions = 0;
|
||||
uint32_t num_declared_data_segments = 0; // From the DataCount section.
|
||||
WireBytesRef code = {0, 0};
|
||||
WireBytesRef name = {0, 0};
|
||||
std::vector<FunctionSig*> signatures; // by signature index
|
||||
std::vector<uint32_t> signature_ids; // by signature index
|
||||
|
@ -1215,6 +1215,41 @@ STREAM_TEST(TestCompileErrorFunctionName) {
|
||||
}
|
||||
}
|
||||
|
||||
STREAM_TEST(TestSetModuleCodeSection) {
|
||||
StreamTester tester;
|
||||
|
||||
uint8_t code[] = {
|
||||
U32V_1(4), // body size
|
||||
U32V_1(0), // locals count
|
||||
kExprLocalGet, 0, kExprEnd // body
|
||||
};
|
||||
|
||||
const uint8_t bytes[] = {
|
||||
WASM_MODULE_HEADER, // module header
|
||||
kTypeSectionCode, // section code
|
||||
U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
|
||||
U32V_1(1), // type count
|
||||
SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
|
||||
kFunctionSectionCode, // section code
|
||||
U32V_1(1 + 1), // section size
|
||||
U32V_1(1), // functions count
|
||||
0, // signature index
|
||||
kCodeSectionCode, // section code
|
||||
U32V_1(1 + arraysize(code) * 1), // section size
|
||||
U32V_1(1), // functions count
|
||||
};
|
||||
|
||||
tester.OnBytesReceived(bytes, arraysize(bytes));
|
||||
tester.OnBytesReceived(code, arraysize(code));
|
||||
tester.FinishStream();
|
||||
tester.RunCompilerTasks();
|
||||
CHECK_EQ(tester.native_module()->module()->code.offset(),
|
||||
arraysize(bytes) - 1);
|
||||
CHECK_EQ(tester.native_module()->module()->code.length(),
|
||||
arraysize(code) + 1);
|
||||
CHECK(tester.IsPromiseFulfilled());
|
||||
}
|
||||
|
||||
#undef STREAM_TEST
|
||||
|
||||
} // namespace wasm
|
||||
|
@ -1,15 +1,15 @@
|
||||
Tests how wasm scripts are reported
|
||||
Check that each inspector gets a wasm script at module creation time.
|
||||
Session #1: Script #0 parsed. URL: wasm://wasm/f608ae1e. Source map URL:
|
||||
Session #2: Script #0 parsed. URL: wasm://wasm/f608ae1e. Source map URL:
|
||||
Session #1: Script #1 parsed. URL: wasm://wasm/74f86b7e. Source map URL: wasm://dwarf
|
||||
Session #2: Script #1 parsed. URL: wasm://wasm/74f86b7e. Source map URL: wasm://dwarf
|
||||
Session #1: Script #2 parsed. URL: wasm://wasm/3754e3fe. Source map URL: abc
|
||||
Session #2: Script #2 parsed. URL: wasm://wasm/3754e3fe. Source map URL: abc
|
||||
Session #1: Script #3 parsed. URL: wasm://wasm/2bd2e40e. Source map URL: abc
|
||||
Session #2: Script #3 parsed. URL: wasm://wasm/2bd2e40e. Source map URL: abc
|
||||
Session #1: Script #4 parsed. URL: wasm://wasm/f568e726. Source map URL: abc
|
||||
Session #2: Script #4 parsed. URL: wasm://wasm/f568e726. Source map URL: abc
|
||||
Session #1: Script #0 parsed. URL: wasm://wasm/f608ae1e. Source map URL: , code begin: 34, code end: 48
|
||||
Session #2: Script #0 parsed. URL: wasm://wasm/f608ae1e. Source map URL: , code begin: 34, code end: 48
|
||||
Session #1: Script #1 parsed. URL: wasm://wasm/74f86b7e. Source map URL: wasm://dwarf, code begin: 34, code end: 48
|
||||
Session #2: Script #1 parsed. URL: wasm://wasm/74f86b7e. Source map URL: wasm://dwarf, code begin: 34, code end: 48
|
||||
Session #1: Script #2 parsed. URL: wasm://wasm/3754e3fe. Source map URL: abc, code begin: 34, code end: 48
|
||||
Session #2: Script #2 parsed. URL: wasm://wasm/3754e3fe. Source map URL: abc, code begin: 34, code end: 48
|
||||
Session #1: Script #3 parsed. URL: wasm://wasm/2bd2e40e. Source map URL: abc, code begin: 34, code end: 48
|
||||
Session #2: Script #3 parsed. URL: wasm://wasm/2bd2e40e. Source map URL: abc, code begin: 34, code end: 48
|
||||
Session #1: Script #4 parsed. URL: wasm://wasm/f568e726. Source map URL: abc, code begin: 34, code end: 48
|
||||
Session #2: Script #4 parsed. URL: wasm://wasm/f568e726. Source map URL: abc, code begin: 34, code end: 48
|
||||
Session #1: Source for wasm://wasm/f608ae1e:
|
||||
Raw: 00 61 73 6d 01 00 00 00 01 07 02 60 00 00 60 00 00 03 03 02 00 01 07 08 01 04 6d 61 69 6e 00 01 0a 0e 02 03 00 01 0b 08 00 02 40 41 02 1a 0b 0b 00 1b 04 6e 61 6d 65 01 14 02 00 0b 6e 6f 70 46 75 6e 63 74 69 6f 6e 01 04 6d 61 69 6e
|
||||
Imports: []
|
||||
|
@ -85,9 +85,13 @@ function trackScripts(debuggerParams) {
|
||||
Protocol.Debugger.enable(debuggerParams);
|
||||
Protocol.Debugger.onScriptParsed(handleScriptParsed);
|
||||
|
||||
async function loadScript({url, scriptId, sourceMapURL}) {
|
||||
InspectorTest.log(`Session #${sessionId}: Script #${scripts.length} parsed. URL: ${url}. Source map URL: ${sourceMapURL}`);
|
||||
let {result: {scriptSource, bytecode}} = await Protocol.Debugger.getScriptSource({scriptId});
|
||||
async function loadScript(
|
||||
{url, scriptId, sourceMapURL, startColumn, endColumn}) {
|
||||
InspectorTest.log(`Session #${sessionId}: Script #${
|
||||
scripts.length} parsed. URL: ${url}. Source map URL: ${
|
||||
sourceMapURL}, code begin: ${startColumn}, code end: ${endColumn}`);
|
||||
let {result: {scriptSource, bytecode}} =
|
||||
await Protocol.Debugger.getScriptSource({scriptId});
|
||||
if (bytecode) {
|
||||
if (scriptSource) {
|
||||
InspectorTest.log('Unexpected scriptSource with bytecode: ');
|
||||
@ -97,10 +101,17 @@ function trackScripts(debuggerParams) {
|
||||
bytecode = InspectorTest.decodeBase64(bytecode);
|
||||
// Check that it can be parsed back to a WebAssembly module.
|
||||
let module = new WebAssembly.Module(bytecode);
|
||||
scriptSource = `
|
||||
scriptSource =
|
||||
`
|
||||
Raw: ${Array.from(bytecode, b => ('0' + b.toString(16)).slice(-2)).join(' ')}
|
||||
Imports: [${WebAssembly.Module.imports(module).map(i => `${i.name}: ${i.kind} from "${i.module}"`).join(', ')}]
|
||||
Exports: [${WebAssembly.Module.exports(module).map(e => `${e.name}: ${e.kind}`).join(', ')}]
|
||||
Imports: [${
|
||||
WebAssembly.Module.imports(module)
|
||||
.map(i => `${i.name}: ${i.kind} from "${i.module}"`)
|
||||
.join(', ')}]
|
||||
Exports: [${
|
||||
WebAssembly.Module.exports(module)
|
||||
.map(e => `${e.name}: ${e.kind}`)
|
||||
.join(', ')}]
|
||||
`.trim();
|
||||
}
|
||||
InspectorTest.log(`Session #${sessionId}: Source for ${url}:`);
|
||||
|
Loading…
Reference in New Issue
Block a user