Commit 237d21b2 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Decode and use module name

* add functionality to wasm-module-builder.js to emit the module name
  in the name section.
* extend WasmModule to store the module name length and offset.
* add functionality to module-decoder.cc to decode the module name.
* use the module name for printing stack traces. more uses should
  follow.
* extend one message test to contain a module name.

R=ahaas@chromium.org

Change-Id: I94e6f1f2eb99cb656a92a85bb7afe0742292046f
Reviewed-on: https://chromium-review.googlesource.com/530366Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45846}
parent 80717621
......@@ -674,9 +674,23 @@ Handle<Object> WasmStackFrame::GetFunctionName() {
MaybeHandle<String> WasmStackFrame::ToString() {
IncrementalStringBuilder builder(isolate_);
Handle<Object> name = GetFunctionName();
if (!name->IsNull(isolate_)) {
builder.AppendString(Handle<String>::cast(name));
Handle<WasmCompiledModule> compiled_module(wasm_instance_->compiled_module(),
isolate_);
MaybeHandle<String> module_name =
WasmCompiledModule::GetModuleNameOrNull(isolate_, compiled_module);
MaybeHandle<String> function_name = WasmCompiledModule::GetFunctionNameOrNull(
isolate_, compiled_module, wasm_func_index_);
bool has_name = !module_name.is_null() || !function_name.is_null();
if (has_name) {
if (module_name.is_null()) {
builder.AppendString(function_name.ToHandleChecked());
} else {
builder.AppendString(module_name.ToHandleChecked());
if (!function_name.is_null()) {
builder.AppendCString(".");
builder.AppendString(function_name.ToHandleChecked());
}
}
builder.AppendCString(" (");
}
......@@ -689,7 +703,7 @@ MaybeHandle<String> WasmStackFrame::ToString() {
SNPrintF(ArrayVector(buffer), ":%d", GetPosition());
builder.AppendCString(buffer);
if (!name->IsNull(isolate_)) builder.AppendCString(")");
if (has_name) builder.AppendCString(")");
return builder.Finish();
}
......
......@@ -728,28 +728,45 @@ class ModuleDecoder : public Decoder {
// Decode function names, ignore the rest.
// Local names will be decoded when needed.
if (name_type == NameSectionType::kFunction) {
uint32_t functions_count = inner.consume_u32v("functions count");
for (; inner.ok() && functions_count > 0; --functions_count) {
uint32_t function_index = inner.consume_u32v("function index");
switch (name_type) {
case NameSectionType::kModule: {
uint32_t name_length = 0;
uint32_t name_offset =
wasm::consume_string(inner, &name_length, false, "function name");
// Be lenient with errors in the name section: Ignore illegal
// or out-of-order indexes and non-UTF8 names. You can even assign
// to the same function multiple times (last valid one wins).
if (inner.ok() && function_index < module_->functions.size() &&
wasm::consume_string(inner, &name_length, false, "module name");
if (inner.ok() &&
unibrow::Utf8::ValidateEncoding(
inner.start() + inner.GetBufferRelativeOffset(name_offset),
name_length)) {
module_->functions[function_index].name_offset = name_offset;
module_->functions[function_index].name_length = name_length;
module_->name_length = name_length;
module_->name_offset = name_offset;
}
break;
}
} else {
inner.consume_bytes(name_payload_len, "name subsection payload");
case NameSectionType::kFunction: {
uint32_t functions_count = inner.consume_u32v("functions count");
for (; inner.ok() && functions_count > 0; --functions_count) {
uint32_t function_index = inner.consume_u32v("function index");
uint32_t name_length = 0;
uint32_t name_offset = wasm::consume_string(inner, &name_length,
false, "function name");
// Be lenient with errors in the name section: Ignore illegal
// or out-of-order indexes and non-UTF8 names. You can even assign
// to the same function multiple times (last valid one wins).
if (inner.ok() && function_index < module_->functions.size() &&
unibrow::Utf8::ValidateEncoding(
inner.start() + inner.GetBufferRelativeOffset(name_offset),
name_length)) {
module_->functions[function_index].name_offset = name_offset;
module_->functions[function_index].name_length = name_length;
}
}
break;
}
default:
inner.consume_bytes(name_payload_len, "name subsection payload");
break;
}
}
// Skip the whole names section in the outer decoder.
......
......@@ -39,7 +39,7 @@ enum SectionCode : int8_t {
kFirstSectionInModule = kTypeSectionCode,
};
enum NameSectionType : uint8_t { kFunction = 1, kLocal = 2 };
enum NameSectionType : uint8_t { kModule = 0, kFunction = 1, kLocal = 2 };
inline bool IsValidSectionCode(uint8_t byte) {
return kTypeSectionCode <= byte && byte <= kDataSectionCode;
......
......@@ -169,6 +169,9 @@ struct V8_EXPORT_PRIVATE WasmModule {
uint32_t num_imported_functions = 0; // number of imported functions.
uint32_t num_declared_functions = 0; // number of declared functions.
uint32_t num_exported_functions = 0; // number of exported functions.
uint32_t name_offset = 0; // offset in the module bytes of the name, if any.
uint32_t name_length = 0; // length in bytes of the name.
// TODO(wasm): Add url here, for spec'ed location information.
std::vector<FunctionSig*> signatures; // signatures in this module.
std::vector<WasmFunction> functions; // functions in this module.
std::vector<WasmDataSegment> data_segments; // data segments in this module.
......
......@@ -1218,6 +1218,15 @@ uint32_t WasmCompiledModule::default_mem_size() const {
return min_mem_pages() * WasmModule::kPageSize;
}
MaybeHandle<String> WasmCompiledModule::GetModuleNameOrNull(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
WasmModule* module = compiled_module->module();
DCHECK_IMPLIES(module->name_offset == 0, module->name_length == 0);
if (!module->name_offset) return {};
return WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
isolate, compiled_module, module->name_offset, module->name_length);
}
MaybeHandle<String> WasmCompiledModule::GetFunctionNameOrNull(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
uint32_t func_index) {
......
......@@ -442,6 +442,10 @@ class WasmCompiledModule : public FixedArray {
static void ReinitializeAfterDeserialization(Isolate*,
Handle<WasmCompiledModule>);
// Get the module name, if set. Returns an empty handle otherwise.
static MaybeHandle<String> GetModuleNameOrNull(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module);
// Get the function name of the function identified by the given index.
// Returns a null handle if the function is unnamed or the name is not a valid
// UTF-8 string.
......
// 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.
// Flags: --expose-wasm
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder();
builder.addFunction('main', kSig_i_v).addBody([kExprUnreachable]).exportFunc();
builder.instantiate().exports.main();
wasm-function[0]:1: RuntimeError: unreachable
RuntimeError: unreachable
at main (wasm-function[0]:1)
at *%(basename)s:12:31
// 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.
// Flags: --expose-wasm
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder();
builder.setName('test-module');
builder.addFunction('main', kSig_i_v).addBody([kExprUnreachable]).exportFunc();
builder.instantiate().exports.main();
wasm-function[0]:1: RuntimeError: unreachable
RuntimeError: unreachable
at test-module.main (wasm-function[0]:1)
at *%(basename)s:13:31
// 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.
// Flags: --expose-wasm
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder();
builder.setName('test-module');
builder.addFunction(undefined, kSig_i_v)
.addBody([kExprUnreachable])
.exportAs('main');
builder.instantiate().exports.main();
wasm-function[0]:1: RuntimeError: unreachable
RuntimeError: unreachable
at test-module (wasm-function[0]:1)
at *%(basename)s:15:31
// 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.
// Flags: --expose-wasm
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder();
builder.addFunction(undefined, kSig_i_v)
.addBody([kExprUnreachable])
.exportAs('main');
builder.instantiate().exports.main();
wasm-function[0]:1: RuntimeError: unreachable
RuntimeError: unreachable
at wasm-function[0]:1
at *%(basename)s:14:31
......@@ -66,6 +66,7 @@ let kDataSectionCode = 11; // Data segments
let kNameSectionCode = 12; // Name section (encoded as string)
// Name section types
let kModuleNameCode = 0;
let kFunctionNamesCode = 1;
let kLocalNamesCode = 2;
......
......@@ -277,6 +277,11 @@ class WasmModuleBuilder {
return this;
}
setName(name) {
this.name = name;
return this;
}
toArray(debug = false) {
let binary = new Binary;
let wasm = this;
......@@ -545,19 +550,26 @@ class WasmModuleBuilder {
binary.emit_bytes(exp);
}
// Add function names.
if (num_function_names > 0) {
// Add names.
if (num_function_names > 0 || wasm.name !== undefined) {
if (debug) print('emitting names @ ' + binary.length);
binary.emit_section(kUnknownSectionCode, section => {
section.emit_string('name');
section.emit_section(kFunctionNamesCode, name_section => {
name_section.emit_u32v(num_function_names);
for (let func of wasm.functions) {
if (func.name === undefined) continue;
name_section.emit_u32v(func.index);
name_section.emit_string(func.name);
}
});
if (wasm.name !== undefined) {
section.emit_section(kModuleNameCode, name_section => {
name_section.emit_string(wasm.name);
});
}
if (num_function_names > 0) {
section.emit_section(kFunctionNamesCode, name_section => {
name_section.emit_u32v(num_function_names);
for (let func of wasm.functions) {
if (func.name === undefined) continue;
name_section.emit_u32v(func.index);
name_section.emit_string(func.name);
}
});
}
});
}
......
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