Commit 1a73f73b authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Implement extensible name section

The format of the name section changed recently. It now contains
subsections of different type (currently for function names or local
variable names).
This CL changes our internal wasm module builders (in JS and C++) to
emit this new format, and changes the decoder to understand it.
We currently only parse the function name section, and ignore names of
local variables. I will later extend this to parse local variable names
when needed for debugging.

R=ahaas@chromium.org, rossberg@chromium.org
BUG=v8:6222

Change-Id: I2627160c25c9209a3f09abe0b88941ec48b24434
Reviewed-on: https://chromium-review.googlesource.com/470247
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Rossberg <rossberg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44492}
parent ceb3f4b1
......@@ -30,7 +30,7 @@ namespace wasm {
#define TRACE(...)
#endif
const char* SectionName(WasmSectionCode code) {
const char* SectionName(SectionCode code) {
switch (code) {
case kUnknownSectionCode:
return "Unknown";
......@@ -106,7 +106,7 @@ class WasmSectionIterator {
return section_code_ != kUnknownSectionCode && decoder_.more();
}
inline WasmSectionCode section_code() const { return section_code_; }
inline SectionCode section_code() const { return section_code_; }
inline const byte* section_start() const { return section_start_; }
......@@ -138,7 +138,7 @@ class WasmSectionIterator {
private:
Decoder& decoder_;
WasmSectionCode section_code_;
SectionCode section_code_;
const byte* section_start_;
const byte* payload_start_;
const byte* section_end_;
......@@ -184,15 +184,13 @@ class WasmSectionIterator {
strncmp(reinterpret_cast<const char*>(section_name_start),
kNameString, kNameStringLength) == 0) {
section_code = kNameSectionCode;
} else {
section_code = kUnknownSectionCode;
}
} else if (!IsValidSectionCode(section_code)) {
decoder_.errorf(decoder_.pc(), "unknown section code #0x%02x",
section_code);
section_code = kUnknownSectionCode;
}
section_code_ = static_cast<WasmSectionCode>(section_code);
section_code_ = static_cast<SectionCode>(section_code);
TRACE("Section: %s\n", SectionName(section_code_));
if (section_code_ == kUnknownSectionCode &&
......@@ -651,22 +649,36 @@ class ModuleDecoder : public Decoder {
// TODO(titzer): find a way to report name errors as warnings.
// Use an inner decoder so that errors don't fail the outer decoder.
Decoder inner(start_, pc_, end_);
uint32_t functions_count = inner.consume_u32v("functions count");
for (uint32_t i = 0; inner.ok() && i < functions_count; ++i) {
uint32_t function_name_length = 0;
uint32_t name_offset =
consume_string(inner, &function_name_length, false);
uint32_t func_index = i;
if (inner.ok() && func_index < module->functions.size()) {
module->functions[func_index].name_offset = name_offset;
module->functions[func_index].name_length = function_name_length;
}
uint32_t local_names_count = inner.consume_u32v("local names count");
for (uint32_t j = 0; inner.ok() && j < local_names_count; j++) {
uint32_t length = inner.consume_u32v("string length");
inner.consume_bytes(length, "string");
// Decode all name subsections.
// Be lenient with their order.
while (inner.ok() && inner.more()) {
uint8_t name_type = inner.consume_u8("name type");
if (name_type & 0x80) inner.error("name type if not varuint7");
uint32_t name_payload_len = inner.consume_u32v("name payload length");
if (!inner.checkAvailable(name_payload_len)) break;
// 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");
uint32_t name_length = 0;
uint32_t name_offset = consume_string(inner, &name_length, false);
// 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::Validate(inner.start() + name_offset,
name_length)) {
module->functions[function_index].name_offset = name_offset;
module->functions[function_index].name_length = name_length;
}
}
} else {
inner.consume_bytes(name_payload_len, "name subsection payload");
}
}
// Skip the whole names section in the outer decoder.
......
......@@ -20,7 +20,7 @@ const uint8_t kWasmFunctionTypeForm = 0x60;
const uint8_t kWasmAnyFunctionTypeForm = 0x70;
const uint8_t kResizableMaximumFlag = 1;
enum WasmSectionCode {
enum SectionCode {
kUnknownSectionCode = 0, // code for unknown sections
kTypeSectionCode = 1, // Function signature declarations
kImportSectionCode = 2, // Import declarations
......@@ -36,11 +36,13 @@ enum WasmSectionCode {
kNameSectionCode = 12, // Name section (encoded as a string)
};
enum NameSectionType : uint8_t { kFunction = 1, kLocal = 2 };
inline bool IsValidSectionCode(uint8_t byte) {
return kTypeSectionCode <= byte && byte <= kDataSectionCode;
}
const char* SectionName(WasmSectionCode code);
const char* SectionName(SectionCode code);
typedef Result<const WasmModule*> ModuleResult;
typedef Result<WasmFunction*> FunctionResult;
......
......@@ -34,7 +34,7 @@ namespace wasm {
// Emit a section code and the size as a padded varint that can be patched
// later.
size_t EmitSection(WasmSectionCode code, ZoneBuffer& buffer) {
size_t EmitSection(SectionCode code, ZoneBuffer& buffer) {
// Emit the section code.
buffer.write_u8(code);
......@@ -206,8 +206,7 @@ void WasmFunctionBuilder::WriteExports(ZoneBuffer& buffer) const {
buffer.write_size(name.size());
buffer.write(reinterpret_cast<const byte*>(name.data()), name.size());
buffer.write_u8(kExternalFunction);
buffer.write_u32v(func_index_ + static_cast<uint32_t>(
builder_->function_imports_.size()));
buffer.write_size(func_index_ + builder_->function_imports_.size());
}
}
......@@ -391,14 +390,14 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
}
// == Emit function signatures ===============================================
bool has_names = false;
uint32_t num_function_names = 0;
if (functions_.size() > 0) {
size_t start = EmitSection(kFunctionSectionCode, buffer);
buffer.write_size(functions_.size());
for (auto function : functions_) {
function->WriteSignature(buffer);
exports += static_cast<uint32_t>(function->exported_names_.size());
if (function->name_.size() > 0) has_names = true;
if (!function->name_.empty()) ++num_function_names;
}
FixupSection(buffer, start);
}
......@@ -507,8 +506,7 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
// == emit start function index ==============================================
if (start_function_index_ >= 0) {
size_t start = EmitSection(kStartSectionCode, buffer);
buffer.write_u32v(start_function_index_ +
static_cast<uint32_t>(function_imports_.size()));
buffer.write_size(start_function_index_ + function_imports_.size());
FixupSection(buffer, start);
}
......@@ -523,8 +521,7 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
buffer.write_size(indirect_functions_.size()); // element count
for (auto index : indirect_functions_) {
buffer.write_u32v(index +
static_cast<uint32_t>(function_imports_.size()));
buffer.write_size(index + function_imports_.size());
}
FixupSection(buffer, start);
......@@ -557,7 +554,7 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
}
// == Emit names =============================================================
if (has_names) {
if (num_function_names > 0 || !function_imports_.empty()) {
// Emit the section code.
buffer.write_u8(kUnknownSectionCode);
// Emit a placeholder for the length.
......@@ -565,19 +562,37 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
// Emit the section string.
buffer.write_size(4);
buffer.write(reinterpret_cast<const byte*>("name"), 4);
// Emit the names.
size_t count = functions_.size() + function_imports_.size();
buffer.write_size(count);
for (size_t i = 0; i < function_imports_.size(); i++) {
buffer.write_u8(0); // empty name for import
buffer.write_u8(0); // no local variables
// Emit a subsection for the function names.
buffer.write_u8(NameSectionType::kFunction);
// Emit a placeholder for the subsection length.
size_t functions_start = buffer.reserve_u32v();
// Emit the function names.
// Imports are always named.
uint32_t num_imports = static_cast<uint32_t>(function_imports_.size());
buffer.write_size(num_imports + num_function_names);
uint32_t function_index = 0;
for (; function_index < num_imports; ++function_index) {
const WasmFunctionImport* import = &function_imports_[function_index];
DCHECK_NOT_NULL(import->name);
buffer.write_u32v(function_index);
uint32_t name_len = static_cast<uint32_t>(import->name_length);
buffer.write_u32v(name_len);
buffer.write(reinterpret_cast<const byte*>(import->name), name_len);
}
for (auto function : functions_) {
buffer.write_size(function->name_.size());
buffer.write(reinterpret_cast<const byte*>(function->name_.data()),
function->name_.size());
buffer.write_u8(0);
if (num_function_names > 0) {
for (auto function : functions_) {
DCHECK_EQ(function_index,
function->func_index() + function_imports_.size());
if (!function->name_.empty()) {
buffer.write_u32v(function_index);
buffer.write_size(function->name_.size());
buffer.write(reinterpret_cast<const byte*>(function->name_.data()),
function->name_.size());
}
++function_index;
}
}
FixupSection(buffer, functions_start);
FixupSection(buffer, start);
}
}
......
......@@ -1132,9 +1132,10 @@ MaybeHandle<String> WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
isolate);
DCHECK_GE(module_bytes->length(), offset);
DCHECK_GE(module_bytes->length() - offset, size);
Address raw = module_bytes->GetCharsAddress() + offset;
if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size))
return {}; // UTF8 decoding error for name.
// UTF8 validation happens at decode time.
DCHECK(unibrow::Utf8::Validate(
reinterpret_cast<const byte*>(module_bytes->GetCharsAddress() + offset),
size));
DCHECK_GE(kMaxInt, offset);
DCHECK_GE(kMaxInt, size);
return isolate->factory()->NewStringFromUtf8SubString(
......@@ -1219,6 +1220,8 @@ MaybeHandle<String> WasmCompiledModule::GetFunctionNameOrNull(
uint32_t func_index) {
DCHECK_LT(func_index, compiled_module->module()->functions.size());
WasmFunction& function = compiled_module->module()->functions[func_index];
DCHECK_IMPLIES(function.name_offset == 0, function.name_length == 0);
if (!function.name_offset) return {};
return WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
isolate, compiled_module, function.name_offset, function.name_length);
}
......
......@@ -308,14 +308,17 @@ class TestingModule : public ModuleEnv {
Handle<SeqOneByteString> old_bytes(
instance_object_->compiled_module()->module_bytes(), isolate_);
uint32_t old_size = static_cast<uint32_t>(old_bytes->length());
ScopedVector<byte> new_bytes(old_size + bytes.length());
// Avoid placing strings at offset 0, this might be interpreted as "not
// set", e.g. for function names.
uint32_t bytes_offset = old_size ? old_size : 1;
ScopedVector<byte> new_bytes(bytes_offset + bytes.length());
memcpy(new_bytes.start(), old_bytes->GetChars(), old_size);
memcpy(new_bytes.start() + old_size, bytes.start(), bytes.length());
memcpy(new_bytes.start() + bytes_offset, bytes.start(), bytes.length());
Handle<SeqOneByteString> new_bytes_str = Handle<SeqOneByteString>::cast(
isolate_->factory()->NewStringFromOneByte(new_bytes).ToHandleChecked());
instance_object_->compiled_module()->shared()->set_module_bytes(
*new_bytes_str);
return old_size;
return bytes_offset;
}
WasmFunction* GetFunctionAt(int index) { return &module_.functions[index]; }
......
......@@ -19,8 +19,7 @@ using namespace v8::internal::wasm;
static const char* kNameString = "name";
static const size_t kNameStringLength = 4;
int fuzz_wasm_section(WasmSectionCode section, const uint8_t* data,
size_t size) {
int fuzz_wasm_section(SectionCode section, const uint8_t* data, size_t size) {
v8_fuzzer::FuzzerSupport* support = v8_fuzzer::FuzzerSupport::Get();
v8::Isolate* isolate = support->GetIsolate();
v8::internal::Isolate* i_isolate =
......
......@@ -10,7 +10,7 @@
#include "src/wasm/module-decoder.h"
int fuzz_wasm_section(v8::internal::wasm::WasmSectionCode section,
int fuzz_wasm_section(v8::internal::wasm::SectionCode section,
const uint8_t* data, size_t size);
#endif // WASM_SECTION_FUZZERS_H_
Running testFunction...
Script nr 0 parsed. URL: v8://test/setup
Script nr 1 parsed. URL: v8://test/runTestFunction
Script nr 2 parsed. URL: wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-0
Script nr 2 parsed. URL: wasm://wasm/wasm-354ada0e/wasm-354ada0e-0
This is a wasm script (nr 0).
Script nr 3 parsed. URL: wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1
Script nr 3 parsed. URL: wasm://wasm/wasm-354ada0e/wasm-354ada0e-1
This is a wasm script (nr 1).
Querying breakable locations for all wasm scripts now...
Requesting all breakable locations in wasm script 0
......@@ -37,51 +37,51 @@ Requesting breakable locations in lines [4,6)
[0] 4:6 || >call 0
[1] 5:4 || >end
Setting a breakpoint on each breakable location...
Setting at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-0:2:2
Setting at wasm://wasm/wasm-354ada0e/wasm-354ada0e-0:2:2
Success!
Setting at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-0:3:2
Setting at wasm://wasm/wasm-354ada0e/wasm-354ada0e-0:3:2
Success!
Setting at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-0:4:2
Setting at wasm://wasm/wasm-354ada0e/wasm-354ada0e-0:4:2
Success!
Setting at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-0:5:0
Setting at wasm://wasm/wasm-354ada0e/wasm-354ada0e-0:5:0
Success!
Setting at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:1:2
Setting at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:1:2
Success!
Setting at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:2:2
Setting at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:2:2
Success!
Setting at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:3:4
Setting at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:3:4
Success!
Setting at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:4:6
Setting at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:4:6
Success!
Setting at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:5:4
Setting at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:5:4
Success!
Setting at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:6:2
Setting at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:6:2
Success!
Setting at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:7:0
Setting at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:7:0
Success!
Running wasm code...
Missing breakpoints: 11
Script nr 4 parsed. URL: v8://test/runWasm
Stopped at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:1:2
Stopped at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:1:2
Missing breakpoints: 10
Stopped at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:2:2
Stopped at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:2:2
Missing breakpoints: 9
Stopped at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:3:4
Stopped at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:3:4
Missing breakpoints: 8
Stopped at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:4:6
Stopped at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:4:6
Missing breakpoints: 7
Stopped at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-0:2:2
Stopped at wasm://wasm/wasm-354ada0e/wasm-354ada0e-0:2:2
Missing breakpoints: 6
Stopped at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-0:3:2
Stopped at wasm://wasm/wasm-354ada0e/wasm-354ada0e-0:3:2
Missing breakpoints: 5
Stopped at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-0:4:2
Stopped at wasm://wasm/wasm-354ada0e/wasm-354ada0e-0:4:2
Missing breakpoints: 4
Stopped at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-0:5:0
Stopped at wasm://wasm/wasm-354ada0e/wasm-354ada0e-0:5:0
Missing breakpoints: 3
Stopped at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:5:4
Stopped at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:5:4
Missing breakpoints: 2
Stopped at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:6:2
Stopped at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:6:2
Missing breakpoints: 1
Stopped at wasm://wasm/wasm-eb3c2032/wasm-eb3c2032-1:7:0
Stopped at wasm://wasm/wasm-354ada0e/wasm-354ada0e-1:7:0
Missing breakpoints: 0
Finished!
Check that inspector gets two wasm scripts at module creation time.
Script #0 parsed. URL: v8://test/testFunction
Script #1 parsed. URL: v8://test/runTestRunction
Script #2 parsed. URL: wasm://wasm/wasm-4205e2ce/wasm-4205e2ce-0
Script #3 parsed. URL: wasm://wasm/wasm-4205e2ce/wasm-4205e2ce-1
Source for wasm://wasm/wasm-4205e2ce/wasm-4205e2ce-0:
Script #2 parsed. URL: wasm://wasm/wasm-7b04570e/wasm-7b04570e-0
Script #3 parsed. URL: wasm://wasm/wasm-7b04570e/wasm-7b04570e-1
Source for wasm://wasm/wasm-7b04570e/wasm-7b04570e-0:
func $nopFunction
nop
end
Source for wasm://wasm/wasm-4205e2ce/wasm-4205e2ce-1:
Source for wasm://wasm/wasm-7b04570e/wasm-7b04570e-1:
func $main
block
i32.const 2
......
......@@ -2,10 +2,10 @@ Installing code an global variable.
Calling instantiate function.
Waiting for two wasm scripts to be parsed.
Ignoring script with url v8://test/callInstantiate
Got wasm script: wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-0
Requesting source for wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-0...
Got wasm script: wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1
Requesting source for wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1...
Got wasm script: wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-0
Requesting source for wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-0...
Got wasm script: wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1
Requesting source for wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1...
func $wasm_A
nop
nop
......@@ -25,59 +25,59 @@ func $wasm_B (param i32)
end
end
Setting breakpoint on line 7 (on the setlocal before the call), url wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1
Setting breakpoint on line 7 (on the setlocal before the call), url wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1
{
columnNumber : 6
lineNumber : 7
scriptId : <scriptId>
}
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:7:6: >set_local 0
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:7:6: >set_local 0
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:8:6: >call 0
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:8:6: >call 0
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-0:1:2: >nop
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-0:1:2: >nop
Step action: stepOver
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-0:2:2: >nop
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-0:2:2: >nop
Step action: stepOut
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:9:6: >br 1
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:9:6: >br 1
Step action: stepOut
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:7:6: >set_local 0
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:7:6: >set_local 0
Step action: stepOver
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:8:6: >call 0
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:8:6: >call 0
Step action: stepOver
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:9:6: >br 1
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:9:6: >br 1
Step action: resume
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:7:6: >set_local 0
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:7:6: >set_local 0
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:8:6: >call 0
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:8:6: >call 0
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-0:1:2: >nop
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-0:1:2: >nop
Step action: stepOut
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:9:6: >br 1
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:9:6: >br 1
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:1:2: >loop
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:1:2: >loop
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:2:4: >get_local 0
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:2:4: >get_local 0
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:3:4: >if
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:3:4: >if
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:4:6: >get_local 0
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:4:6: >get_local 0
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:5:6: >i32.const 1
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:5:6: >i32.const 1
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:6:6: >i32.sub
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:6:6: >i32.sub
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:7:6: >set_local 0
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:7:6: >set_local 0
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:8:6: >call 0
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:8:6: >call 0
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-0:1:2: >nop
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-0:1:2: >nop
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-0:2:2: >nop
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-0:2:2: >nop
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-0:3:0: >end
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-0:3:0: >end
Step action: stepInto
Paused at wasm://wasm/wasm-0e9ccf72/wasm-0e9ccf72-1:9:6: >br 1
Paused at wasm://wasm/wasm-0c10a5fe/wasm-0c10a5fe-1:9:6: >br 1
Step action: resume
exports.main returned!
Finished!
......@@ -10,7 +10,7 @@ var name = 'regression_684858';
function patchNameLength(buffer) {
var count = 0;
var view = new Uint8Array(buffer);
for (var i = 0, e = view.length - name.length; i < e; ++i) {
for (var i = 0, e = view.length - name.length; i <= e; ++i) {
var subs = String.fromCharCode.apply(null, view.slice(i, i + name.length));
if (subs != name) continue;
++count;
......
......@@ -54,16 +54,16 @@ Error.prepareStackTrace = function(error, frames) {
return frames;
};
(function testFunctionNamesAsCallSites() {
var names = expected_names.concat(["testFunctionNamesAsCallSites", null]);
var names = expected_names.concat(['testFunctionNamesAsCallSites', null]);
try {
module.exports.main();
assertFalse("should throw");
assertFalse('should throw');
} catch (e) {
assertEquals(names.length, e.stack.length);
assertEquals(names.length, e.stack.length, 'stack length');
for (var i = 0; i < names.length; ++i) {
assertEquals(names[i], e.stack[i].getFunctionName());
assertEquals(
names[i], e.stack[i].getFunctionName(), 'function name at ' + i);
}
}
})();
......@@ -25,7 +25,8 @@ function verifyStack(frames, expected) {
assertContains(exp[4], frames[i].getFileName(), "["+i+"].getFileName()");
var toString;
if (exp[0]) {
toString = exp[1] + " (<WASM>[" + exp[2] + "]+" + exp[3] + ")";
var fun_str = exp[1] !== null ? exp[1] : "<WASM UNNAMED>";
toString = fun_str + " (<WASM>[" + exp[2] + "]+" + exp[3] + ")";
} else {
toString = exp[4] + ":" + exp[2] + ":";
}
......@@ -70,10 +71,10 @@ var module = builder.instantiate({mod: {func: STACK}});
(function testSimpleStack() {
var expected_string = "Error\n" +
// The line numbers below will change as this test gains / loses lines..
" at STACK (stack.js:39:11)\n" + // --
" at STACK (stack.js:40:11)\n" + // --
" at main (<WASM>[1]+1)\n" + // --
" at testSimpleStack (stack.js:78:18)\n" + // --
" at stack.js:80:3"; // --
" at testSimpleStack (stack.js:79:18)\n" + // --
" at stack.js:81:3"; // --
module.exports.main();
assertEquals(expected_string, stripPath(stack));
......@@ -90,10 +91,10 @@ Error.prepareStackTrace = function(error, frames) {
verifyStack(stack, [
// isWasm function line pos file
[ false, "STACK", 39, 0, "stack.js"],
[ false, "STACK", 40, 0, "stack.js"],
[ true, "main", 1, 1, null],
[ false, "testStackFrames", 89, 0, "stack.js"],
[ false, null, 98, 0, "stack.js"]
[ false, "testStackFrames", 90, 0, "stack.js"],
[ false, null, 99, 0, "stack.js"]
]);
})();
......@@ -106,8 +107,8 @@ Error.prepareStackTrace = function(error, frames) {
verifyStack(e.stack, [
// isWasm function line pos file
[ true, "exec_unreachable", 2, 1, null],
[ false, "testWasmUnreachable", 102, 0, "stack.js"],
[ false, null, 113, 0, "stack.js"]
[ false, "testWasmUnreachable", 103, 0, "stack.js"],
[ false, null, 114, 0, "stack.js"]
]);
}
})();
......@@ -120,10 +121,10 @@ Error.prepareStackTrace = function(error, frames) {
assertContains("out of bounds", e.message);
verifyStack(e.stack, [
// isWasm function line pos file
[ true, "", 3, 3, null],
[ true, null, 3, 3, null],
[ true, "call_mem_out_of_bounds", 4, 1, null],
[ false, "testWasmMemOutOfBounds", 117, 0, "stack.js"],
[ false, null, 129, 0, "stack.js"]
[ false, "testWasmMemOutOfBounds", 118, 0, "stack.js"],
[ false, null, 130, 0, "stack.js"]
]);
}
})();
......
......@@ -65,6 +65,10 @@ let kCodeSectionCode = 10; // Function code
let kDataSectionCode = 11; // Data segments
let kNameSectionCode = 12; // Name section (encoded as string)
// Name section types
let kFunctionNamesCode = 1;
let kLocalNamesCode = 2;
let kWasmFunctionTypeForm = 0x60;
let kWasmAnyFunctionTypeForm = 0x70;
......
......@@ -336,15 +336,16 @@ class WasmModuleBuilder {
}
// Add functions declarations
let has_names = false;
let num_function_names = 0;
let names = false;
if (wasm.functions.length > 0) {
if (debug) print("emitting function decls @ " + binary.length);
binary.emit_section(kFunctionSectionCode, section => {
section.emit_u32v(wasm.functions.length);
for (let func of wasm.functions) {
has_names = has_names || (func.name != undefined &&
func.name.length > 0);
if (func.name !== undefined) {
++num_function_names;
}
section.emit_u32v(func.type_index);
}
});
......@@ -363,7 +364,7 @@ class WasmModuleBuilder {
}
// Add memory section
if (wasm.memory != undefined) {
if (wasm.memory !== undefined) {
if (debug) print("emitting memory @ " + binary.length);
binary.emit_section(kMemorySectionCode, section => {
section.emit_u8(1); // one memory entry
......@@ -424,7 +425,7 @@ class WasmModuleBuilder {
}
// Add export table.
var mem_export = (wasm.memory != undefined && wasm.memory.exp);
var mem_export = (wasm.memory !== undefined && wasm.memory.exp);
var exports_count = wasm.exports.length + (mem_export ? 1 : 0);
if (exports_count > 0) {
if (debug) print("emitting exports @ " + binary.length);
......@@ -444,7 +445,7 @@ class WasmModuleBuilder {
}
// Add start function section.
if (wasm.start_index != undefined) {
if (wasm.start_index !== undefined) {
if (debug) print("emitting start function @ " + binary.length);
binary.emit_section(kStartSectionCode, section => {
section.emit_u32v(wasm.start_index);
......@@ -485,7 +486,7 @@ class WasmModuleBuilder {
// Function body length will be patched later.
let local_decls = [];
let l = func.locals;
if (l != undefined) {
if (l !== undefined) {
let local_decls_count = 0;
if (l.i32_count > 0) {
local_decls.push({count: l.i32_count, type: kWasmI32});
......@@ -545,21 +546,18 @@ class WasmModuleBuilder {
}
// Add function names.
if (has_names) {
if (debug) print("emitting names @ " + binary.length);
if (num_function_names > 0) {
if (debug) print('emitting names @ ' + binary.length);
binary.emit_section(kUnknownSectionCode, section => {
section.emit_string("name");
var count = wasm.functions.length + wasm.num_imported_funcs;
section.emit_u32v(count);
for (var i = 0; i < wasm.num_imported_funcs; i++) {
section.emit_u8(0); // empty string
section.emit_u8(0); // local names count == 0
}
for (let func of wasm.functions) {
var name = func.name == undefined ? "" : func.name;
section.emit_string(name);
section.emit_u8(0); // local names count == 0
}
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);
}
});
});
}
......
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