Commit 327fd140 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Revise compile error messages

This CL revises some of our error messages, and removes unneeded parts
(like "AsyncCompilation: " or "(null): "). It also extends existing
tests to check for the precise error message more thoroughly to detect
changes or nondeterminism earlier.

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

Cq-Include-Trybots: luci.chromium.try:linux-blink-rel
Bug: chromium:926311
Change-Id: I1ccfb307d4a61291f4582330152a53fbadd0848f
Reviewed-on: https://chromium-review.googlesource.com/c/1445897
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59296}
parent 06ba822e
...@@ -1063,10 +1063,9 @@ void AsyncCompileJob::FinishCompile() { ...@@ -1063,10 +1063,9 @@ void AsyncCompileJob::FinishCompile() {
FinishModule(); FinishModule();
} }
void AsyncCompileJob::AsyncCompileFailed(const char* context, void AsyncCompileJob::AsyncCompileFailed(const WasmError& error) {
const WasmError& error) { ErrorThrower thrower(isolate_, "WebAssembly.compile()");
ErrorThrower thrower(isolate_, "AsyncCompile"); thrower.CompileFailed(error);
thrower.CompileFailed(context, error);
// {job} keeps the {this} pointer alive. // {job} keeps the {this} pointer alive.
std::shared_ptr<AsyncCompileJob> job = std::shared_ptr<AsyncCompileJob> job =
isolate_->wasm_engine()->RemoveCompileJob(this); isolate_->wasm_engine()->RemoveCompileJob(this);
...@@ -1117,7 +1116,7 @@ class AsyncCompileJob::CompilationStateCallback { ...@@ -1117,7 +1116,7 @@ class AsyncCompileJob::CompilationStateCallback {
job->isolate_->set_context(*job->native_context_); job->isolate_->set_context(*job->native_context_);
WasmError error = Impl(job->native_module_->compilation_state()) WasmError error = Impl(job->native_module_->compilation_state())
->GetCompileError(); ->GetCompileError();
return job->AsyncCompileFailed("Async compilation failed", error); return job->AsyncCompileFailed(error);
})); }));
break; break;
...@@ -1308,7 +1307,7 @@ class AsyncCompileJob::DecodeFail : public CompileStep { ...@@ -1308,7 +1307,7 @@ class AsyncCompileJob::DecodeFail : public CompileStep {
void RunInForeground(AsyncCompileJob* job) override { void RunInForeground(AsyncCompileJob* job) override {
TRACE_COMPILE("(1b) Decoding failed.\n"); TRACE_COMPILE("(1b) Decoding failed.\n");
// {job_} is deleted in AsyncCompileFailed, therefore the {return}. // {job_} is deleted in AsyncCompileFailed, therefore the {return}.
return job->AsyncCompileFailed("Wasm decoding failed", error_); return job->AsyncCompileFailed(error_);
} }
}; };
......
...@@ -107,7 +107,7 @@ class AsyncCompileJob { ...@@ -107,7 +107,7 @@ class AsyncCompileJob {
void FinishCompile(); void FinishCompile();
void AsyncCompileFailed(const char* context, const WasmError&); void AsyncCompileFailed(const WasmError&);
void AsyncCompileSucceeded(Handle<WasmModuleObject> result); void AsyncCompileSucceeded(Handle<WasmModuleObject> result);
......
...@@ -160,7 +160,7 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile( ...@@ -160,7 +160,7 @@ MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
DecodeWasmModule(enabled, bytes.start(), bytes.end(), false, kWasmOrigin, DecodeWasmModule(enabled, bytes.start(), bytes.end(), false, kWasmOrigin,
isolate->counters(), allocator()); isolate->counters(), allocator());
if (result.failed()) { if (result.failed()) {
thrower->CompileFailed("Wasm decoding failed", result.error()); thrower->CompileFailed(result.error());
return {}; return {};
} }
......
...@@ -122,12 +122,6 @@ class V8_EXPORT_PRIVATE ErrorThrower { ...@@ -122,12 +122,6 @@ class V8_EXPORT_PRIVATE ErrorThrower {
PRINTF_FORMAT(2, 3) void LinkError(const char* fmt, ...); PRINTF_FORMAT(2, 3) void LinkError(const char* fmt, ...);
PRINTF_FORMAT(2, 3) void RuntimeError(const char* fmt, ...); PRINTF_FORMAT(2, 3) void RuntimeError(const char* fmt, ...);
void CompileFailed(const char* context, const WasmError& error) {
DCHECK(error.has_error());
CompileError("%s: %s @+%u", context, error.message().c_str(),
error.offset());
}
void CompileFailed(const WasmError& error) { void CompileFailed(const WasmError& error) {
DCHECK(error.has_error()); DCHECK(error.has_error());
CompileError("%s @+%u", error.message().c_str(), error.offset()); CompileError("%s @+%u", error.message().c_str(), error.offset());
......
...@@ -584,13 +584,15 @@ var prettyPrinted; ...@@ -584,13 +584,15 @@ var prettyPrinted;
} }
assertPromiseResult = function(promise, success, fail) { assertPromiseResult = function(promise, success, fail) {
if (success !== undefined) assertEquals('function', typeof success);
if (fail !== undefined) assertEquals('function', typeof fail);
const stack = (new Error()).stack; const stack = (new Error()).stack;
var test_promise = promise.then( var test_promise = promise.then(
result => { result => {
try { try {
if (--promiseTestCount == 0) testRunner.notifyDone(); if (--promiseTestCount == 0) testRunner.notifyDone();
if (success) success(result); if (success !== undefined) success(result);
} catch (e) { } catch (e) {
// Use setTimeout to throw the error again to get out of the promise // Use setTimeout to throw the error again to get out of the promise
// chain. // chain.
...@@ -602,7 +604,7 @@ var prettyPrinted; ...@@ -602,7 +604,7 @@ var prettyPrinted;
result => { result => {
try { try {
if (--promiseTestCount == 0) testRunner.notifyDone(); if (--promiseTestCount == 0) testRunner.notifyDone();
if (!fail) throw result; if (fail === undefined) throw result;
fail(result); fail(result);
} catch (e) { } catch (e) {
// Use setTimeout to throw the error again to get out of the promise // Use setTimeout to throw the error again to get out of the promise
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --expose-wasm --allow-natives-syntax
load("test/mjsunit/wasm/wasm-module-builder.js"); load("test/mjsunit/wasm/wasm-module-builder.js");
async function assertCompiles(buffer) { async function assertCompiles(buffer) {
...@@ -11,13 +9,15 @@ async function assertCompiles(buffer) { ...@@ -11,13 +9,15 @@ async function assertCompiles(buffer) {
assertInstanceof(module, WebAssembly.Module); assertInstanceof(module, WebAssembly.Module);
} }
async function assertCompileError(buffer) { function assertCompileError(buffer, msg) {
try { assertEquals('string', typeof msg);
await WebAssembly.compile(buffer); msg = 'WebAssembly.compile(): ' + msg;
assertUnreachable(); function checkException(e) {
} catch (e) {
if (!(e instanceof WebAssembly.CompileError)) throw e; if (!(e instanceof WebAssembly.CompileError)) throw e;
assertEquals(msg, e.message, 'Error message');
} }
return assertPromiseResult(
WebAssembly.compile(buffer), assertUnreachable, checkException);
} }
assertPromiseResult(async function basicCompile() { assertPromiseResult(async function basicCompile() {
...@@ -49,7 +49,7 @@ assertPromiseResult(async function basicCompile() { ...@@ -49,7 +49,7 @@ assertPromiseResult(async function basicCompile() {
// Three compilations of the bad module should fail. // Three compilations of the bad module should fail.
for (var i = 0; i < kNumCompiles; i++) { for (var i = 0; i < kNumCompiles; i++) {
await assertCompileError(bad_buffer); await assertCompileError(bad_buffer, 'BufferSource argument is empty');
} }
}()); }());
...@@ -68,7 +68,10 @@ assertPromiseResult(async function badFunctionInTheMiddle() { ...@@ -68,7 +68,10 @@ assertPromiseResult(async function badFunctionInTheMiddle() {
builder.addFunction('b' + i, sig).addBody([kExprI32Const, 42]); builder.addFunction('b' + i, sig).addBody([kExprI32Const, 42]);
} }
let buffer = builder.toBuffer(); let buffer = builder.toBuffer();
await assertCompileError(buffer); await assertCompileError(
buffer,
'Compiling wasm function \"bad\" failed: ' +
'expected 1 elements on the stack for fallthru to @1, found 0 @+94');
}()); }());
assertPromiseResult(async function importWithoutCode() { assertPromiseResult(async function importWithoutCode() {
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
// Flags: --expose-wasm --allow-natives-syntax // Flags: --expose-wasm --allow-natives-syntax
'use strict';
load("test/mjsunit/wasm/wasm-module-builder.js"); load("test/mjsunit/wasm/wasm-module-builder.js");
function module(bytes) { function module(bytes) {
...@@ -36,6 +34,7 @@ function builder() { ...@@ -36,6 +34,7 @@ function builder() {
} }
function assertCompileError(bytes, msg) { function assertCompileError(bytes, msg) {
if (typeof msg === 'string') msg = 'WebAssembly.Module(): ' + msg;
assertThrows(() => module(bytes), WebAssembly.CompileError, msg); assertThrows(() => module(bytes), WebAssembly.CompileError, msg);
} }
...@@ -49,18 +48,13 @@ function assertLinkError(bytes, imports, msg) { ...@@ -49,18 +48,13 @@ function assertLinkError(bytes, imports, msg) {
assertThrows(() => instance(bytes, imports), WebAssembly.LinkError, msg); assertThrows(() => instance(bytes, imports), WebAssembly.LinkError, msg);
} }
function assertRuntimeError(bytes, imports, msg) {
assertThrows(
() => instantiateAndFailAtRuntime(bytes, imports),
WebAssembly.RuntimeError, msg);
}
function assertConversionError(bytes, imports, msg) { function assertConversionError(bytes, imports, msg) {
assertThrows( assertThrows(
() => instantiateAndFailAtRuntime(bytes, imports), TypeError, msg); () => instantiateAndFailAtRuntime(bytes, imports), TypeError, msg);
} }
(function TestDecodingError() { (function TestDecodingError() {
print(arguments.callee.name);
assertCompileError("", /is empty/); assertCompileError("", /is empty/);
assertCompileError("X", /expected 4 bytes, fell off end @\+0/); assertCompileError("X", /expected 4 bytes, fell off end @\+0/);
assertCompileError( assertCompileError(
...@@ -68,14 +62,16 @@ function assertConversionError(bytes, imports, msg) { ...@@ -68,14 +62,16 @@ function assertConversionError(bytes, imports, msg) {
})(); })();
(function TestValidationError() { (function TestValidationError() {
print(arguments.callee.name);
assertCompileError( assertCompileError(
builder().addFunction("f", kSig_i_v).end().toBuffer(), builder().addFunction('f', kSig_i_v).end().toBuffer(),
/function body must end with "end" opcode @/); 'Compiling wasm function "f" failed: ' +
'function body must end with "end" opcode @+24');
assertCompileError( assertCompileError(
builder().addFunction('f', kSig_i_v).addBody([kExprReturn]) builder().addFunction('f', kSig_i_v).addBody([kExprReturn])
.end().toBuffer(), .end().toBuffer(),
/expected 1 elements on the stack for return, found 0 @/); /expected 1 elements on the stack for return, found 0 @/);
assertCompileError(builder().addFunction("f", kSig_v_v).addBody([ assertCompileError(builder().addFunction('f', kSig_v_v).addBody([
kExprGetLocal, 0 kExprGetLocal, 0
]).end().toBuffer(), /invalid local index: 0 @/); ]).end().toBuffer(), /invalid local index: 0 @/);
assertCompileError( assertCompileError(
...@@ -83,6 +79,7 @@ function assertConversionError(bytes, imports, msg) { ...@@ -83,6 +79,7 @@ function assertConversionError(bytes, imports, msg) {
})(); })();
(function TestTypeError() { (function TestTypeError() {
print(arguments.callee.name);
let b; let b;
b = builder(); b = builder();
b.addImport("foo", "bar", kSig_v_v); b.addImport("foo", "bar", kSig_v_v);
...@@ -98,6 +95,7 @@ function assertConversionError(bytes, imports, msg) { ...@@ -98,6 +95,7 @@ function assertConversionError(bytes, imports, msg) {
})(); })();
(function TestLinkingError() { (function TestLinkingError() {
print(arguments.callee.name);
let b; let b;
b = builder(); b = builder();
...@@ -131,34 +129,33 @@ function assertConversionError(bytes, imports, msg) { ...@@ -131,34 +129,33 @@ function assertConversionError(bytes, imports, msg) {
assertLinkError( assertLinkError(
b.toBuffer(), {foo: {bar: () => new WebAssembly.Memory({initial: 0})}}, b.toBuffer(), {foo: {bar: () => new WebAssembly.Memory({initial: 0})}},
/memory import must be a WebAssembly\.Memory object/); /memory import must be a WebAssembly\.Memory object/);
})();
b = builder(); (function TestTrapUnreachable() {
b.addFunction("startup", kSig_v_v).addBody([ print(arguments.callee.name);
kExprUnreachable, let instance = builder().addFunction('run', kSig_v_v)
]).end().addStart(0); .addBody([kExprUnreachable]).exportFunc().end().instantiate();
assertRuntimeError(b.toBuffer(), {}, "unreachable"); assertTraps(kTrapUnreachable, instance.exports.run);
})();
(function TestTrapDivByZero() {
print(arguments.callee.name);
let instance = builder().addFunction('run', kSig_v_v).addBody(
[kExprI32Const, 1, kExprI32Const, 0, kExprI32DivS, kExprDrop])
.exportFunc().end().instantiate();
assertTraps(kTrapDivByZero, instance.exports.run);
})(); })();
(function TestTrapError() { (function TestUnreachableInStart() {
assertRuntimeError(builder().addFunction("run", kSig_v_v).addBody([ print(arguments.callee.name);
kExprUnreachable
]).exportFunc().end().toBuffer(), {}, "unreachable"); let b = builder().addFunction("start", kSig_v_v).addBody(
[kExprUnreachable]).end().addStart(0);
assertRuntimeError(builder().addFunction("run", kSig_v_v).addBody([ assertTraps(kTrapUnreachable, () => b.instantiate());
kExprI32Const, 1,
kExprI32Const, 0,
kExprI32DivS,
kExprDrop
]).exportFunc().end().toBuffer(), {}, "divide by zero");
assertRuntimeError(builder().
addFunction("run", kSig_v_v).addBody([]).exportFunc().end().
addFunction("start", kSig_v_v).addBody([kExprUnreachable]).end().
addStart(1).toBuffer(),
{}, "unreachable");
})(); })();
(function TestConversionError() { (function TestConversionError() {
print(arguments.callee.name);
let b = builder(); let b = builder();
b.addImport('foo', 'bar', kSig_v_l); b.addImport('foo', 'bar', kSig_v_l);
let buffer = b.addFunction('run', kSig_v_v) let buffer = b.addFunction('run', kSig_v_v)
...@@ -180,6 +177,7 @@ function assertConversionError(bytes, imports, msg) { ...@@ -180,6 +177,7 @@ function assertConversionError(bytes, imports, msg) {
(function InternalDebugTrace() { (function InternalDebugTrace() {
print(arguments.callee.name);
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
var sig = builder.addType(kSig_i_dd); var sig = builder.addType(kSig_i_dd);
builder.addImport("mod", "func", sig); builder.addImport("mod", "func", sig);
......
...@@ -43,7 +43,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -43,7 +43,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
builder.addExportOfKind("ex_oob", kExternalException, except + 1); builder.addExportOfKind("ex_oob", kExternalException, except + 1);
assertThrows( assertThrows(
() => builder.instantiate(), WebAssembly.CompileError, () => builder.instantiate(), WebAssembly.CompileError,
/Wasm decoding failed: exception index 1 out of bounds/); 'WebAssembly.Module(): exception index 1 out of bounds (1 entry) @+30');
})(); })();
(function TestExportSameNameTwice() { (function TestExportSameNameTwice() {
...@@ -54,7 +54,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -54,7 +54,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
builder.addExportOfKind("ex", kExternalException, except); builder.addExportOfKind("ex", kExternalException, except);
assertThrows( assertThrows(
() => builder.instantiate(), WebAssembly.CompileError, () => builder.instantiate(), WebAssembly.CompileError,
/Duplicate export name 'ex' for exception 0 and exception 0/); 'WebAssembly.Module(): Duplicate export name \'ex\' ' +
'for exception 0 and exception 0 @+28');
})(); })();
(function TestExportModuleGetExports() { (function TestExportModuleGetExports() {
......
...@@ -45,7 +45,7 @@ assertThrows(() => {instantiate(kSig_i_v, [kExprI32Const, 0]);}); ...@@ -45,7 +45,7 @@ assertThrows(() => {instantiate(kSig_i_v, [kExprI32Const, 0]);});
assertThrows( assertThrows(
() => builder.instantiate(), WebAssembly.CompileError, () => builder.instantiate(), WebAssembly.CompileError,
'WebAssembly.Module(): Wasm decoding failed: ' + 'WebAssembly.Module(): ' +
'start function index 1 out of bounds (1 entry) @+20'); 'start function index 1 out of bounds (1 entry) @+20');
})(); })();
...@@ -62,8 +62,7 @@ assertThrows(() => {instantiate(kSig_i_v, [kExprI32Const, 0]);}); ...@@ -62,8 +62,7 @@ assertThrows(() => {instantiate(kSig_i_v, [kExprI32Const, 0]);});
assertThrows( assertThrows(
() => builder.instantiate(), WebAssembly.CompileError, () => builder.instantiate(), WebAssembly.CompileError,
'WebAssembly.Module(): Wasm decoding failed: ' + 'WebAssembly.Module(): unexpected section <Start> @+27');
'unexpected section <Start> @+27');
})(); })();
......
...@@ -484,19 +484,7 @@ let kTrapMsgs = [ ...@@ -484,19 +484,7 @@ let kTrapMsgs = [
]; ];
function assertTraps(trap, code) { function assertTraps(trap, code) {
try { assertThrows(code, WebAssembly.RuntimeError, kTrapMsgs[trap]);
if (typeof code === 'function') {
code();
} else {
eval(code);
}
} catch (e) {
assertEquals('object', typeof e);
assertEquals(kTrapMsgs[trap], e.message);
// Success.
return;
}
throw new MjsUnitAssertionError('Did not trap, expected: ' + kTrapMsgs[trap]);
} }
class Binary extends Array { class Binary extends Array {
......
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