blob: 61a8f53a014c192f28a0c25252cf3702561e7191 [file] [log] [blame]
// META: global=jsshell
// META: script=/wasm/jsapi/wasm-constants.js
// META: script=/wasm/jsapi/wasm-module-builder.js
// META: script=/wasm/jsapi/assertions.js
function assert_exported_function(fn, { name, length }, description) {
assert_equals(Object.getPrototypeOf(fn), Function.prototype,
`${description}: prototype`);
assert_function_name(fn, name, description);
assert_function_length(fn, length, description);
}
function assert_Instance(instance, expected_exports) {
assert_equals(Object.getPrototypeOf(instance), WebAssembly.Instance.prototype,
"prototype");
assert_true(Object.isExtensible(instance), "extensible");
assert_equals(instance.exports, instance.exports, "exports should be idempotent");
const exports = instance.exports;
assert_equals(Object.getPrototypeOf(exports), null, "exports prototype");
assert_false(Object.isExtensible(exports), "extensible exports");
for (const [key, expected] of Object.entries(expected_exports)) {
const property = Object.getOwnPropertyDescriptor(exports, key);
assert_equals(typeof property, "object", `${key} should be present`);
assert_false(property.writable, `${key}: writable`);
assert_true(property.enumerable, `${key}: enumerable`);
assert_false(property.configurable, `${key}: configurable`);
const actual = property.value;
assert_true(Object.isExtensible(actual), `${key}: extensible`);
switch (expected.kind) {
case "function":
assert_exported_function(actual, expected, `value of ${key}`);
break;
case "global":
assert_equals(Object.getPrototypeOf(actual), WebAssembly.Global.prototype,
`value of ${key}: prototype`);
assert_equals(actual.value, expected.value, `value of ${key}: value`);
assert_equals(actual.valueOf(), expected.value, `value of ${key}: valueOf()`);
break;
case "memory":
assert_equals(Object.getPrototypeOf(actual), WebAssembly.Memory.prototype,
`value of ${key}: prototype`);
assert_equals(Object.getPrototypeOf(actual.buffer), ArrayBuffer.prototype,
`value of ${key}: prototype of buffer`);
assert_equals(actual.buffer.byteLength, 0x10000 * expected.size, `value of ${key}: size of buffer`);
const array = new Uint8Array(actual.buffer);
assert_equals(array[0], 0, `value of ${key}: first element of buffer`);
assert_equals(array[array.byteLength - 1], 0, `value of ${key}: last element of buffer`);
break;
case "table":
assert_equals(Object.getPrototypeOf(actual), WebAssembly.Table.prototype,
`value of ${key}: prototype`);
assert_equals(actual.length, expected.length, `value of ${key}: length of table`);
break;
}
}
}
let emptyModuleBinary;
setup(() => {
emptyModuleBinary = new WasmModuleBuilder().toBuffer();
});
test(() => {
assert_function_name(WebAssembly.Instance, "Instance", "WebAssembly.Instance");
}, "name");
test(() => {
assert_function_length(WebAssembly.Instance, 1, "WebAssembly.Instance");
}, "length");
test(() => {
assert_throws(new TypeError(), () => new WebAssembly.Instance());
}, "No arguments");
test(() => {
const invalidArguments = [
undefined,
null,
true,
"",
Symbol(),
1,
{},
WebAssembly.Module,
WebAssembly.Module.prototype,
];
for (const argument of invalidArguments) {
assert_throws(new TypeError(), () => new WebAssembly.Instance(argument),
`new Instance(${format_value(argument)})`);
}
}, "Non-Module arguments");
test(() => {
const module = new WebAssembly.Module(emptyModuleBinary);
const invalidArguments = [
null,
true,
"",
Symbol(),
1,
];
for (const argument of invalidArguments) {
assert_throws(new TypeError(), () => new WebAssembly.Instance(module, argument),
`new Instance(module, ${format_value(argument)})`);
}
}, "Non-object imports");
test(() => {
const module = new WebAssembly.Module(emptyModuleBinary);
assert_throws(new TypeError(), () => WebAssembly.Instance(module));
}, "Calling");
test(() => {
const module = new WebAssembly.Module(emptyModuleBinary);
const arguments = [
[],
[undefined],
[{}],
];
for (const value of arguments) {
const instance = new WebAssembly.Instance(module, ...arguments);
assert_Instance(instance, {});
}
}, "Empty module");
test(() => {
const builder = new WasmModuleBuilder();
builder.addImportedGlobal("module", "global1", kWasmI32);
builder.addImportedGlobal("module", "global2", kWasmI32);
const buffer = builder.toBuffer();
const module = new WebAssembly.Module(buffer);
const order = [];
const imports = {
get module() {
order.push("module getter");
return {
get global1() {
order.push("global1 getter");
return 0;
},
get global2() {
order.push("global2 getter");
return 0;
},
}
},
};
new WebAssembly.Instance(module, imports);
const expected = [
"module getter",
"global1 getter",
"module getter",
"global2 getter",
];
assert_array_equals(order, expected);
}, "getter order for imports object");
test(() => {
const builder = new WasmModuleBuilder();
builder.addImport("module", "fn", kSig_v_v);
builder.addImportedGlobal("module", "global", kWasmI32);
builder.addImportedMemory("module", "memory", 0, 128);
builder.addImportedTable("module", "table", 0, 128);
const buffer = builder.toBuffer();
const module = new WebAssembly.Module(buffer);
const instance = new WebAssembly.Instance(module, {
"module": {
"fn": function() {},
"global": 0,
"memory": new WebAssembly.Memory({ "initial": 64, maximum: 128 }),
"table": new WebAssembly.Table({ "element": "anyfunc", "initial": 64, maximum: 128 }),
},
get "module2"() {
assert_unreached("Should not get modules that are not imported");
},
});
assert_Instance(instance, {});
}, "imports");
test(() => {
const builder = new WasmModuleBuilder();
builder
.addFunction("fn", kSig_v_d)
.addBody([
kExprEnd
])
.exportFunc();
builder
.addFunction("fn2", kSig_v_v)
.addBody([
kExprEnd
])
.exportFunc();
builder.setFunctionTableLength(1);
builder.addExportOfKind("table", kExternalTable, 0);
builder.addGlobal(kWasmI32, true)
.exportAs("global")
.init = 7;
builder.addGlobal(kWasmF64, true)
.exportAs("global2")
.init = 1.2;
builder.addMemory(4, 8, true);
const buffer = builder.toBuffer()
const module = new WebAssembly.Module(buffer);
const instance = new WebAssembly.Instance(module, {});
const expected = {
"fn": { "kind": "function", "name": "0", "length": 1 },
"fn2": { "kind": "function", "name": "1", "length": 0 },
"table": { "kind": "table", "length": 1 },
"global": { "kind": "global", "value": 7 },
"global2": { "kind": "global", "value": 1.2 },
"memory": { "kind": "memory", "size": 4 },
};
assert_Instance(instance, expected);
}, "exports");