blob: fb6496bb4f37a9dd73027b6f5336a41542052842 [file] [log] [blame] [edit]
import * as assert from "../assert.js";
import { compile, instantiate } from "./wast-wrapper.js";
async function testGCConstExprs() {
{
let m = instantiate(`
(module
(type (array i32))
(global (export "g") (ref 0) (array.new 0 (i32.const 42) (i32.const 10)))
(func (export "f") (param i32) (result i32)
(array.get 0 (global.get 0) (local.get 0)))
)
`);
assert.eq(m.exports.f(3), 42);
}
{
let m = instantiate(`
(module
(type (struct (field i32) (field i64)))
(global (export "g") (ref 0) (struct.new 0 (i32.const 42) (i64.const 84)))
(func (export "f1") (result i32)
(struct.get 0 0 (global.get 0)))
(func (export "f2") (result i64)
(struct.get 0 1 (global.get 0)))
)
`);
assert.eq(m.exports.f1(), 42);
assert.eq(m.exports.f2(), 84n);
}
{
let m = instantiate(`
(module
(type (array externref))
(global (export "g") (ref 0) (array.new_default 0 (i32.const 10)))
(func (export "f") (param i32) (result externref)
(array.get 0 (global.get 0) (local.get 0)))
)
`);
assert.eq(m.exports.f(3), null);
}
{
let m = instantiate(`
(module
(type (struct (field i32) (field i64)))
(global (export "g") (ref 0) (struct.new_default 0))
(func (export "f1") (result i32)
(struct.get 0 0 (global.get 0)))
(func (export "f2") (result i64)
(struct.get 0 1 (global.get 0)))
)
`);
assert.eq(m.exports.f1(), 0);
assert.eq(m.exports.f2(), 0n);
}
{
let m = instantiate(`
(module
(type (array i32))
(global (export "g") (ref 0)
(array.new_fixed 0 4 (i32.const 0) (i32.const 1) (i32.const 2) (i32.const 3)))
(func (export "f") (param i32) (result i32)
(array.get 0 (global.get 0) (local.get 0)))
)
`);
assert.eq(m.exports.f(0), 0);
assert.eq(m.exports.f(1), 1);
assert.eq(m.exports.f(2), 2);
assert.eq(m.exports.f(3), 3);
}
// Test array.new with arithmetic and global.get operations
{
let m = instantiate(`
(module
(type (array i32))
(global (import "m" "gi1") i32)
(global (import "m" "gi2") i32)
(global (export "g") (ref 0)
(array.new 0 (i32.add (global.get 0) (i32.const 3)) (global.get 1)))
(func (export "f") (param i32) (result i32)
(array.get 0 (global.get 2) (local.get 0)))
)`,
{ m: { gi1: 42, gi2: 10} }
);
assert.eq(m.exports.f(3), 45);
}
// Test struct.new with arithmetic & global.get
{
let m = instantiate(`
(module
(type (struct (field i32)))
(global (import "m" "gi1") i32)
(global (import "m" "gi2") i32)
(global (export "g") (ref 0)
(struct.new 0 (i32.add (global.get 0) (global.get 1))))
(func (export "f") (result i32)
(struct.get 0 0 (global.get 2)))
)`,
{ m: { gi1: 42, gi2: 10} }
);
assert.eq(m.exports.f(), 52);
}
{
let m = instantiate(`
(module
(global (export "g") (ref i31) (ref.i31 (i32.const 555))))
`);
assert.eq(m.exports.g.value, 555);
}
{
let m = instantiate(`
(module
(global (export "g") (ref i31) (ref.i31 (i32.const 0x4000_0000))))
`);
assert.eq(m.exports.g.value, -0x40000000);
}
{
let m = instantiate(`
(module
(global (export "g") (ref i31) (ref.i31 (i32.const 0x4000_0000))))
`);
assert.eq(m.exports.g.value, -0x40000000);
}
{
let m = instantiate(`
(module
(global (export "g") (ref i31) (ref.i31 (i32.const 0xaaaa_aaaa))))
`);
assert.eq(m.exports.g.value, 0x2aaaaaaa);
}
{
let m = instantiate(`
(module
(global (export "g") (ref i31) (ref.i31 (i32.const 0x7fff_ffff))))
`);
assert.eq(m.exports.g.value, -1);
}
{
let m = instantiate(`
(module
(global (export "g") externref (extern.convert_any (ref.i31 (i32.const 555)))))
`);
assert.eq(m.exports.g.value, 555);
}
{
let m = instantiate(`
(module
(type (struct))
(global (export "g") externref (extern.convert_any (struct.new 0))))
`);
assert.isObject(m.exports.g.value);
}
{
let m = compile(`
(module
(global (import "m" "gi1") externref)
(global (export "g") (ref null any) (any.convert_extern (global.get 0)))
(func (export "f") (result i32)
(i31.get_s (ref.cast (ref i31) (global.get 1))))
)
`);
let inst1 = new WebAssembly.Instance(m, { m: { gi1: 42 } });
let inst2 = new WebAssembly.Instance(m, { m: { gi1: 2 ** 31 - 1 } });
assert.eq(inst1.exports.g.value, 42);
assert.eq(inst1.exports.f(), 42);
assert.eq(inst2.exports.g.value, 2 ** 31 - 1);
assert.throws(
() => inst2.exports.f(),
WebAssembly.RuntimeError,
"ref.cast failed to cast reference to target heap type"
);
}
}
async function testInvalidConstExprs() {
assert.throws(
() => compile(`
(module
(type (struct (field i32)))
(global (export "g") (ref 0) (struct.new 0 (i64.const 1))))
`),
WebAssembly.CompileError,
"WebAssembly.Module doesn't validate: argument type mismatch in struct.new, got I64, expected I32"
);
assert.throws(
() => compile(`
(module
(type (struct (field i32)))
(global (export "g") i32 (struct.new 0 (i32.const 1))))
`),
WebAssembly.CompileError,
"WebAssembly.Module doesn't validate: control flow returns with unexpected type. (ref <struct:0>) is not a I32"
);
assert.throws(
() => compile(`
(module
(type (array i32))
(global (export "g") (ref 0) (array.len (array.new 0 (i32.const 1) (i32.const 1)))))
`),
WebAssembly.CompileError,
"WebAssembly.Module doesn't parse at byte 37: Invalid instruction for constant expression"
);
}
async function testConstExprGlobalOrdering() {
instantiate(`
(module
(global i32 (i32.const 0))
(global i32 (global.get 0)))
`);
instantiate(`
(module
(global i32 (i32.const 0))
(global i32 (i32.const 1))
(global i32 (i32.const 2))
(global i32 (global.get 1))
(global i32 (global.get 3)))
`);
{
let m = instantiate(`
(module
(global i32 (i32.add (i32.const 0) (i32.const 1)))
(global (export "g") i32 (i32.add (i32.const 1 (global.get 0)))))
`);
assert.eq(m.exports.g.value, 2);
}
instantiate(`
(module
(global (import "m" "g") externref)
(table 10 externref (global.get 0)))
`, { m: { g: "foo" } });
instantiate(`
(module
(global i32 (i32.const 0))
(global i32 (i32.const 1))
(global i32 (i32.const 2))
(global i32 (global.get 1))
(global i32 (global.get 3)))
`);
instantiate(`
(module
(table (export "t") 64 funcref)
(global i32 (i32.const 5))
(elem (table 0) (offset (i32.add (global.get 0) (i32.const 42))) funcref (ref.null func)))
`);
assert.throws(
() => compile(`
(module
(global i32 (global.get 1))
(global i32 (i32.const 0)))
`),
WebAssembly.CompileError,
"WebAssembly.Module doesn't parse at byte 19: get_global's index 1 exceeds the number of globals 0"
);
assert.throws(
() => compile(`
(module
(table 10 externref (global.get 0))
(global externref (ref.null extern)))
`),
WebAssembly.CompileError,
"WebAssembly.Module doesn't parse at byte 22: get_global's index 0 exceeds the number of globals 0"
);
}
async function testElementConstExprs() {
{
let m = instantiate(`
(module
(type (struct (field i32)))
(type (struct (field f32)))
(table 10 (ref null struct))
(elem (table 0) (offset (i32.const 0)) (ref struct) (struct.new 0 (i32.const 2)) (struct.new 1 (f32.const 3)))
(func (export "f0") (param i32) (result i32)
(struct.get 0 0 (ref.cast (ref 0) (table.get (local.get 0)))))
(func (export "f1") (param i32) (result f32)
(struct.get 1 0 (ref.cast (ref 1) (table.get (local.get 0)))))
)
`);
assert.eq(m.exports.f0(0), 2);
assert.eq(m.exports.f1(1), 3);
}
{
let m = instantiate(`
(module
(type (struct (field i32)))
(type (struct (field f32)))
(table 10 (ref null struct))
(elem (ref struct) (struct.new 0 (i32.const 2)) (struct.new 1 (f32.const 3)))
(func (export "init") (table.init 0 0 (i32.const 0) (i32.const 0) (i32.const 2)))
(func (export "f0") (param i32) (result i32)
(struct.get 0 0 (ref.cast (ref 0) (table.get (local.get 0)))))
(func (export "f1") (param i32) (result f32)
(struct.get 1 0 (ref.cast (ref 1) (table.get (local.get 0)))))
)
`);
m.exports.init();
assert.eq(m.exports.f0(0), 2);
assert.eq(m.exports.f1(1), 3);
}
{
let m = instantiate(`
(module
(type (struct (field i32)))
(type (struct (field f32)))
(table 10 externref)
(elem externref (extern.convert_any (struct.new 0 (i32.const 2)))
(extern.convert_any (struct.new 1 (f32.const 4.2))))
(func (export "init") (table.init 0 0 (i32.const 2) (i32.const 0) (i32.const 0)))
(func (export "f") (param i32) (result externref)
(table.get (local.get 0)))
)
`);
m.exports.init();
assert.isObject(m.exports.f(0));
assert.isObject(m.exports.f(1));
}
}
await assert.asyncTest(testGCConstExprs());
await assert.asyncTest(testInvalidConstExprs());
await assert.asyncTest(testConstExprGlobalOrdering())
await assert.asyncTest(testElementConstExprs());