2016-10-13 16:17:44 +00:00
|
|
|
// 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.
|
|
|
|
|
2017-12-15 21:24:43 +00:00
|
|
|
// Flags: --expose-wasm --allow-natives-syntax
|
2016-10-13 16:17:44 +00:00
|
|
|
|
2021-06-01 12:46:36 +00:00
|
|
|
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
2016-10-13 16:17:44 +00:00
|
|
|
|
|
|
|
function builder() {
|
|
|
|
return new WasmModuleBuilder;
|
|
|
|
}
|
|
|
|
|
2017-07-24 16:20:40 +00:00
|
|
|
function assertCompileError(bytes, msg) {
|
2019-02-07 13:06:39 +00:00
|
|
|
assertThrows(
|
|
|
|
() => new WebAssembly.Module(bytes), WebAssembly.CompileError,
|
|
|
|
'WebAssembly.Module(): ' + msg);
|
|
|
|
assertThrowsAsync(
|
|
|
|
WebAssembly.compile(bytes), WebAssembly.CompileError,
|
|
|
|
'WebAssembly.compile(): ' + msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
function assertInstantiateError(error, bytes, imports = {}, msg) {
|
|
|
|
assertThrows(
|
|
|
|
() => new WebAssembly.Instance(new WebAssembly.Module(bytes), imports),
|
|
|
|
error, 'WebAssembly.Instance(): ' + msg);
|
|
|
|
assertThrowsAsync(
|
|
|
|
WebAssembly.instantiate(bytes, imports), error,
|
|
|
|
'WebAssembly.instantiate(): ' + msg);
|
2016-10-13 16:17:44 +00:00
|
|
|
}
|
|
|
|
|
2017-01-13 20:47:44 +00:00
|
|
|
// default imports to {} so we get LinkError by default, thus allowing us to
|
|
|
|
// distinguish the TypeError we want to catch
|
2017-07-24 16:20:40 +00:00
|
|
|
function assertTypeError(bytes, imports = {}, msg) {
|
2019-02-07 13:06:39 +00:00
|
|
|
assertInstantiateError(TypeError, bytes, imports, msg);
|
2016-10-13 16:17:44 +00:00
|
|
|
}
|
|
|
|
|
2017-07-24 16:20:40 +00:00
|
|
|
function assertLinkError(bytes, imports, msg) {
|
2019-02-07 13:06:39 +00:00
|
|
|
assertInstantiateError(WebAssembly.LinkError, bytes, imports, msg);
|
2016-12-16 14:23:35 +00:00
|
|
|
}
|
|
|
|
|
2017-07-24 16:20:40 +00:00
|
|
|
function assertConversionError(bytes, imports, msg) {
|
2019-02-07 13:06:39 +00:00
|
|
|
let instance =
|
|
|
|
new WebAssembly.Instance(new WebAssembly.Module(bytes), imports);
|
|
|
|
assertThrows(() => instance.exports.run(), TypeError, msg);
|
2016-10-13 16:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
(function TestDecodingError() {
|
2019-02-01 13:51:23 +00:00
|
|
|
print(arguments.callee.name);
|
2019-02-07 13:06:39 +00:00
|
|
|
assertCompileError(bytes(), 'BufferSource argument is empty');
|
|
|
|
assertCompileError(bytes('X'), 'expected 4 bytes, fell off end @+0');
|
2017-07-24 16:20:40 +00:00
|
|
|
assertCompileError(
|
2019-02-07 13:06:39 +00:00
|
|
|
bytes('\0x00asm'),
|
|
|
|
'expected magic word 00 61 73 6d, found 00 78 30 30 @+0');
|
2016-10-13 16:17:44 +00:00
|
|
|
})();
|
|
|
|
|
|
|
|
(function TestValidationError() {
|
2019-02-01 13:51:23 +00:00
|
|
|
print(arguments.callee.name);
|
2021-06-16 14:20:03 +00:00
|
|
|
let error = msg => 'Compiling function #0 failed: ' + msg;
|
2019-03-14 14:27:12 +00:00
|
|
|
let f_error = msg => 'Compiling function #0:"f" failed: ' + msg;
|
2021-06-16 14:20:03 +00:00
|
|
|
assertCompileError(
|
|
|
|
(function build() {
|
|
|
|
let b = builder();
|
|
|
|
b.addType(kSig_v_v);
|
|
|
|
// Use explicit section because the builder would automatically emit
|
|
|
|
// e.g. locals declarations.
|
|
|
|
// 1 function with type 0.
|
|
|
|
b.addExplicitSection([kFunctionSectionCode, 2, 1, 0]);
|
|
|
|
// 1 function body with length 0.
|
|
|
|
b.addExplicitSection([kCodeSectionCode, 2, 1, 0]);
|
|
|
|
return b.toBuffer();
|
|
|
|
})(),
|
|
|
|
error('expected local decls count @+22'));
|
2017-07-24 16:20:40 +00:00
|
|
|
assertCompileError(
|
2019-02-01 13:51:23 +00:00
|
|
|
builder().addFunction('f', kSig_i_v).end().toBuffer(),
|
2019-02-07 13:06:39 +00:00
|
|
|
f_error('function body must end with "end" opcode @+24'));
|
2018-12-10 15:30:48 +00:00
|
|
|
assertCompileError(
|
|
|
|
builder().addFunction('f', kSig_i_v).addBody([kExprReturn])
|
|
|
|
.end().toBuffer(),
|
2019-02-07 13:06:39 +00:00
|
|
|
f_error('expected 1 elements on the stack for return, found 0 @+24'));
|
2019-02-01 13:51:23 +00:00
|
|
|
assertCompileError(builder().addFunction('f', kSig_v_v).addBody([
|
2019-10-08 12:38:48 +00:00
|
|
|
kExprLocalGet, 0
|
2019-02-07 13:06:39 +00:00
|
|
|
]).end().toBuffer(), f_error('invalid local index: 0 @+24'));
|
2017-07-24 16:20:40 +00:00
|
|
|
assertCompileError(
|
2019-02-07 13:06:39 +00:00
|
|
|
builder().addStart(0).toBuffer(),
|
|
|
|
'start function index 0 out of bounds (0 entries) @+10');
|
2016-10-13 16:17:44 +00:00
|
|
|
})();
|
|
|
|
|
2019-02-07 13:06:39 +00:00
|
|
|
function import_error(index, module, func, msg) {
|
|
|
|
let full_msg = 'Import #' + index + ' module=\"' + module + '\"';
|
|
|
|
if (func !== undefined) full_msg += ' function=\"' + func + '\"';
|
|
|
|
return full_msg + ' error: ' + msg;
|
|
|
|
}
|
|
|
|
|
2017-04-11 20:09:20 +00:00
|
|
|
(function TestTypeError() {
|
2019-02-01 13:51:23 +00:00
|
|
|
print(arguments.callee.name);
|
2019-02-07 13:06:39 +00:00
|
|
|
let b = builder();
|
|
|
|
b.addImport('foo', 'bar', kSig_v_v);
|
|
|
|
let msg =
|
|
|
|
import_error(0, 'foo', undefined, 'module is not an object or function');
|
|
|
|
assertTypeError(b.toBuffer(), {}, msg);
|
2017-04-11 20:09:20 +00:00
|
|
|
|
|
|
|
b = builder();
|
2019-02-07 13:06:39 +00:00
|
|
|
b.addImportedGlobal('foo', 'bar', kWasmI32);
|
|
|
|
assertTypeError(b.toBuffer(), {}, msg);
|
2017-04-11 20:09:20 +00:00
|
|
|
|
|
|
|
b = builder();
|
2019-02-07 13:06:39 +00:00
|
|
|
b.addImportedMemory('foo', 'bar');
|
|
|
|
assertTypeError(b.toBuffer(), {}, msg);
|
2017-04-11 20:09:20 +00:00
|
|
|
})();
|
|
|
|
|
|
|
|
(function TestLinkingError() {
|
2019-02-01 13:51:23 +00:00
|
|
|
print(arguments.callee.name);
|
2017-04-11 20:09:20 +00:00
|
|
|
let b;
|
2019-02-07 13:06:39 +00:00
|
|
|
let msg;
|
2017-04-11 20:09:20 +00:00
|
|
|
|
2016-10-13 16:17:44 +00:00
|
|
|
b = builder();
|
2019-02-07 13:06:39 +00:00
|
|
|
msg = import_error(0, 'foo', 'bar', 'function import requires a callable');
|
|
|
|
b.addImport('foo', 'bar', kSig_v_v);
|
|
|
|
assertLinkError(b.toBuffer(), {foo: {}}, msg);
|
2016-10-13 16:17:44 +00:00
|
|
|
b = builder();
|
2019-02-07 13:06:39 +00:00
|
|
|
b.addImport('foo', 'bar', kSig_v_v);
|
|
|
|
assertLinkError(b.toBuffer(), {foo: {bar: 9}}, msg);
|
2016-10-13 16:17:44 +00:00
|
|
|
|
2016-12-16 14:23:35 +00:00
|
|
|
b = builder();
|
2019-02-07 13:06:39 +00:00
|
|
|
msg = import_error(
|
|
|
|
0, 'foo', 'bar',
|
2020-09-14 08:05:52 +00:00
|
|
|
'global import must be a number, valid Wasm reference, '
|
|
|
|
+ 'or WebAssembly.Global object');
|
2019-02-07 13:06:39 +00:00
|
|
|
b.addImportedGlobal('foo', 'bar', kWasmI32);
|
|
|
|
assertLinkError(b.toBuffer(), {foo: {}}, msg);
|
2016-12-16 14:23:35 +00:00
|
|
|
b = builder();
|
2019-02-07 13:06:39 +00:00
|
|
|
b.addImportedGlobal('foo', 'bar', kWasmI32);
|
|
|
|
assertLinkError(b.toBuffer(), {foo: {bar: ''}}, msg);
|
2016-12-16 14:23:35 +00:00
|
|
|
b = builder();
|
2019-02-07 13:06:39 +00:00
|
|
|
b.addImportedGlobal('foo', 'bar', kWasmI32);
|
|
|
|
assertLinkError(b.toBuffer(), {foo: {bar: () => 9}}, msg);
|
2016-10-13 16:17:44 +00:00
|
|
|
|
|
|
|
b = builder();
|
2019-02-07 13:06:39 +00:00
|
|
|
msg = import_error(
|
|
|
|
0, 'foo', 'bar', 'memory import must be a WebAssembly.Memory object');
|
|
|
|
b.addImportedMemory('foo', 'bar');
|
|
|
|
assertLinkError(b.toBuffer(), {foo: {}}, msg);
|
2016-12-16 14:23:35 +00:00
|
|
|
b = builder();
|
2019-02-07 13:06:39 +00:00
|
|
|
b.addImportedMemory('foo', 'bar', 1);
|
2017-07-24 16:20:40 +00:00
|
|
|
assertLinkError(
|
|
|
|
b.toBuffer(), {foo: {bar: () => new WebAssembly.Memory({initial: 0})}},
|
2019-02-07 13:06:39 +00:00
|
|
|
msg);
|
2019-02-01 13:51:23 +00:00
|
|
|
})();
|
2016-12-16 14:23:35 +00:00
|
|
|
|
2019-02-01 13:51:23 +00:00
|
|
|
(function TestTrapUnreachable() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let instance = builder().addFunction('run', kSig_v_v)
|
|
|
|
.addBody([kExprUnreachable]).exportFunc().end().instantiate();
|
|
|
|
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);
|
2016-10-13 16:17:44 +00:00
|
|
|
})();
|
|
|
|
|
2019-02-01 13:51:23 +00:00
|
|
|
(function TestUnreachableInStart() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
|
|
|
|
let b = builder().addFunction("start", kSig_v_v).addBody(
|
|
|
|
[kExprUnreachable]).end().addStart(0);
|
|
|
|
assertTraps(kTrapUnreachable, () => b.instantiate());
|
2016-10-13 16:17:44 +00:00
|
|
|
})();
|
|
|
|
|
2017-12-15 21:24:43 +00:00
|
|
|
(function InternalDebugTrace() {
|
2019-02-01 13:51:23 +00:00
|
|
|
print(arguments.callee.name);
|
2017-12-15 21:24:43 +00:00
|
|
|
var builder = new WasmModuleBuilder();
|
|
|
|
var sig = builder.addType(kSig_i_dd);
|
|
|
|
builder.addImport("mod", "func", sig);
|
|
|
|
builder.addFunction("main", sig)
|
2019-10-08 12:38:48 +00:00
|
|
|
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprCallFunction, 0])
|
2018-02-02 10:27:11 +00:00
|
|
|
.exportAs("main");
|
2017-12-15 21:24:43 +00:00
|
|
|
var main = builder.instantiate({
|
|
|
|
mod: {
|
|
|
|
func: ()=>{%DebugTrace();}
|
|
|
|
}
|
|
|
|
}).exports.main;
|
|
|
|
main();
|
|
|
|
})();
|
2019-03-14 14:27:12 +00:00
|
|
|
|
|
|
|
(function TestMultipleCorruptFunctions() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
// Generate a module with multiple corrupt functions. The error message must
|
|
|
|
// be deterministic.
|
|
|
|
var builder = new WasmModuleBuilder();
|
|
|
|
var sig = builder.addType(kSig_v_v);
|
|
|
|
for (let i = 0; i < 10; ++i) {
|
|
|
|
builder.addFunction('f' + i, sig).addBody([kExprEnd]);
|
|
|
|
}
|
|
|
|
assertCompileError(
|
|
|
|
builder.toBuffer(),
|
|
|
|
'Compiling function #0:"f0" failed: ' +
|
|
|
|
'trailing code after function end @+33');
|
|
|
|
})();
|