blob: d4986bb6c856b38d940dd50a4e51bd9ab2c3207e [file] [edit]
import * as assert from "../assert.js";
import { compile, instantiate } from "./wast-wrapper.js";
function testValidation() {
assert.throws(
() => compile(`
(module
(func (export "f") (result (ref any))
(ref.cast (ref 256) (ref.null none))))
`),
WebAssembly.CompileError,
"WebAssembly.Module doesn't parse at byte 7: can't get heap type for ref.cast, in function at index 0"
);
compile(`
(module
(func (export "f") (result (ref any))
(ref.cast (ref any) (ref.null none))))
`);
}
function testBasicCasts() {
instantiate(`
(module
(func (export "f") (result (ref null extern))
(ref.cast externref (ref.null extern))))
`).exports.f();
assert.eq(
instantiate(`
(module
(func (export "f") (result i32)
(ref.test externref (ref.null extern))))
`).exports.f(),
1
);
instantiate(`
(module
(func (export "f") (result (ref null func))
(ref.cast funcref (ref.null func))))
`).exports.f();
assert.eq(
instantiate(`
(module
(func (export "f") (result i32)
(ref.test funcref (ref.null func))))
`).exports.f(),
1
);
instantiate(`
(module
(type (array i32))
(start 0)
(func (export "f")
(ref.cast (ref null 0) (ref.null 0))
drop))
`).exports.f();
assert.eq(
instantiate(`
(module
(type (array i32))
(func (export "f") (result i32)
(ref.test (ref null 0) (ref.null 0))))
`).exports.f(),
1
);
assert.throws(
() => instantiate(`
(module
(func (export "f") (result (ref null extern))
(ref.cast (ref extern) (ref.null extern))))
`).exports.f(),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(func (export "f") (result i32)
(ref.test (ref extern) (ref.null extern))))
`).exports.f(),
0
);
}
function testI31Casts() {
instantiate(`
(module
(start 1)
(func (result i31ref)
(ref.cast (ref i31) (ref.i31 (i32.const 42))))
(func (call 0) drop))
`);
assert.eq(
instantiate(`
(module
(func (export "f") (result i32)
(ref.test (ref i31) (ref.i31 (i32.const 42)))))
`).exports.f(),
1
)
assert.throws(
() => instantiate(`
(module
(type (array i32))
(start 0)
(func
(ref.cast (ref i31) (array.new 0 (i32.const 42) (i32.const 5)))
drop))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(type (array i32))
(func (export "f") (result i32)
(ref.test (ref i31) (array.new 0 (i32.const 42) (i32.const 5)))))
`).exports.f(),
0
);
}
function testFunctionCasts() {
instantiate(`
(module
(type (func (param) (result i32)))
(elem declare funcref (ref.func 0))
(start 2)
(func (type 0) (i32.const 42))
(func (result funcref)
(ref.cast (ref func) (ref.func 0)))
(func (call 1) drop))
`);
assert.eq(
instantiate(`
(module
(type (func (param) (result i32)))
(elem declare funcref (ref.func 0))
(func (type 0) (i32.const 42))
(func (export "f") (result i32)
(ref.test (ref func) (ref.func 0))))
`).exports.f(),
1
)
instantiate(`
(module
(type (func (param) (result i32)))
(elem declare funcref (ref.func 0))
(start 2)
(func (type 0) (i32.const 42))
(func (param funcref)
(ref.cast (ref 0) (local.get 0))
drop)
(func (call 1 (ref.func 0))))
`);
assert.eq(
instantiate(`
(module
(type (func (param) (result i32)))
(elem declare funcref (ref.func 0))
(func (type 0) (i32.const 42))
(func (param funcref) (result i32)
(ref.test (ref 0) (local.get 0)))
(func (export "f") (result i32)
(call 1 (ref.func 0))))
`).exports.f(),
1
)
// Casts should work after properties are added to exported functions.
{
let f = instantiate(`
(module
(type (func (param) (result i32)))
(elem declare funcref (ref.func 0))
(func (export "f") (type 0) (i32.const 42)))
`).exports.f;
f.x = 3;
Object.seal(f); // Sealing transition shouldn't disrupt cast.
instantiate(`
(module
(type (func (param) (result i32)))
(func (export "g") (param funcref) (result i32)
(call_ref 0 (ref.cast (ref 0) (local.get 0)))))
`).exports.g(f);
assert.eq(
instantiate(`
(module
(type (func (param) (result i32)))
(func (export "g") (param funcref) (result i32)
(ref.test (ref 0) (local.get 0))))
`).exports.g(f),
1
)
}
assert.throws(
() => instantiate(`
(module
(start 0)
(func
(ref.cast (ref func) (ref.i31 (i32.const 42)))
drop))
`),
WebAssembly.CompileError,
"WebAssembly.Module doesn't validate: ref.cast to type (ref i31) expected a funcref"
);
assert.throws(
() => instantiate(`
(module
(func (export "f") (result i32)
(ref.test (ref func) (ref.i31 (i32.const 42)))))
`),
WebAssembly.CompileError,
"WebAssembly.Module doesn't validate: ref.test to type (ref i31) expected a funcref"
);
assert.throws(
() => instantiate(`
(module
(type (func (param) (result i32)))
(type (func (param) (result f32)))
(elem declare funcref (ref.func 0))
(start 2)
(func (type 1) (f32.const 42))
(func (param funcref)
(ref.cast (ref 0) (local.get 0))
drop)
(func (call 1 (ref.func 0))))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(type (func (param) (result i32)))
(type (func (param) (result f32)))
(elem declare funcref (ref.func 0))
(func (type 1) (f32.const 42))
(func (param funcref) (result i32)
(ref.test (ref 0) (local.get 0)))
(func (export "f") (result i32)
(call 1 (ref.func 0))))
`).exports.f(),
0
);
assert.throws(
() => instantiate(`
(module
(type (func (param) (result i32)))
(type (func (param) (result f32)))
(elem declare funcref (ref.func 0))
(start 1)
(func (type 0) (i32.const 42))
(func
(ref.cast (ref 1) (ref.func 0))
drop))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(type (func (param) (result i32)))
(type (func (param) (result f32)))
(elem declare funcref (ref.func 0))
(func (type 0) (i32.const 42))
(func (export "f") (result i32)
(ref.test (ref 1) (ref.func 0))))
`).exports.f(),
0
);
}
function testArrayCasts() {
instantiate(`
(module
(type (array i32))
(start 1)
(func (result arrayref)
(ref.cast (ref array) (array.new 0 (i32.const 42) (i32.const 5))))
(func (call 0) drop))
`);
assert.eq(
instantiate(`
(module
(type (array i32))
(func (export "f") (result i32)
(ref.test (ref array) (array.new 0 (i32.const 42) (i32.const 5)))))
`).exports.f(),
1
)
instantiate(`
(module
(type (array i32))
(start 1)
(func (param arrayref)
(ref.cast (ref 0) (local.get 0))
drop)
(func (call 0 (array.new 0 (i32.const 42) (i32.const 5)))))
`);
assert.eq(
instantiate(`
(module
(type (array i32))
(func (param arrayref) (result i32)
(ref.test (ref 0) (local.get 0)))
(func (export "f") (result i32)
(call 0 (array.new 0 (i32.const 42) (i32.const 5)))))
`).exports.f(),
1
)
assert.throws(
() => instantiate(`
(module
(start 0)
(func
(ref.cast (ref array) (ref.i31 (i32.const 42)))
drop))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(func (export "f") (result i32)
(ref.test (ref array) (ref.i31 (i32.const 42)))))
`).exports.f(),
0
);
assert.throws(
() => instantiate(`
(module
(type (array i32))
(type (array f32))
(start 1)
(func (param arrayref)
(ref.cast (ref 0) (local.get 0))
drop)
(func (call 0 (array.new 1 (f32.const 42.2) (i32.const 5)))))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(type (array i32))
(type (array f32))
(func (param arrayref) (result i32)
(ref.test (ref 0) (local.get 0)))
(func (export "f") (result i32)
(call 0 (array.new 1 (f32.const 42.2) (i32.const 5)))))
`).exports.f(),
0
);
assert.throws(
() => instantiate(`
(module
(type (array i32))
(type (array f32))
(start 0)
(func
(ref.cast (ref 1) (array.new 0 (i32.const 42) (i32.const 5)))
drop))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(type (array i32))
(type (array f32))
(func (export "f") (result i32)
(ref.test (ref 1) (array.new 0 (i32.const 42) (i32.const 5)))))
`).exports.f(),
0
);
}
function testStructCasts() {
instantiate(`
(module
(type (struct (field i32)))
(start 1)
(func (result structref)
(ref.cast (ref struct) (struct.new 0 (i32.const 42))))
(func (call 0) drop))
`);
assert.eq(
instantiate(`
(module
(type (struct (field i32)))
(func (export "f") (result i32)
(ref.test (ref struct) (struct.new 0 (i32.const 42)))))
`).exports.f(),
1
)
instantiate(`
(module
(type (struct (field i32)))
(start 1)
(func (param structref)
(ref.cast (ref 0) (local.get 0))
drop)
(func (call 0 (struct.new 0 (i32.const 42)))))
`);
assert.eq(
instantiate(`
(module
(type (struct (field i32)))
(func (param structref) (result i32)
(ref.test (ref 0) (local.get 0)))
(func (export "f") (result i32)
(call 0 (struct.new 0 (i32.const 42)))))
`).exports.f(),
1
)
assert.throws(
() => instantiate(`
(module
(start 0)
(func
(ref.cast (ref struct) (ref.i31 (i32.const 42)))
drop))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(func (export "f") (result i32)
(ref.test (ref struct) (ref.i31 (i32.const 42)))))
`).exports.f(),
0
);
assert.throws(
() => instantiate(`
(module
(type (struct (field i32)))
(type (struct (field f32)))
(start 1)
(func (param structref)
(ref.cast (ref 0) (local.get 0))
drop)
(func (call 0 (struct.new 1 (f32.const 42.2)))))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(type (struct (field i32)))
(type (struct (field f32)))
(func (param structref) (result i32)
(ref.test (ref 0) (local.get 0)))
(func (export "f") (result i32)
(call 0 (struct.new 1 (f32.const 42.2)))))
`).exports.f(),
0
);
assert.throws(
() => instantiate(`
(module
(type (struct (field i32)))
(type (struct (field f32)))
(start 0)
(func
(ref.cast (ref 1) (struct.new 0 (i32.const 42)))
drop))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(type (struct (field i32)))
(type (struct (field f32)))
(func (export "f") (result i32)
(ref.test (ref 1) (struct.new 0 (i32.const 42)))))
`).exports.f(),
0
);
}
function testSubtypeCasts() {
instantiate(`
(module
(type (sub (array i32)))
(type (sub 0 (array i32)))
(start 1)
(func (param arrayref)
(ref.cast (ref 0) (local.get 0))
drop)
(func (call 0 (array.new 1 (i32.const 42) (i32.const 5)))))
`);
assert.eq(
instantiate(`
(module
(type (sub (array i32)))
(type (sub 0 (array i32)))
(func (param arrayref) (result i32)
(ref.test (ref 0) (local.get 0)))
(func (export "f") (result i32)
(call 0 (array.new 1 (i32.const 42) (i32.const 5)))))
`).exports.f(),
1
);
instantiate(`
(module
(type (sub (struct (field i32))))
(type (sub 0 (struct (field i32) (field i64))))
(start 1)
(func (param structref)
(ref.cast (ref 0) (local.get 0))
drop)
(func (call 0 (struct.new 1 (i32.const 42) (i64.const 43)))))
`);
assert.eq(
instantiate(`
(module
(type (sub (struct (field i32))))
(type (sub 0 (struct (field i32) (field i64))))
(func (param structref) (result i32)
(ref.test (ref 0) (local.get 0)))
(func (export "f") (result i32)
(call 0 (struct.new 1 (i32.const 42) (i64.const 43)))))
`).exports.f(),
1
);
instantiate(`
(module
(type (sub (func (result i32))))
(type (sub 0 (func (result i32))))
(elem declare funcref (ref.func 0))
(start 2)
(func (type 1) (i32.const 42))
(func (param funcref)
(ref.cast (ref 0) (local.get 0))
drop)
(func (call 1 (ref.func 0))))
`);
assert.eq(
instantiate(`
(module
(type (sub (func (result i32))))
(type (sub 0 (func (result i32))))
(elem declare funcref (ref.func 0))
(func (type 1) (i32.const 42))
(func (param funcref) (result i32)
(ref.test (ref 0) (local.get 0)))
(func (export "f") (result i32)
(call 1 (ref.func 0))))
`).exports.f(),
1
);
assert.throws(
() => instantiate(`
(module
(type (sub (array i32)))
(type (sub 0 (array i32)))
(start 1)
(func (param arrayref)
(ref.cast (ref 1) (local.get 0))
drop)
(func (call 0 (array.new 0 (i32.const 42) (i32.const 5)))))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(type (sub (array i32)))
(type (sub 0 (array i32)))
(func (param arrayref) (result i32)
(ref.test (ref 1) (local.get 0)))
(func (export "f") (result i32)
(call 0 (array.new 0 (i32.const 42) (i32.const 5)))))
`).exports.f(),
0
);
assert.throws(
() => instantiate(`
(module
(type (sub (func (result i32))))
(type (sub 0 (func (result i32))))
(elem declare funcref (ref.func 0))
(start 2)
(func (type 0) (i32.const 42))
(func (param funcref)
(ref.cast (ref 1) (local.get 0))
drop)
(func (call 1 (ref.func 0))))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(type (sub (func (result i32))))
(type (sub 0 (func (result i32))))
(elem declare funcref (ref.func 0))
(func (type 0) (i32.const 42))
(func (param funcref) (result i32)
(ref.test (ref 1) (local.get 0)))
(func (export "f") (result i32)
(call 1 (ref.func 0))))
`).exports.f(),
0
);
}
function testEqCasts() {
instantiate(`
(module
(type (array i32))
(start 1)
(func (param arrayref) (result eqref)
(ref.cast (ref eq) (local.get 0)))
(func
(call 0 (array.new 0 (i32.const 42) (i32.const 5)))
drop))
`);
assert.eq(
instantiate(`
(module
(type (array i32))
(func (param arrayref) (result i32)
(ref.test (ref eq) (local.get 0)))
(func (export "f") (result i32)
(call 0 (array.new 0 (i32.const 42) (i32.const 5)))))
`).exports.f(),
1
);
instantiate(`
(module
(type (struct (field i32)))
(start 1)
(func (param structref) (result eqref)
(ref.cast (ref eq) (local.get 0)))
(func
(call 0 (struct.new 0 (i32.const 42)))
drop))
`);
assert.eq(
instantiate(`
(module
(type (struct (field i32)))
(func (param structref) (result i32)
(ref.test (ref eq) (local.get 0)))
(func (export "f") (result i32)
(call 0 (struct.new 0 (i32.const 42)))))
`).exports.f(),
1
);
instantiate(`
(module
(start 1)
(func (param i31ref) (result eqref)
(ref.cast (ref eq) (local.get 0)))
(func
(call 0 (ref.i31 (i32.const 42)))
drop))
`);
assert.eq(
instantiate(`
(module
(func (param i31ref) (result i32)
(ref.test (ref eq) (local.get 0)))
(func (export "f") (result i32)
(call 0 (ref.i31 (i32.const 42)))))
`).exports.f(),
1
);
assert.throws(
() => compile(`
(module
(type (func (result i32)))
(elem declare funcref (ref.func 0))
(func (type 0) (i32.const 42))
(func (param funcref)
(ref.cast (ref eq) (local.get 0))
drop))
`),
WebAssembly.CompileError,
"WebAssembly.Module doesn't validate: ref.cast to type (ref null func) expected a subtype of anyref, in function at index 1 (evaluating 'new WebAssembly.Module(binary)')"
);
}
function testAnyCasts() {
instantiate(`
(module
(type (array i32))
(start 1)
(func (param arrayref) (result anyref)
(ref.cast (ref any) (local.get 0)))
(func
(call 0 (array.new 0 (i32.const 42) (i32.const 5)))
drop))
`);
assert.eq(
instantiate(`
(module
(type (array i32))
(func (param arrayref) (result i32)
(ref.test (ref any) (local.get 0)))
(func (export "f") (result i32)
(call 0 (array.new 0 (i32.const 42) (i32.const 5)))))
`).exports.f(),
1
);
instantiate(`
(module
(type (struct (field i32)))
(start 1)
(func (param structref) (result anyref)
(ref.cast (ref any) (local.get 0)))
(func
(call 0 (struct.new 0 (i32.const 42)))
drop))
`);
assert.eq(
instantiate(`
(module
(type (struct (field i32)))
(func (param structref) (result i32)
(ref.test (ref any) (local.get 0)))
(func (export "f") (result i32)
(call 0 (struct.new 0 (i32.const 42)))))
`).exports.f(),
1
);
instantiate(`
(module
(start 1)
(func (param i31ref) (result anyref)
(ref.cast (ref any) (local.get 0)))
(func
(call 0 (ref.i31 (i32.const 42)))
drop))
`);
assert.eq(
instantiate(`
(module
(func (param i31ref) (result i32)
(ref.test (ref any) (local.get 0)))
(func (export "f") (result i32)
(call 0 (ref.i31 (i32.const 42)))))
`).exports.f(),
1
);
assert.throws(
() => compile(`
(module
(type (func (result i32)))
(elem declare funcref (ref.func 0))
(func (type 0) (i32.const 42))
(func (param funcref)
(ref.cast (ref any) (local.get 0))
drop))
`),
WebAssembly.CompileError,
"WebAssembly.Module doesn't validate: ref.cast to type (ref null func) expected a subtype of anyref, in function at index 1 (evaluating 'new WebAssembly.Module(binary)')"
);
}
function testNullCasts() {
assert.throws(
() => instantiate(`
(module
(type (array i32))
(start 1)
(func (param arrayref) (result nullref)
(ref.cast (ref none) (local.get 0)))
(func
(call 0 (array.new 0 (i32.const 42) (i32.const 5)))
drop))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
)
assert.eq(
instantiate(`
(module
(type (array i32))
(func (param arrayref) (result i32)
(ref.test (ref none) (local.get 0)))
(func (export "f") (result i32)
(call 0 (array.new 0 (i32.const 42) (i32.const 5)))))
`).exports.f(),
0
);
assert.throws(
() => instantiate(`
(module
(start 1)
(func (param funcref) (result nullfuncref)
(ref.cast (ref nofunc) (local.get 0)))
(func
(call 0 (ref.null func))
drop))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
)
assert.eq(
instantiate(`
(module
(func (param funcref) (result i32)
(ref.test (ref nofunc) (local.get 0)))
(func (export "f") (result i32)
(call 0 (ref.null func))))
`).exports.f(),
0
);
assert.throws(
() => instantiate(`
(module
(start 1)
(func (param externref) (result nullexternref)
(ref.cast (ref noextern) (local.get 0)))
(func
(call 0 (ref.null extern))
drop))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
)
assert.eq(
instantiate(`
(module
(func (param externref) (result i32)
(ref.test (ref noextern) (local.get 0)))
(func (export "f") (result i32)
(call 0 (ref.null extern))))
`).exports.f(),
0
);
assert.throws(
() => instantiate(`
(module
(type (struct (field i32)))
(start 1)
(func (param structref) (result nullref)
(ref.cast (ref none) (local.get 0)))
(func
(call 0 (struct.new 0 (i32.const 42)))
drop))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(type (struct (field i32)))
(func (param structref) (result i32)
(ref.test (ref none) (local.get 0)))
(func (export "f") (result i32)
(call 0 (struct.new 0 (i32.const 42)))))
`).exports.f(),
0
);
assert.throws(
() => instantiate(`
(module
(start 1)
(func (param i31ref) (result nullref)
(ref.cast (ref none) (local.get 0)))
(func
(call 0 (ref.i31 (i32.const 42)))
drop))
`),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
assert.eq(
instantiate(`
(module
(func (param i31ref) (result i32)
(ref.test (ref none) (local.get 0)))
(func (export "f") (result i32)
(call 0 (ref.i31 (i32.const 42)))))
`).exports.f(),
0
);
assert.throws(
() => compile(`
(module
(type (func (result i32)))
(elem declare funcref (ref.func 0))
(func (type 0) (i32.const 42))
(func (param funcref)
(ref.cast (ref none) (local.get 0))
drop))
`),
WebAssembly.CompileError,
"WebAssembly.Module doesn't validate: ref.cast to type (ref null func) expected a subtype of anyref, in function at index 1 (evaluating 'new WebAssembly.Module(binary)')"
);
}
function testLargeIndexCasts() {
{
let typedefs = "", casts = "";
for (var i = 0; i < 500; i++) {
typedefs += `(type (struct))\n`;
casts += `(ref.cast (ref ${i}) (struct.new ${i})) drop\n`
}
instantiate(`
(module
${typedefs}
(start 0)
(func ${casts}))
`);
}
}
testValidation();
testBasicCasts();
testI31Casts();
testFunctionCasts();
testArrayCasts();
testStructCasts();
testSubtypeCasts();
testEqCasts();
testAnyCasts();
testNullCasts();
testLargeIndexCasts();