Commit 07752032 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Decode local names for debugging

When providing scope information (containing the value of local
variables of live stack frames), decode the local variable names of all
functions in a wasm module and store this in the WasmDebugInfo
structure.
Use these names to actually name the reported locals, instead of using
the default names "param#<d>" and "local#<d>". These names are only used
as fallbacks for locals which were not assigned a name.

R=titzer@chromium.org,kozyatinskiy@chromium.org
BUG=v8:6245

Change-Id: Ibf7d30e392248ef5590177cd8b6329239b45e018
Reviewed-on: https://chromium-review.googlesource.com/548495
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarBen Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46379}
parent eaf850e2
...@@ -1404,6 +1404,60 @@ std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start, ...@@ -1404,6 +1404,60 @@ std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start,
return result; return result;
} }
void DecodeLocalNames(const byte* module_start, const byte* module_end,
LocalNames* result) {
DCHECK_NOT_NULL(result);
DCHECK(result->names.empty());
static constexpr int kModuleHeaderSize = 8;
Decoder decoder(module_start, module_end);
decoder.consume_bytes(kModuleHeaderSize, "module header");
WasmSectionIterator section_iter(decoder);
while (decoder.ok() && section_iter.more() &&
section_iter.section_code() != kNameSectionCode) {
section_iter.advance(true);
}
if (!section_iter.more()) return;
// Reset the decoder to not read beyond the name section end.
decoder.Reset(section_iter.payload(), decoder.pc_offset());
while (decoder.ok() && decoder.more()) {
uint8_t name_type = decoder.consume_u8("name type");
if (name_type & 0x80) break; // no varuint7
uint32_t name_payload_len = decoder.consume_u32v("name payload length");
if (!decoder.checkAvailable(name_payload_len)) break;
if (name_type != NameSectionType::kLocal) {
decoder.consume_bytes(name_payload_len, "name subsection payload");
continue;
}
uint32_t local_names_count = decoder.consume_u32v("local names count");
for (uint32_t i = 0; i < local_names_count; ++i) {
uint32_t func_index = decoder.consume_u32v("function index");
if (func_index > kMaxInt) continue;
result->names.emplace_back(static_cast<int>(func_index));
LocalNamesPerFunction& func_names = result->names.back();
result->max_function_index =
std::max(result->max_function_index, func_names.function_index);
uint32_t num_names = decoder.consume_u32v("namings count");
for (uint32_t k = 0; k < num_names; ++k) {
uint32_t local_index = decoder.consume_u32v("local index");
WireBytesRef name = wasm::consume_string(decoder, true, "local name");
if (!decoder.ok()) break;
if (local_index > kMaxInt) continue;
func_names.max_local_index =
std::max(func_names.max_local_index, static_cast<int>(local_index));
func_names.names.emplace_back(static_cast<int>(local_index), name);
}
}
}
}
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -51,6 +51,7 @@ typedef Result<std::unique_ptr<WasmModule>> ModuleResult; ...@@ -51,6 +51,7 @@ typedef Result<std::unique_ptr<WasmModule>> ModuleResult;
typedef Result<std::unique_ptr<WasmFunction>> FunctionResult; typedef Result<std::unique_ptr<WasmFunction>> FunctionResult;
typedef std::vector<std::pair<int, int>> FunctionOffsets; typedef std::vector<std::pair<int, int>> FunctionOffsets;
typedef Result<FunctionOffsets> FunctionOffsetsResult; typedef Result<FunctionOffsets> FunctionOffsetsResult;
struct AsmJsOffsetEntry { struct AsmJsOffsetEntry {
int byte_offset; int byte_offset;
int source_position_call; int source_position_call;
...@@ -59,6 +60,24 @@ struct AsmJsOffsetEntry { ...@@ -59,6 +60,24 @@ struct AsmJsOffsetEntry {
typedef std::vector<std::vector<AsmJsOffsetEntry>> AsmJsOffsets; typedef std::vector<std::vector<AsmJsOffsetEntry>> AsmJsOffsets;
typedef Result<AsmJsOffsets> AsmJsOffsetsResult; typedef Result<AsmJsOffsets> AsmJsOffsetsResult;
struct LocalName {
int local_index;
WireBytesRef name;
LocalName(int local_index, WireBytesRef name)
: local_index(local_index), name(name) {}
};
struct LocalNamesPerFunction {
int function_index;
int max_local_index = -1;
std::vector<LocalName> names;
explicit LocalNamesPerFunction(int function_index)
: function_index(function_index) {}
};
struct LocalNames {
int max_function_index = -1;
std::vector<LocalNamesPerFunction> names;
};
// Decodes the bytes of a wasm module between {module_start} and {module_end}. // Decodes the bytes of a wasm module between {module_start} and {module_end}.
V8_EXPORT_PRIVATE ModuleResult SyncDecodeWasmModule(Isolate* isolate, V8_EXPORT_PRIVATE ModuleResult SyncDecodeWasmModule(Isolate* isolate,
const byte* module_start, const byte* module_start,
...@@ -108,6 +127,13 @@ V8_EXPORT_PRIVATE std::vector<CustomSectionOffset> DecodeCustomSections( ...@@ -108,6 +127,13 @@ V8_EXPORT_PRIVATE std::vector<CustomSectionOffset> DecodeCustomSections(
AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* module_start, AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* module_start,
const byte* module_end); const byte* module_end);
// Decode the local names assignment from the name section.
// Stores the result in the given {LocalNames} structure. The result will be
// empty if no name section is present. On encountering an error in the name
// section, returns all information decoded up to the first error.
void DecodeLocalNames(const byte* module_start, const byte* module_end,
LocalNames* result);
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -61,6 +61,34 @@ Handle<Object> WasmValToValueObject(Isolate* isolate, WasmVal value) { ...@@ -61,6 +61,34 @@ Handle<Object> WasmValToValueObject(Isolate* isolate, WasmVal value) {
} }
} }
MaybeHandle<String> GetLocalName(Isolate* isolate,
Handle<WasmDebugInfo> debug_info,
int func_index, int local_index) {
DCHECK_LE(0, func_index);
DCHECK_LE(0, local_index);
if (!debug_info->has_locals_names()) {
Handle<WasmCompiledModule> compiled_module(
debug_info->wasm_instance()->compiled_module(), isolate);
Handle<FixedArray> locals_names =
wasm::DecodeLocalNames(isolate, compiled_module);
debug_info->set_locals_names(*locals_names);
}
Handle<FixedArray> locals_names(debug_info->locals_names(), isolate);
if (func_index >= locals_names->length() ||
locals_names->get(func_index)->IsUndefined(isolate)) {
return {};
}
Handle<FixedArray> func_locals_names(
FixedArray::cast(locals_names->get(func_index)), isolate);
if (local_index >= func_locals_names->length() ||
func_locals_names->get(local_index)->IsUndefined(isolate)) {
return {};
}
return handle(String::cast(func_locals_names->get(local_index)));
}
// Forward declaration. // Forward declaration.
class InterpreterHandle; class InterpreterHandle;
InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info); InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info);
...@@ -410,8 +438,10 @@ class InterpreterHandle { ...@@ -410,8 +438,10 @@ class InterpreterHandle {
} }
Handle<JSArray> GetScopeDetails(Address frame_pointer, int frame_index, Handle<JSArray> GetScopeDetails(Address frame_pointer, int frame_index,
Handle<WasmInstanceObject> instance) { Handle<WasmDebugInfo> debug_info) {
auto frame = GetInterpretedFrame(frame_pointer, frame_index); auto frame = GetInterpretedFrame(frame_pointer, frame_index);
Isolate* isolate = debug_info->GetIsolate();
Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
Handle<FixedArray> global_scope = Handle<FixedArray> global_scope =
isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize); isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
...@@ -434,7 +464,7 @@ class InterpreterHandle { ...@@ -434,7 +464,7 @@ class InterpreterHandle {
kExternalUint8Array, memory_buffer, 0, byte_length); kExternalUint8Array, memory_buffer, 0, byte_length);
JSObject::SetOwnPropertyIgnoreAttributes(global_scope_object, name, JSObject::SetOwnPropertyIgnoreAttributes(global_scope_object, name,
uint8_array, NONE) uint8_array, NONE)
.Check(); .Assert();
} }
Handle<FixedArray> local_scope = Handle<FixedArray> local_scope =
...@@ -450,15 +480,30 @@ class InterpreterHandle { ...@@ -450,15 +480,30 @@ class InterpreterHandle {
int num_params = frame->GetParameterCount(); int num_params = frame->GetParameterCount();
int num_locals = frame->GetLocalCount(); int num_locals = frame->GetLocalCount();
DCHECK_LE(num_params, num_locals); DCHECK_LE(num_params, num_locals);
for (int i = 0; i < num_locals; ++i) { if (num_locals > 0) {
// TODO(clemensh): Use names from name section if present. Handle<JSObject> locals_obj =
const char* label = i < num_params ? "param#%d" : "local#%d"; isolate_->factory()->NewJSObjectWithNullProto();
Handle<String> name = PrintFToOneByteString<true>(isolate_, label, i); Handle<String> locals_name =
WasmVal value = frame->GetLocalValue(i); isolate_->factory()->InternalizeOneByteString(
Handle<Object> value_obj = WasmValToValueObject(isolate_, value); STATIC_CHAR_VECTOR("locals"));
JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, name, JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, locals_name,
value_obj, NONE) locals_obj, NONE)
.Check(); .Assert();
for (int i = 0; i < num_locals; ++i) {
MaybeHandle<String> name =
GetLocalName(isolate, debug_info, frame->function()->func_index, i);
if (name.is_null()) {
// Parameters should come before locals in alphabetical ordering, so
// we name them "args" here.
const char* label = i < num_params ? "arg#%d" : "local#%d";
name = PrintFToOneByteString<true>(isolate_, label, i);
}
WasmVal value = frame->GetLocalValue(i);
Handle<Object> value_obj = WasmValToValueObject(isolate_, value);
JSObject::SetOwnPropertyIgnoreAttributes(
locals_obj, name.ToHandleChecked(), value_obj, NONE)
.Assert();
}
} }
// Fill stack values. // Fill stack values.
...@@ -468,18 +513,18 @@ class InterpreterHandle { ...@@ -468,18 +513,18 @@ class InterpreterHandle {
// which does not make too much sense here. // which does not make too much sense here.
Handle<JSObject> stack_obj = Handle<JSObject> stack_obj =
isolate_->factory()->NewJSObjectWithNullProto(); isolate_->factory()->NewJSObjectWithNullProto();
Handle<String> stack_name = isolate_->factory()->InternalizeOneByteString(
STATIC_CHAR_VECTOR("stack"));
JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, stack_name,
stack_obj, NONE)
.Assert();
for (int i = 0; i < stack_count; ++i) { for (int i = 0; i < stack_count; ++i) {
WasmVal value = frame->GetStackValue(i); WasmVal value = frame->GetStackValue(i);
Handle<Object> value_obj = WasmValToValueObject(isolate_, value); Handle<Object> value_obj = WasmValToValueObject(isolate_, value);
JSObject::SetOwnElementIgnoreAttributes( JSObject::SetOwnElementIgnoreAttributes(
stack_obj, static_cast<uint32_t>(i), value_obj, NONE) stack_obj, static_cast<uint32_t>(i), value_obj, NONE)
.Check(); .Assert();
} }
Handle<String> stack_name = isolate_->factory()->InternalizeOneByteString(
STATIC_CHAR_VECTOR("stack"));
JSObject::SetOwnPropertyIgnoreAttributes(local_scope_object, stack_name,
stack_obj, NONE)
.Check();
Handle<JSArray> global_jsarr = Handle<JSArray> global_jsarr =
isolate_->factory()->NewJSArrayWithElements(global_scope); isolate_->factory()->NewJSArrayWithElements(global_scope);
...@@ -695,6 +740,5 @@ Handle<JSArray> WasmDebugInfo::GetScopeDetails(Handle<WasmDebugInfo> debug_info, ...@@ -695,6 +740,5 @@ Handle<JSArray> WasmDebugInfo::GetScopeDetails(Handle<WasmDebugInfo> debug_info,
Address frame_pointer, Address frame_pointer,
int frame_index) { int frame_index) {
InterpreterHandle* interp_handle = GetInterpreterHandle(*debug_info); InterpreterHandle* interp_handle = GetInterpreterHandle(*debug_info);
Handle<WasmInstanceObject> instance(debug_info->wasm_instance()); return interp_handle->GetScopeDetails(frame_pointer, frame_index, debug_info);
return interp_handle->GetScopeDetails(frame_pointer, frame_index, instance);
} }
...@@ -742,6 +742,33 @@ Handle<JSArray> wasm::GetCustomSections(Isolate* isolate, ...@@ -742,6 +742,33 @@ Handle<JSArray> wasm::GetCustomSections(Isolate* isolate,
return array_object; return array_object;
} }
Handle<FixedArray> wasm::DecodeLocalNames(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
Handle<SeqOneByteString> wire_bytes(compiled_module->module_bytes(), isolate);
LocalNames decoded_locals;
{
DisallowHeapAllocation no_gc;
wasm::DecodeLocalNames(wire_bytes->GetChars(),
wire_bytes->GetChars() + wire_bytes->length(),
&decoded_locals);
}
Handle<FixedArray> locals_names =
isolate->factory()->NewFixedArray(decoded_locals.max_function_index + 1);
for (LocalNamesPerFunction& func : decoded_locals.names) {
Handle<FixedArray> func_locals_names =
isolate->factory()->NewFixedArray(func.max_local_index + 1);
locals_names->set(func.function_index, *func_locals_names);
for (LocalName& name : func.names) {
Handle<String> name_str =
WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
isolate, compiled_module, name.name)
.ToHandleChecked();
func_locals_names->set(name.local_index, *name_str);
}
}
return locals_names;
}
bool wasm::SyncValidate(Isolate* isolate, const ModuleWireBytes& bytes) { bool wasm::SyncValidate(Isolate* isolate, const ModuleWireBytes& bytes) {
if (bytes.start() == nullptr || bytes.length() == 0) return false; if (bytes.start() == nullptr || bytes.length() == 0) return false;
ModuleResult result = SyncDecodeWasmModule(isolate, bytes.start(), ModuleResult result = SyncDecodeWasmModule(isolate, bytes.start(),
......
...@@ -412,6 +412,11 @@ V8_EXPORT_PRIVATE Handle<JSArray> GetCustomSections( ...@@ -412,6 +412,11 @@ V8_EXPORT_PRIVATE Handle<JSArray> GetCustomSections(
Isolate* isolate, Handle<WasmModuleObject> module, Handle<String> name, Isolate* isolate, Handle<WasmModuleObject> module, Handle<String> name,
ErrorThrower* thrower); ErrorThrower* thrower);
// Decode local variable names from the names section. Return FixedArray of
// FixedArray of <undefined|String>. The outer fixed array is indexed by the
// function index, the inner one by the local index.
Handle<FixedArray> DecodeLocalNames(Isolate*, Handle<WasmCompiledModule>);
// Assumed to be called with a code object associated to a wasm module instance. // Assumed to be called with a code object associated to a wasm module instance.
// Intended to be called from runtime functions. // Intended to be called from runtime functions.
// Returns nullptr on failing to get owning instance. // Returns nullptr on failing to get owning instance.
......
...@@ -1597,3 +1597,6 @@ bool WasmInstanceWrapper::IsWasmInstanceWrapper(Object* obj) { ...@@ -1597,3 +1597,6 @@ bool WasmInstanceWrapper::IsWasmInstanceWrapper(Object* obj) {
return false; return false;
return true; return true;
} }
DEFINE_OPTIONAL_ARR_ACCESSORS(WasmDebugInfo, locals_names, kLocalsNames,
FixedArray)
...@@ -550,9 +550,13 @@ class WasmDebugInfo : public FixedArray { ...@@ -550,9 +550,13 @@ class WasmDebugInfo : public FixedArray {
kInstance, kInstance,
kInterpreterHandle, kInterpreterHandle,
kInterpretedFunctions, kInterpretedFunctions,
// FixedArray of FixedArray of <undefined|String>.
kLocalsNames,
kFieldCount kFieldCount
}; };
DECLARE_OPTIONAL_ACCESSORS(locals_names, FixedArray);
static Handle<WasmDebugInfo> New(Handle<WasmInstanceObject>); static Handle<WasmDebugInfo> New(Handle<WasmInstanceObject>);
// Setup a WasmDebugInfo with an existing WasmInstance struct. // Setup a WasmDebugInfo with an existing WasmInstance struct.
......
Test retrieving scope information when pausing in wasm functions
Installing code and global variable.
Calling instantiate function.
Waiting for wasm script to be parsed.
Got wasm script!
Setting breakpoint on line 2 (first instruction)
{
columnNumber : 2
lineNumber : 2
scriptId : <scriptId>
}
Paused:
(local i32 f64)
#i32.const 11
set_local 0
at func (2:2):
- scope (global):
-- skipped
- scope (local):
locals: "i32Arg": 4 (number), "local#1": 0 (number), "unicode☼f64": 0 (number)
stack:
at (anonymous) (0:17):
- scope (global):
-- skipped
Paused:
i32.const 11
#set_local 0
i32.const 47
at func (3:2):
- scope (global):
-- skipped
- scope (local):
locals: "i32Arg": 4 (number), "local#1": 0 (number), "unicode☼f64": 0 (number)
stack: "0": 11 (number)
at (anonymous) (0:17):
- scope (global):
-- skipped
Paused:
set_local 0
#i32.const 47
set_local 1
at func (4:2):
- scope (global):
-- skipped
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 0 (number), "unicode☼f64": 0 (number)
stack:
at (anonymous) (0:17):
- scope (global):
-- skipped
Paused:
i32.const 47
#set_local 1
i32.const 1
at func (5:2):
- scope (global):
-- skipped
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 0 (number), "unicode☼f64": 0 (number)
stack: "0": 47 (number)
at (anonymous) (0:17):
- scope (global):
-- skipped
Paused:
set_local 1
#i32.const 1
f64.convert_u/i32
at func (6:2):
- scope (global):
-- skipped
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "unicode☼f64": 0 (number)
stack:
at (anonymous) (0:17):
- scope (global):
-- skipped
Paused:
i32.const 1
#f64.convert_u/i32
i32.const 7
at func (7:2):
- scope (global):
-- skipped
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "unicode☼f64": 0 (number)
stack: "0": 1 (number)
at (anonymous) (0:17):
- scope (global):
-- skipped
Paused:
f64.convert_u/i32
#i32.const 7
f64.convert_u/i32
at func (8:2):
- scope (global):
-- skipped
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "unicode☼f64": 0 (number)
stack: "0": 1 (number)
at (anonymous) (0:17):
- scope (global):
-- skipped
Paused:
i32.const 7
#f64.convert_u/i32
f64.div
at func (9:2):
- scope (global):
-- skipped
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "unicode☼f64": 0 (number)
stack: "0": 1 (number), "1": 7 (number)
at (anonymous) (0:17):
- scope (global):
-- skipped
Paused:
f64.convert_u/i32
#f64.div
set_local 2
at func (10:2):
- scope (global):
-- skipped
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "unicode☼f64": 0 (number)
stack: "0": 1 (number), "1": 7 (number)
at (anonymous) (0:17):
- scope (global):
-- skipped
Paused:
f64.div
#set_local 2
end
at func (11:2):
- scope (global):
-- skipped
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "unicode☼f64": 0 (number)
stack: "0": 0.14285714285714285 (number)
at (anonymous) (0:17):
- scope (global):
-- skipped
Paused:
set_local 2
#end
at func (12:0):
- scope (global):
-- skipped
- scope (local):
locals: "i32Arg": 11 (number), "local#1": 47 (number), "unicode☼f64": 0.14285714285714285 (number)
stack:
at (anonymous) (0:17):
- scope (global):
-- skipped
exports.main returned. Test finished.
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
let {session, contextGroup, Protocol} = InspectorTest.start(
'Test retrieving scope information when pausing in wasm functions');
session.setupScriptMap();
Protocol.Debugger.enable();
let evaluate = code => Protocol.Runtime.evaluate({expression: code});
(async function test() {
let scriptId = await instantiateWasm();
await setBreakpoint(scriptId);
printPauseLocationsAndContinue();
await evaluate('instance.exports.main(4)');
InspectorTest.log('exports.main returned. Test finished.');
InspectorTest.completeTest();
})();
async function printPauseLocationsAndContinue() {
while (true) {
let msg = await Protocol.Debugger.oncePaused();
let loc = msg.params.callFrames[0].location;
InspectorTest.log('Paused:');
await session.logSourceLocation(loc);
await dumpScopeChainsOnPause(msg);
Protocol.Debugger.stepOver();
}
}
async function instantiateWasm() {
utils.load('test/mjsunit/wasm/wasm-constants.js');
utils.load('test/mjsunit/wasm/wasm-module-builder.js');
var builder = new WasmModuleBuilder();
builder.addFunction('func', kSig_v_i)
.addLocals(
{i32_count: 1, f64_count: 1}, ['i32Arg', undefined, 'unicode☼f64'])
.addBody([
// Set param 0 to 11.
kExprI32Const, 11, kExprSetLocal, 0,
// Set local 1 to 47.
kExprI32Const, 47, kExprSetLocal, 1,
// Set local 2 to 1/7.
kExprI32Const, 1, kExprF64UConvertI32, kExprI32Const, 7,
kExprF64UConvertI32, kExprF64Div, kExprSetLocal, 2
])
.exportAs('main');
var module_bytes = builder.toArray();
function instantiate(bytes) {
var buffer = new ArrayBuffer(bytes.length);
var view = new Uint8Array(buffer);
for (var i = 0; i < bytes.length; ++i) {
view[i] = bytes[i] | 0;
}
var module = new WebAssembly.Module(buffer);
// Set global variable.
instance = new WebAssembly.Instance(module);
}
InspectorTest.log('Installing code and global variable.');
await evaluate('var instance;\n' + instantiate.toString());
InspectorTest.log('Calling instantiate function.');
evaluate('instantiate(' + JSON.stringify(module_bytes) + ')');
return waitForWasmScript();
}
async function setBreakpoint(scriptId) {
InspectorTest.log('Setting breakpoint on line 2 (first instruction)');
let breakpoint = await Protocol.Debugger.setBreakpoint(
{'location': {'scriptId': scriptId, 'lineNumber': 2}});
printFailure(breakpoint);
InspectorTest.logMessage(breakpoint.result.actualLocation);
}
function printFailure(message) {
if (!message.result) {
InspectorTest.logMessage(message);
}
return message;
}
async function waitForWasmScript() {
InspectorTest.log('Waiting for wasm script to be parsed.');
while (true) {
let script_msg = await Protocol.Debugger.onceScriptParsed();
let url = script_msg.params.url;
if (!url.startsWith('wasm://')) {
continue;
}
InspectorTest.log('Got wasm script!');
return script_msg.params.scriptId;
}
}
async function getValueString(value) {
if (value.type == 'object') {
var msg = await Protocol.Runtime.getProperties({objectId: value.objectId});
printFailure(msg);
let printProperty = elem => '"' + elem.name + '"' +
': ' + elem.value.description + ' (' + elem.value.type + ')';
return msg.result.result.map(printProperty).join(', ');
}
return JSON.stringify(value.value) + ' (' + value.type + ')';
}
async function dumpProperties(message) {
printFailure(message);
for (var value of message.result.result) {
var value_str = await getValueString(value.value);
InspectorTest.log(' ' + value.name + ': ' + value_str);
}
}
async function dumpScopeChainsOnPause(message) {
for (var frame of message.params.callFrames) {
var functionName = frame.functionName || '(anonymous)';
var lineNumber = frame.location ? frame.location.lineNumber : frame.lineNumber;
var columnNumber = frame.location ? frame.location.columnNumber : frame.columnNumber;
InspectorTest.log(`at ${functionName} (${lineNumber}:${columnNumber}):`);
for (var scope of frame.scopeChain) {
InspectorTest.logObject(' - scope (' + scope.type + '):');
if (scope.type == 'global') {
InspectorTest.logObject(' -- skipped');
} else {
var properties = await Protocol.Runtime.getProperties(
{'objectId': scope.object.objectId});
await dumpProperties(properties);
}
}
}
}
...@@ -37,7 +37,7 @@ at wasm_B (7:6): ...@@ -37,7 +37,7 @@ at wasm_B (7:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 4 (number) locals: {"arg#0":4} (Object)
stack: {"0":3} (Object) stack: {"0":3} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -48,7 +48,7 @@ at wasm_B (8:6): ...@@ -48,7 +48,7 @@ at wasm_B (8:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 3 (number) locals: {"arg#0":3} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -64,7 +64,7 @@ at wasm_B (8:6): ...@@ -64,7 +64,7 @@ at wasm_B (8:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 3 (number) locals: {"arg#0":3} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -80,7 +80,7 @@ at wasm_B (8:6): ...@@ -80,7 +80,7 @@ at wasm_B (8:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 3 (number) locals: {"arg#0":3} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -91,7 +91,7 @@ at wasm_B (9:6): ...@@ -91,7 +91,7 @@ at wasm_B (9:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 3 (number) locals: {"arg#0":3} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -102,7 +102,7 @@ at wasm_B (7:6): ...@@ -102,7 +102,7 @@ at wasm_B (7:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 3 (number) locals: {"arg#0":3} (Object)
stack: {"0":2} (Object) stack: {"0":2} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -113,7 +113,7 @@ at wasm_B (8:6): ...@@ -113,7 +113,7 @@ at wasm_B (8:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 2 (number) locals: {"arg#0":2} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -124,7 +124,7 @@ at wasm_B (9:6): ...@@ -124,7 +124,7 @@ at wasm_B (9:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 2 (number) locals: {"arg#0":2} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -135,7 +135,7 @@ at wasm_B (7:6): ...@@ -135,7 +135,7 @@ at wasm_B (7:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 2 (number) locals: {"arg#0":2} (Object)
stack: {"0":1} (Object) stack: {"0":1} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -146,7 +146,7 @@ at wasm_B (8:6): ...@@ -146,7 +146,7 @@ at wasm_B (8:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 1 (number) locals: {"arg#0":1} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -162,7 +162,7 @@ at wasm_B (8:6): ...@@ -162,7 +162,7 @@ at wasm_B (8:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 1 (number) locals: {"arg#0":1} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -173,7 +173,7 @@ at wasm_B (9:6): ...@@ -173,7 +173,7 @@ at wasm_B (9:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 1 (number) locals: {"arg#0":1} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -184,7 +184,7 @@ at wasm_B (1:2): ...@@ -184,7 +184,7 @@ at wasm_B (1:2):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 1 (number) locals: {"arg#0":1} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -195,7 +195,7 @@ at wasm_B (2:4): ...@@ -195,7 +195,7 @@ at wasm_B (2:4):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 1 (number) locals: {"arg#0":1} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -206,7 +206,7 @@ at wasm_B (3:4): ...@@ -206,7 +206,7 @@ at wasm_B (3:4):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 1 (number) locals: {"arg#0":1} (Object)
stack: {"0":1} (Object) stack: {"0":1} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -217,7 +217,7 @@ at wasm_B (4:6): ...@@ -217,7 +217,7 @@ at wasm_B (4:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 1 (number) locals: {"arg#0":1} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -228,7 +228,7 @@ at wasm_B (5:6): ...@@ -228,7 +228,7 @@ at wasm_B (5:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 1 (number) locals: {"arg#0":1} (Object)
stack: {"0":1} (Object) stack: {"0":1} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -239,7 +239,7 @@ at wasm_B (6:6): ...@@ -239,7 +239,7 @@ at wasm_B (6:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 1 (number) locals: {"arg#0":1} (Object)
stack: {"0":1,"1":1} (Object) stack: {"0":1,"1":1} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -250,7 +250,7 @@ at wasm_B (7:6): ...@@ -250,7 +250,7 @@ at wasm_B (7:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 1 (number) locals: {"arg#0":1} (Object)
stack: {"0":0} (Object) stack: {"0":0} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -261,7 +261,7 @@ at wasm_B (8:6): ...@@ -261,7 +261,7 @@ at wasm_B (8:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 0 (number) locals: {"arg#0":0} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -277,7 +277,7 @@ at wasm_B (8:6): ...@@ -277,7 +277,7 @@ at wasm_B (8:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 0 (number) locals: {"arg#0":0} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -293,7 +293,7 @@ at wasm_B (8:6): ...@@ -293,7 +293,7 @@ at wasm_B (8:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 0 (number) locals: {"arg#0":0} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -309,7 +309,7 @@ at wasm_B (8:6): ...@@ -309,7 +309,7 @@ at wasm_B (8:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 0 (number) locals: {"arg#0":0} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
...@@ -320,7 +320,7 @@ at wasm_B (9:6): ...@@ -320,7 +320,7 @@ at wasm_B (9:6):
- scope (global): - scope (global):
-- skipped -- skipped
- scope (local): - scope (local):
param#0: 0 (number) locals: {"arg#0":0} (Object)
stack: {} (Object) stack: {} (Object)
at (anonymous) (0:17): at (anonymous) (0:17):
- scope (global): - scope (global):
......
...@@ -86,6 +86,15 @@ class WasmFunctionBuilder { ...@@ -86,6 +86,15 @@ class WasmFunctionBuilder {
this.body = []; this.body = [];
} }
numLocalNames() {
if (this.local_names === undefined) return 0;
let num_local_names = 0;
for (let loc_name of this.local_names) {
if (loc_name !== undefined) ++num_local_names;
}
return num_local_names;
}
exportAs(name) { exportAs(name) {
this.module.addExport(name, this.index); this.module.addExport(name, this.index);
return this; return this;
...@@ -112,8 +121,9 @@ class WasmFunctionBuilder { ...@@ -112,8 +121,9 @@ class WasmFunctionBuilder {
return this; return this;
} }
addLocals(locals) { addLocals(locals, names) {
this.locals = locals; this.locals = locals;
this.local_names = names;
return this; return this;
} }
...@@ -341,16 +351,11 @@ class WasmModuleBuilder { ...@@ -341,16 +351,11 @@ class WasmModuleBuilder {
} }
// Add functions declarations // Add functions declarations
let num_function_names = 0;
let names = false;
if (wasm.functions.length > 0) { if (wasm.functions.length > 0) {
if (debug) print("emitting function decls @ " + binary.length); if (debug) print("emitting function decls @ " + binary.length);
binary.emit_section(kFunctionSectionCode, section => { binary.emit_section(kFunctionSectionCode, section => {
section.emit_u32v(wasm.functions.length); section.emit_u32v(wasm.functions.length);
for (let func of wasm.functions) { for (let func of wasm.functions) {
if (func.name !== undefined) {
++num_function_names;
}
section.emit_u32v(func.type_index); section.emit_u32v(func.type_index);
} }
}); });
...@@ -551,15 +556,24 @@ class WasmModuleBuilder { ...@@ -551,15 +556,24 @@ class WasmModuleBuilder {
} }
// Add names. // Add names.
if (num_function_names > 0 || wasm.name !== undefined) { let num_function_names = 0;
let num_functions_with_local_names = 0;
for (let func of wasm.functions) {
if (func.name !== undefined) ++num_function_names;
if (func.numLocalNames() > 0) ++num_functions_with_local_names;
}
if (num_function_names > 0 || num_functions_with_local_names > 0 ||
wasm.name !== undefined) {
if (debug) print('emitting names @ ' + binary.length); if (debug) print('emitting names @ ' + binary.length);
binary.emit_section(kUnknownSectionCode, section => { binary.emit_section(kUnknownSectionCode, section => {
section.emit_string('name'); section.emit_string('name');
// Emit module name.
if (wasm.name !== undefined) { if (wasm.name !== undefined) {
section.emit_section(kModuleNameCode, name_section => { section.emit_section(kModuleNameCode, name_section => {
name_section.emit_string(wasm.name); name_section.emit_string(wasm.name);
}); });
} }
// Emit function names.
if (num_function_names > 0) { if (num_function_names > 0) {
section.emit_section(kFunctionNamesCode, name_section => { section.emit_section(kFunctionNamesCode, name_section => {
name_section.emit_u32v(num_function_names); name_section.emit_u32v(num_function_names);
...@@ -570,6 +584,22 @@ class WasmModuleBuilder { ...@@ -570,6 +584,22 @@ class WasmModuleBuilder {
} }
}); });
} }
// Emit local names.
if (num_functions_with_local_names > 0) {
section.emit_section(kLocalNamesCode, name_section => {
name_section.emit_u32v(num_functions_with_local_names);
for (let func of wasm.functions) {
if (func.numLocalNames() == 0) continue;
name_section.emit_u32v(func.index);
name_section.emit_u32v(func.numLocalNames());
for (let i = 0; i < func.local_names.length; ++i) {
if (func.local_names[i] === undefined) continue;
name_section.emit_u32v(i);
name_section.emit_string(func.local_names[i]);
}
}
});
}
}); });
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment