blob: 5e372105c7d1c1c165e87c6f1362440439adb63c [file] [log] [blame]
import * as assert from '../assert.js';
import * as utilities from '../utilities.js';
const version = 0x01;
const emptyModuleArray = Uint8Array.of(0x0, 0x61, 0x73, 0x6d, version, 0x00, 0x00, 0x00);
const invalidConstructorInputs = [undefined, null, "", 1, {}, []];
const invalidInstanceImports = [null, "", 1];
const checkOwnPropertyDescriptor = (obj, prop, expect) => {
const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
assert.eq(typeof descriptor.value, expect.typeofvalue);
assert.eq(descriptor.writable, expect.writable);
assert.eq(descriptor.configurable, expect.configurable);
assert.eq(descriptor.enumerable, expect.enumerable);
};
const checkAccessorOwnPropertyDescriptor = (obj, prop, expect) => {
const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
assert.eq(typeof descriptor.value, "undefined");
assert.eq(typeof descriptor.writable, "undefined");
assert.eq(descriptor.configurable, expect.configurable);
assert.eq(descriptor.enumerable, expect.enumerable);
};
const functionProperties = {
"validate": { length: 1 },
"compile": { length: 1 },
};
const constructorProperties = {
"Module": { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
"Instance": { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
"Memory": { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
"Table": { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
"CompileError": { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
"LinkError": { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
"RuntimeError": { typeofvalue: "function", writable: true, configurable: true, enumerable: false, length: 1 },
};
assert.isNotUndef(WebAssembly);
checkOwnPropertyDescriptor(utilities.global, "WebAssembly", { typeofvalue: "object", writable: true, configurable: true, enumerable: false });
assert.eq(String(WebAssembly), "[object WebAssembly]");
assert.isUndef(WebAssembly.length);
assert.eq(WebAssembly instanceof Object, true);
assert.throws(() => WebAssembly(), TypeError, `WebAssembly is not a function. (In 'WebAssembly()', 'WebAssembly' is an instance of WebAssembly)`);
assert.throws(() => new WebAssembly(), TypeError, `WebAssembly is not a constructor (evaluating 'new WebAssembly()')`);
for (const f in functionProperties) {
assert.isNotUndef(WebAssembly[f]);
assert.eq(WebAssembly[f].name, f);
assert.eq(WebAssembly[f].length, functionProperties[f].length);
}
for (const c in constructorProperties) {
assert.isNotUndef(WebAssembly[c]);
assert.eq(WebAssembly[c].name, c);
assert.eq(WebAssembly[c].length, constructorProperties[c].length);
checkOwnPropertyDescriptor(WebAssembly, c, constructorProperties[c]);
checkOwnPropertyDescriptor(WebAssembly[c], "prototype", { typeofvalue: "object", writable: false, configurable: false, enumerable: false });
if (["CompileError", "LinkError", "RuntimeError"].indexOf(c) >= 0)
WebAssembly[c](); // Per spec, the WebAssembly.*Error types match ye olden JavaScript NativeError behavior: they can be constructed without `new`.
else
assert.throws(() => WebAssembly[c](), TypeError, `calling WebAssembly.${c} constructor without new is invalid`);
switch (c) {
case "Module":
for (const invalid of invalidConstructorInputs)
assert.throws(() => new WebAssembly[c](invalid), TypeError, `first argument must be an ArrayBufferView or an ArrayBuffer (evaluating 'new WebAssembly[c](invalid)')`);
for (const buffer of [new ArrayBuffer(), new DataView(new ArrayBuffer()), new Int8Array(), new Uint8Array(), new Uint8ClampedArray(), new Int16Array(), new Uint16Array(), new Int32Array(), new Uint32Array(), new Float32Array(), new Float64Array()])
// FIXME the following should be WebAssembly.CompileError. https://bugs.webkit.org/show_bug.cgi?id=163768
assert.throws(() => new WebAssembly[c](buffer), Error, `WebAssembly.Module doesn't parse at byte 0: expected a module of at least 8 bytes (evaluating 'new WebAssembly[c](buffer)')`);
assert.instanceof(new WebAssembly[c](emptyModuleArray), WebAssembly.Module);
break;
case "Instance":
for (const invalid of invalidConstructorInputs)
assert.throws(() => new WebAssembly[c](invalid), TypeError, `first argument to WebAssembly.Instance must be a WebAssembly.Module (evaluating 'new WebAssembly[c](invalid)')`);
const instance = new WebAssembly[c](new WebAssembly.Module(emptyModuleArray));
assert.instanceof(instance, WebAssembly.Instance);
for (const invalid of invalidInstanceImports)
assert.throws(() => new WebAssembly[c](new WebAssembly.Module(emptyModuleArray), invalid), TypeError, `second argument to WebAssembly.Instance must be undefined or an Object (evaluating 'new WebAssembly[c](new WebAssembly.Module(emptyModuleArray), invalid)')`);
assert.isNotUndef(instance.exports);
checkAccessorOwnPropertyDescriptor(WebAssembly.Instance.prototype, "exports", { configurable: true, enumerable: true });
assert.throws(() => WebAssembly.Instance.prototype.exports = undefined, TypeError, `Attempted to assign to readonly property.`);
assert.throws(() => WebAssembly.Instance.prototype.exports, TypeError, `expected |this| value to be an instance of WebAssembly.Instance`);
assert.isUndef(instance.exports.__proto__);
assert.eq(Reflect.isExtensible(instance.exports), false);
assert.eq(Symbol.iterator in instance.exports, false);
assert.eq(Symbol.toStringTag in instance.exports, true);
assert.eq(Object.getOwnPropertySymbols(instance.exports).length, 1);
assert.eq(Object.getOwnPropertySymbols(instance.exports)[0], Symbol.toStringTag);
assert.throws(() => instance.exports[Symbol.toStringTag] = 42, TypeError, `Attempted to assign to readonly property.`);
break;
case "Memory":
new WebAssembly.Memory({initial: 20});
break;
case "Table":
new WebAssembly.Table({initial: 20, element: "funcref"});
new WebAssembly.Table({initial: 20, maximum: 20, element: "funcref"});
new WebAssembly.Table({initial: 20, maximum: 25, element: "funcref"});
break;
case "CompileError":
case "LinkError":
case "RuntimeError": {
{
const e = new WebAssembly[c];
assert.eq(e instanceof WebAssembly[c], true);
assert.eq(e instanceof Error, true);
assert.eq(e instanceof TypeError, false);
assert.eq(e.message, "");
assert.eq(typeof e.stack, "string");
const sillyString = "uh-oh!";
const e2 = new WebAssembly[c](sillyString);
assert.eq(e2.message, sillyString + " (evaluating 'new WebAssembly[c](sillyString)')");
}
{
const e = WebAssembly[c]();
assert.eq(e instanceof WebAssembly[c], true);
assert.eq(e instanceof Error, true);
assert.eq(e instanceof TypeError, false);
assert.eq(e.message, "");
assert.eq(typeof e.stack, "string");
const sillyString = "uh-oh!";
const e2 = WebAssembly[c](sillyString);
assert.eq(e2.message, sillyString);
}
} break;
default: throw new Error(`Implementation error: unexpected constructor property "${c}"`);
}
}