Commit 3596cac8 authored by clemensh's avatar clemensh Committed by Commit bot

[wasm] Differentiate unnamed and empty names

Empty function names are allowed and are output as such, unnamed
functions or functions with no valid UTF-8 name are output as
"<WASM UNNAMED>", while the CallSite object returns null as the
function name.

R=titzer@chromium.org, yangguo@chromium.org

Review-Url: https://codereview.chromium.org/1970503004
Cr-Commit-Position: refs/heads/master@{#36348}
parent 2c95b572
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include "src/safepoint-table.h" #include "src/safepoint-table.h"
#include "src/string-stream.h" #include "src/string-stream.h"
#include "src/vm-state-inl.h" #include "src/vm-state-inl.h"
#include "src/wasm/wasm-module.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -1355,13 +1354,6 @@ uint32_t WasmFrame::function_index() { ...@@ -1355,13 +1354,6 @@ uint32_t WasmFrame::function_index() {
return val; return val;
} }
Object* WasmFrame::function_name() {
Object* wasm_object = wasm_obj();
if (wasm_object->IsUndefined()) return wasm_object;
Handle<JSObject> wasm = handle(JSObject::cast(wasm_object));
return *wasm::GetWasmFunctionName(wasm, function_index());
}
namespace { namespace {
......
...@@ -971,8 +971,6 @@ class WasmFrame : public StandardFrame { ...@@ -971,8 +971,6 @@ class WasmFrame : public StandardFrame {
Object* wasm_obj(); Object* wasm_obj();
uint32_t function_index(); uint32_t function_index();
Object* function_name();
static WasmFrame* cast(StackFrame* frame) { static WasmFrame* cast(StackFrame* frame) {
DCHECK(frame->is_wasm()); DCHECK(frame->is_wasm());
return static_cast<WasmFrame*>(frame); return static_cast<WasmFrame*>(frame);
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
#include "src/v8.h" #include "src/v8.h"
#include "src/version.h" #include "src/version.h"
#include "src/vm-state-inl.h" #include "src/vm-state-inl.h"
#include "src/wasm/wasm-module.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -616,11 +616,17 @@ class CaptureStackTraceHelper { ...@@ -616,11 +616,17 @@ class CaptureStackTraceHelper {
factory()->NewJSObject(isolate_->object_function()); factory()->NewJSObject(isolate_->object_function());
if (!function_key_.is_null()) { if (!function_key_.is_null()) {
Handle<Object> fun_name = handle(frame->function_name(), isolate_); Object* wasm_object = frame->wasm_obj();
if (fun_name->IsUndefined()) Handle<String> name;
fun_name = isolate_->factory()->InternalizeUtf8String( if (!wasm_object->IsUndefined()) {
Vector<const char>("<WASM>")); Handle<JSObject> wasm = handle(JSObject::cast(wasm_object));
JSObject::AddProperty(stack_frame, function_key_, fun_name, NONE); wasm::GetWasmFunctionName(wasm, frame->function_index())
.ToHandle(&name);
}
if (name.is_null()) {
name = isolate_->factory()->NewStringFromStaticChars("<WASM UNNAMED>");
}
JSObject::AddProperty(stack_frame, function_key_, name, NONE);
} }
// Encode the function index as line number. // Encode the function index as line number.
if (!line_key_.is_null()) { if (!line_key_.is_null()) {
......
...@@ -630,12 +630,6 @@ function CallSiteGetScriptNameOrSourceURL() { ...@@ -630,12 +630,6 @@ function CallSiteGetScriptNameOrSourceURL() {
function CallSiteGetFunctionName() { function CallSiteGetFunctionName() {
// See if the function knows its own name // See if the function knows its own name
CheckCallSite(this, "getFunctionName"); CheckCallSite(this, "getFunctionName");
if (HAS_PRIVATE(this, callSiteWasmObjectSymbol)) {
var wasm = GET_PRIVATE(this, callSiteWasmObjectSymbol);
var func_index = GET_PRIVATE(this, callSiteWasmFunctionIndexSymbol);
if (IS_UNDEFINED(wasm)) return "<WASM>";
return %WasmGetFunctionName(wasm, func_index);
}
return %CallSiteGetFunctionNameRT(this); return %CallSiteGetFunctionNameRT(this);
} }
...@@ -679,7 +673,8 @@ function CallSiteToString() { ...@@ -679,7 +673,8 @@ function CallSiteToString() {
var funName = this.getFunctionName(); var funName = this.getFunctionName();
var funcIndex = GET_PRIVATE(this, callSiteWasmFunctionIndexSymbol); var funcIndex = GET_PRIVATE(this, callSiteWasmFunctionIndexSymbol);
var pos = this.getPosition(); var pos = this.getPosition();
return funName + " (<WASM>:" + funcIndex + ":" + pos + ")"; if (IS_NULL(funName)) funName = "<WASM UNNAMED>";
return funName + " (<WASM>[" + funcIndex + "]+" + pos + ")";
} }
var fileName; var fileName;
......
...@@ -205,12 +205,13 @@ Handle<Object> CallSite::GetFileName() { ...@@ -205,12 +205,13 @@ Handle<Object> CallSite::GetFileName() {
Handle<Object> CallSite::GetFunctionName() { Handle<Object> CallSite::GetFunctionName() {
if (IsWasm()) { if (IsWasm()) {
if (wasm_obj_->IsUndefined()) return isolate_->factory()->null_value(); MaybeHandle<String> name;
// wasm_obj_ can be a String if we generate WASM code directly in a test if (!wasm_obj_->IsUndefined()) {
// case. name = wasm::GetWasmFunctionName(Handle<JSObject>::cast(wasm_obj_),
if (wasm_obj_->IsString()) return wasm_obj_; wasm_func_index_);
return wasm::GetWasmFunctionName(Handle<JSObject>::cast(wasm_obj_), }
wasm_func_index_); if (name.is_null()) return isolate_->factory()->null_value();
return name.ToHandleChecked();
} }
Handle<String> result = JSFunction::GetName(fun_); Handle<String> result = JSFunction::GetName(fun_);
if (result->length() != 0) return result; if (result->length() != 0) return result;
......
...@@ -311,15 +311,5 @@ RUNTIME_FUNCTION(Runtime_FunctionToString) { ...@@ -311,15 +311,5 @@ RUNTIME_FUNCTION(Runtime_FunctionToString) {
: *JSFunction::ToString(Handle<JSFunction>::cast(function)); : *JSFunction::ToString(Handle<JSFunction>::cast(function));
} }
RUNTIME_FUNCTION(Runtime_WasmGetFunctionName) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSObject, wasm, 0);
CONVERT_SMI_ARG_CHECKED(func_index, 1);
return *wasm::GetWasmFunctionName(wasm, func_index);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -320,7 +320,6 @@ namespace internal { ...@@ -320,7 +320,6 @@ namespace internal {
F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \ F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \
F(EnqueueMicrotask, 1, 1) \ F(EnqueueMicrotask, 1, 1) \
F(RunMicrotasks, 0, 1) \ F(RunMicrotasks, 0, 1) \
F(WasmGetFunctionName, 2, 1) \
F(OrdinaryHasInstance, 2, 1) F(OrdinaryHasInstance, 2, 1)
#define FOR_EACH_INTRINSIC_JSON(F) \ #define FOR_EACH_INTRINSIC_JSON(F) \
......
...@@ -14,10 +14,12 @@ namespace wasm { ...@@ -14,10 +14,12 @@ namespace wasm {
// module, then the first (kIntSize * (N+1)) bytes are integer entries. // module, then the first (kIntSize * (N+1)) bytes are integer entries.
// The first integer entry encodes the number of functions in the module. // The first integer entry encodes the number of functions in the module.
// The entries 1 to N contain offsets into the second part of this array. // The entries 1 to N contain offsets into the second part of this array.
// If a function is unnamed (not to be confused with an empty name), then the
// integer entry is the negative offset of the next function name.
// After these N+1 integer entries, the second part begins, which holds a // After these N+1 integer entries, the second part begins, which holds a
// concatenation of all function names. // concatenation of all function names.
// //
// Returns undefined if the array length would not fit in an integer value // Returns undefined if the array length would not fit in an integer value.
Handle<Object> BuildFunctionNamesTable(Isolate* isolate, WasmModule* module) { Handle<Object> BuildFunctionNamesTable(Isolate* isolate, WasmModule* module) {
uint64_t func_names_length = 0; uint64_t func_names_length = 0;
for (auto& func : module->functions) func_names_length += func.name_length; for (auto& func : module->functions) func_names_length += func.name_length;
...@@ -36,37 +38,35 @@ Handle<Object> BuildFunctionNamesTable(Isolate* isolate, WasmModule* module) { ...@@ -36,37 +38,35 @@ Handle<Object> BuildFunctionNamesTable(Isolate* isolate, WasmModule* module) {
int func_index = 0; int func_index = 0;
for (WasmFunction& fun : module->functions) { for (WasmFunction& fun : module->functions) {
WasmName name = module->GetNameOrNull(&fun); WasmName name = module->GetNameOrNull(&fun);
func_names_array->copy_in(current_offset, if (name.start() == nullptr) {
reinterpret_cast<const byte*>(name.start()), func_names_array->set_int(func_index + 1, -current_offset);
name.length()); } else {
func_names_array->set_int(func_index + 1, current_offset); func_names_array->copy_in(current_offset,
current_offset += name.length(); reinterpret_cast<const byte*>(name.start()),
name.length());
func_names_array->set_int(func_index + 1, current_offset);
current_offset += name.length();
}
++func_index; ++func_index;
} }
return func_names_array; return func_names_array;
} }
Handle<Object> GetWasmFunctionNameFromTable(Handle<ByteArray> func_names_array, MaybeHandle<String> GetWasmFunctionNameFromTable(
uint32_t func_index) { Handle<ByteArray> func_names_array, uint32_t func_index) {
uint32_t num_funcs = static_cast<uint32_t>(func_names_array->get_int(0)); uint32_t num_funcs = static_cast<uint32_t>(func_names_array->get_int(0));
DCHECK(static_cast<int>(num_funcs) >= 0); DCHECK(static_cast<int>(num_funcs) >= 0);
auto undefined = [&func_names_array]() -> Handle<Object> { Factory* factory = func_names_array->GetIsolate()->factory();
return func_names_array->GetIsolate()->factory()->undefined_value(); DCHECK(func_index < num_funcs);
};
if (func_index >= num_funcs) return undefined();
int offset = func_names_array->get_int(func_index + 1); int offset = func_names_array->get_int(func_index + 1);
if (offset < 0) return {};
int next_offset = func_index == num_funcs - 1 int next_offset = func_index == num_funcs - 1
? func_names_array->length() ? func_names_array->length()
: func_names_array->get_int(func_index + 2); : abs(func_names_array->get_int(func_index + 2));
ScopedVector<byte> buffer(next_offset - offset); ScopedVector<byte> buffer(next_offset - offset);
func_names_array->copy_out(offset, buffer.start(), next_offset - offset); func_names_array->copy_out(offset, buffer.start(), next_offset - offset);
if (!unibrow::Utf8::Validate(buffer.start(), buffer.length())) { if (!unibrow::Utf8::Validate(buffer.start(), buffer.length())) return {};
return undefined(); return factory->NewStringFromUtf8(Vector<const char>::cast(buffer));
}
MaybeHandle<Object> maybe_name =
func_names_array->GetIsolate()->factory()->NewStringFromUtf8(
Vector<const char>::cast(buffer));
return maybe_name.is_null() ? undefined() : maybe_name.ToHandleChecked();
} }
} // namespace wasm } // namespace wasm
......
...@@ -16,12 +16,15 @@ namespace wasm { ...@@ -16,12 +16,15 @@ namespace wasm {
struct WasmModule; struct WasmModule;
// Encode all function names of the WasmModule into one ByteArray. // Encode all function names of the WasmModule into one ByteArray.
// Returns undefined if the array length would not fit in an integer value.
Handle<Object> BuildFunctionNamesTable(Isolate* isolate, WasmModule* module); Handle<Object> BuildFunctionNamesTable(Isolate* isolate, WasmModule* module);
// Extract the function name for the given func_index from the wasm module. // Extract the function name for the given func_index from the function name
// Returns undefined if the function index is invalid. // table.
Handle<Object> GetWasmFunctionNameFromTable(Handle<ByteArray> wasm_names_table, // Returns a null handle if the respective function is unnamed (not to be
uint32_t func_index); // confused with empty names) or the function name is not a valid UTF-8 string.
MaybeHandle<String> GetWasmFunctionNameFromTable(
Handle<ByteArray> wasm_names_table, uint32_t func_index);
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
......
...@@ -332,7 +332,7 @@ static MaybeHandle<JSFunction> ReportFFIError(ErrorThrower& thrower, ...@@ -332,7 +332,7 @@ static MaybeHandle<JSFunction> ReportFFIError(ErrorThrower& thrower,
const char* error, uint32_t index, const char* error, uint32_t index,
wasm::WasmName module_name, wasm::WasmName module_name,
wasm::WasmName function_name) { wasm::WasmName function_name) {
if (function_name.start()) { if (!function_name.is_empty()) {
thrower.Error("Import #%d module=\"%.*s\" function=\"%.*s\" error: %s", thrower.Error("Import #%d module=\"%.*s\" function=\"%.*s\" error: %s",
index, module_name.length(), module_name.start(), index, module_name.length(), module_name.start(),
function_name.length(), function_name.start(), error); function_name.length(), function_name.start(), error);
...@@ -368,7 +368,7 @@ static MaybeHandle<JSFunction> LookupFunction( ...@@ -368,7 +368,7 @@ static MaybeHandle<JSFunction> LookupFunction(
} }
Handle<Object> function; Handle<Object> function;
if (function_name.start()) { if (!function_name.is_empty()) {
// Look up the function in the module. // Look up the function in the module.
Handle<String> name = factory->InternalizeUtf8String(function_name); Handle<String> name = factory->InternalizeUtf8String(function_name);
MaybeHandle<Object> result = Object::GetProperty(module, name); MaybeHandle<Object> result = Object::GetProperty(module, name);
...@@ -977,13 +977,12 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) { ...@@ -977,13 +977,12 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
return -1; return -1;
} }
Handle<Object> GetWasmFunctionName(Handle<JSObject> wasm, uint32_t func_index) { MaybeHandle<String> GetWasmFunctionName(Handle<JSObject> wasm,
Handle<Object> func_names_arr_obj = handle( uint32_t func_index) {
wasm->GetInternalField(kWasmFunctionNamesArray), wasm->GetIsolate()); Object* func_names_arr_obj = wasm->GetInternalField(kWasmFunctionNamesArray);
if (func_names_arr_obj->IsUndefined()) if (func_names_arr_obj->IsUndefined()) return Handle<String>::null();
return func_names_arr_obj; // Return undefined.
return GetWasmFunctionNameFromTable( return GetWasmFunctionNameFromTable(
Handle<ByteArray>::cast(func_names_arr_obj), func_index); handle(ByteArray::cast(func_names_arr_obj)), func_index);
} }
} // namespace wasm } // namespace wasm
......
...@@ -195,7 +195,7 @@ struct WasmModule { ...@@ -195,7 +195,7 @@ struct WasmModule {
// Get a string stored in the module bytes representing a name. // Get a string stored in the module bytes representing a name.
WasmName GetNameOrNull(uint32_t offset, uint32_t length) const { WasmName GetNameOrNull(uint32_t offset, uint32_t length) const {
if (length == 0) return {NULL, 0}; // no name. if (offset == 0 && length == 0) return {NULL, 0}; // no name.
CHECK(BoundsCheck(offset, offset + length)); CHECK(BoundsCheck(offset, offset + length));
DCHECK_GE(static_cast<int>(length), 0); DCHECK_GE(static_cast<int>(length), 0);
return {reinterpret_cast<const char*>(module_start + offset), return {reinterpret_cast<const char*>(module_start + offset),
...@@ -325,9 +325,10 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start, ...@@ -325,9 +325,10 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module); int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module);
// Extract a function name from the given wasm object. // Extract a function name from the given wasm object.
// Returns undefined if the function is unnamed or the function index is // Returns a null handle if the function is unnamed or the name is not a valid
// invalid. // UTF-8 string.
Handle<Object> GetWasmFunctionName(Handle<JSObject> wasm, uint32_t func_index); MaybeHandle<String> GetWasmFunctionName(Handle<JSObject> wasm,
uint32_t func_index);
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
......
...@@ -30,10 +30,13 @@ void testFunctionNameTable(Vector<Vector<const char>> names) { ...@@ -30,10 +30,13 @@ void testFunctionNameTable(Vector<Vector<const char>> names) {
WasmModule module; WasmModule module;
std::vector<char> all_names; std::vector<char> all_names;
// No name should have offset 0, because that encodes unnamed functions.
// In real wasm binary, offset 0 is impossible anyway.
all_names.push_back('\0');
uint32_t func_index = 0; uint32_t func_index = 0;
for (Vector<const char> name : names) { for (Vector<const char> name : names) {
size_t name_offset = all_names.size(); size_t name_offset = name.start() ? all_names.size() : 0;
all_names.insert(all_names.end(), name.start(), all_names.insert(all_names.end(), name.start(),
name.start() + name.length()); name.start() + name.length());
// Make every second function name null-terminated. // Make every second function name null-terminated.
...@@ -53,19 +56,21 @@ void testFunctionNameTable(Vector<Vector<const char>> names) { ...@@ -53,19 +56,21 @@ void testFunctionNameTable(Vector<Vector<const char>> names) {
func_index = 0; func_index = 0;
for (Vector<const char> name : names) { for (Vector<const char> name : names) {
Handle<Object> string_obj = GetWasmFunctionNameFromTable( MaybeHandle<String> string = GetWasmFunctionNameFromTable(
Handle<ByteArray>::cast(wasm_function_name_table), func_index); Handle<ByteArray>::cast(wasm_function_name_table), func_index);
CHECK(!string_obj.is_null()); if (name.start()) {
CHECK(string_obj->IsString()); CHECK(string.ToHandleChecked()->IsUtf8EqualTo(name));
Handle<String> string = Handle<String>::cast(string_obj); } else {
CHECK(string->IsUtf8EqualTo(name)); CHECK(string.is_null());
}
++func_index; ++func_index;
} }
} }
void testFunctionNameTable(Vector<const char *> names) { void testFunctionNameTable(Vector<const char *> names) {
std::vector<Vector<const char>> names_vec; std::vector<Vector<const char>> names_vec;
for (const char *name : names) names_vec.push_back(CStrVector(name)); for (const char *name : names)
names_vec.push_back(name ? CStrVector(name) : Vector<const char>());
testFunctionNameTable(Vector<Vector<const char>>( testFunctionNameTable(Vector<Vector<const char>>(
names_vec.data(), static_cast<int>(names_vec.size()))); names_vec.data(), static_cast<int>(names_vec.size())));
} }
...@@ -108,3 +113,8 @@ TEST(UTF8Names) { ...@@ -108,3 +113,8 @@ TEST(UTF8Names) {
const char *names[] = {"↱fun↰", "↺", "alpha:α beta:β"}; const char *names[] = {"↱fun↰", "↺", "alpha:α beta:β"};
testFunctionNameTable(ArrayVector(names)); testFunctionNameTable(ArrayVector(names));
} }
TEST(UnnamedVsEmptyNames) {
const char *names[] = {"", nullptr, nullptr, ""};
testFunctionNameTable(ArrayVector(names));
}
...@@ -112,11 +112,11 @@ TEST(CollectDetailedWasmStack_ExplicitThrowFromJs) { ...@@ -112,11 +112,11 @@ TEST(CollectDetailedWasmStack_ExplicitThrowFromJs) {
// Line number is 1-based, with 0 == kNoLineNumberInfo. // Line number is 1-based, with 0 == kNoLineNumberInfo.
ExceptionInfo expected_exceptions[] = { ExceptionInfo expected_exceptions[] = {
{"a", 3, 8}, // - {"a", 3, 8}, // -
{"js", 4, 2}, // - {"js", 4, 2}, // -
{"<WASM>", static_cast<int>(wasm_index), 2}, // - {"<WASM UNNAMED>", static_cast<int>(wasm_index), 2}, // -
{"<WASM>", static_cast<int>(wasm_index_2), 1}, // - {"<WASM UNNAMED>", static_cast<int>(wasm_index_2), 1}, // -
{"callFn", 1, 24} // - {"callFn", 1, 24} // -
}; };
CheckExceptionInfos(isolate, maybe_exc.ToHandleChecked(), CheckExceptionInfos(isolate, maybe_exc.ToHandleChecked(),
expected_exceptions); expected_exceptions);
...@@ -157,9 +157,9 @@ TEST(CollectDetailedWasmStack_WasmError) { ...@@ -157,9 +157,9 @@ TEST(CollectDetailedWasmStack_WasmError) {
// Line number is 1-based, with 0 == kNoLineNumberInfo. // Line number is 1-based, with 0 == kNoLineNumberInfo.
ExceptionInfo expected_exceptions[] = { ExceptionInfo expected_exceptions[] = {
{"<WASM>", static_cast<int>(wasm_index), 1}, // - {"<WASM UNNAMED>", static_cast<int>(wasm_index), 1}, // -
{"<WASM>", static_cast<int>(wasm_index_2), 1}, // - {"<WASM UNNAMED>", static_cast<int>(wasm_index_2), 1}, // -
{"callFn", 1, 24} //- {"callFn", 1, 24} //-
}; };
CheckExceptionInfos(isolate, maybe_exc.ToHandleChecked(), CheckExceptionInfos(isolate, maybe_exc.ToHandleChecked(),
expected_exceptions); expected_exceptions);
......
...@@ -89,8 +89,8 @@ TEST(Unreachable) { ...@@ -89,8 +89,8 @@ TEST(Unreachable) {
CHECK(returnObjMaybe.is_null()); CHECK(returnObjMaybe.is_null());
ExceptionInfo expected_exceptions[] = { ExceptionInfo expected_exceptions[] = {
{"<WASM>", static_cast<int>(wasm_index), 1}, // -- {"<WASM UNNAMED>", static_cast<int>(wasm_index), 1}, // --
{"callFn", 1, 24} // -- {"callFn", 1, 24} // --
}; };
CheckExceptionInfos(isolate, maybe_exc.ToHandleChecked(), CheckExceptionInfos(isolate, maybe_exc.ToHandleChecked(),
expected_exceptions); expected_exceptions);
...@@ -131,9 +131,9 @@ TEST(IllegalLoad) { ...@@ -131,9 +131,9 @@ TEST(IllegalLoad) {
// Line number is 1-based, with 0 == kNoLineNumberInfo. // Line number is 1-based, with 0 == kNoLineNumberInfo.
ExceptionInfo expected_exceptions[] = { ExceptionInfo expected_exceptions[] = {
{"<WASM>", static_cast<int>(wasm_index), 6}, // -- {"<WASM UNNAMED>", static_cast<int>(wasm_index), 6}, // --
{"<WASM>", static_cast<int>(wasm_index_2), 2}, // -- {"<WASM UNNAMED>", static_cast<int>(wasm_index_2), 2}, // --
{"callFn", 1, 24} // -- {"callFn", 1, 24} // --
}; };
CheckExceptionInfos(isolate, maybe_exc.ToHandleChecked(), CheckExceptionInfos(isolate, maybe_exc.ToHandleChecked(),
expected_exceptions); expected_exceptions);
......
// Copyright 2016 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();
var last_func_index = builder.addFunction("exec_unreachable", kSig_v_v)
.addBody([kExprUnreachable])
var illegal_func_name = [0xff];
var func_names = [ "☠", illegal_func_name, "some math: (½)² = ¼", "" ];
var expected_names = ["exec_unreachable", "☠", null,
"some math: (½)² = ¼", "", "main"];
for (var func_name of func_names) {
last_func_index = builder.addFunction(func_name, kSig_v_v)
.addBody([kExprCallFunction, kArity0, last_func_index]).index;
}
builder.addFunction("main", kSig_v_v)
.addBody([kExprCallFunction, kArity0, last_func_index])
.exportFunc();
var module = builder.instantiate();
(function testFunctionNamesAsString() {
var names = expected_names.concat(["testFunctionNamesAsString", null]);
try {
module.exports.main();
assertFalse("should throw");
} catch (e) {
var lines = e.stack.split(/\r?\n/);
lines.shift();
assertEquals(names.length, lines.length);
for (var i = 0; i < names.length; ++i) {
var line = lines[i].trim();
if (names[i] === null) continue;
var printed_name = names[i] === undefined ? "<WASM UNNAMED>" : names[i]
var expected_start = "at " + printed_name + " (";
assertTrue(line.startsWith(expected_start),
"should start with '" + expected_start + "': '" + line + "'");
}
}
})();
// For the remaining tests, collect the Callsite objects instead of just a
// string:
Error.prepareStackTrace = function(error, frames) {
return frames;
};
(function testFunctionNamesAsCallSites() {
var names = expected_names.concat(["testFunctionNamesAsCallSites", null]);
try {
module.exports.main();
assertFalse("should throw");
} catch (e) {
assertEquals(names.length, e.stack.length);
for (var i = 0; i < names.length; ++i) {
assertEquals(names[i], e.stack[i].getFunctionName());
}
}
})();
...@@ -28,7 +28,7 @@ function verifyStack(frames, expected) { ...@@ -28,7 +28,7 @@ function verifyStack(frames, expected) {
var toString; var toString;
if (exp[0]) { if (exp[0]) {
var funName = exp[1] == "?" ? "" : exp[1]; var funName = exp[1] == "?" ? "" : exp[1];
toString = funName + " (<WASM>:" + exp[2] + ":" + exp[3] + ")"; toString = funName + " (<WASM>[" + exp[2] + "]+" + exp[3] + ")";
} else { } else {
toString = exp[4] + ":" + exp[2] + ":"; toString = exp[4] + ":" + exp[2] + ":";
} }
...@@ -72,7 +72,7 @@ var module = builder.instantiate({func: STACK}); ...@@ -72,7 +72,7 @@ var module = builder.instantiate({func: STACK});
var expected_string = "Error\n" + var expected_string = "Error\n" +
// The line numbers below will change as this test gains / loses lines.. // The line numbers below will change as this test gains / loses lines..
" at STACK (stack.js:42:11)\n" + // -- " at STACK (stack.js:42:11)\n" + // --
" at main (<WASM>:0:1)\n" + // -- " at main (<WASM>[0]+1)\n" + // --
" at testSimpleStack (stack.js:79:18)\n" + // -- " at testSimpleStack (stack.js:79:18)\n" + // --
" at stack.js:81:3"; // -- " at stack.js:81:3"; // --
......
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