diff options
-rwxr-xr-x | scripts/fuzz_opt.py | 1 | ||||
-rwxr-xr-x | scripts/gen-s-parser.py | 5 | ||||
-rw-r--r-- | scripts/test/binaryenjs.py | 2 | ||||
-rw-r--r-- | src/gen-s-parser.inc | 23 | ||||
-rw-r--r-- | src/ir/properties.h | 3 | ||||
-rw-r--r-- | src/literal.h | 6 | ||||
-rw-r--r-- | src/parser/contexts.h | 11 | ||||
-rw-r--r-- | src/parser/parsers.h | 11 | ||||
-rw-r--r-- | src/parser/wast-parser.cpp | 7 | ||||
-rw-r--r-- | src/passes/Print.cpp | 6 | ||||
-rw-r--r-- | src/wasm-binary.h | 1 | ||||
-rw-r--r-- | src/wasm-builder.h | 3 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 3 | ||||
-rw-r--r-- | src/wasm-ir-builder.h | 2 | ||||
-rw-r--r-- | src/wasm/literal.cpp | 3 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 18 | ||||
-rw-r--r-- | src/wasm/wasm-ir-builder.cpp | 4 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 4 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 3 | ||||
-rw-r--r-- | test/binaryen.js/expressions.js | 3 | ||||
-rw-r--r-- | test/lit/basic/shared-i31.wast | 37 | ||||
-rw-r--r-- | test/spec/shared-i31.wast | 230 |
22 files changed, 348 insertions, 38 deletions
diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index 2707df4c0..ada930127 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -356,6 +356,7 @@ INITIAL_CONTENTS_IGNORE = [ 'shared-polymorphism.wast', 'shared-struct.wast', 'shared-array.wast', + 'shared-i31.wast', ] diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py index 43a85c636..711096a5b 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -572,8 +572,9 @@ instructions = [ ("resume", "makeResume()"), ("suspend", "makeSuspend()"), # GC - ("i31.new", "makeRefI31()"), # deprecated - ("ref.i31", "makeRefI31()"), + ("i31.new", "makeRefI31(Unshared)"), # deprecated + ("ref.i31", "makeRefI31(Unshared)"), + ("ref.i31_shared", "makeRefI31(Shared)"), ("i31.get_s", "makeI31Get(true)"), ("i31.get_u", "makeI31Get(false)"), ("ref.test", "makeRefTest()"), diff --git a/scripts/test/binaryenjs.py b/scripts/test/binaryenjs.py index d546ced13..93fbe532f 100644 --- a/scripts/test/binaryenjs.py +++ b/scripts/test/binaryenjs.py @@ -60,7 +60,7 @@ def do_test_binaryen_js_with(which): test([shared.MOZJS, '-m', 'a.mjs']) if shared.NODEJS: if node_has_wasm or 'WebAssembly.' not in test_src: - test([shared.NODEJS, '--experimental-wasm-eh', 'a.mjs']) + test([shared.NODEJS, 'a.mjs']) else: print('Skipping ' + test_path + ' because WebAssembly might not be supported') diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 8a3dcba0b..bbed0f8be 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -1831,7 +1831,7 @@ switch (buf[0]) { } case 'n': if (op == "i31.new"sv) { - CHECK_ERR(makeRefI31(ctx, pos, annotations)); + CHECK_ERR(makeRefI31(ctx, pos, annotations, Unshared)); return Ok{}; } goto parse_error; @@ -4505,12 +4505,23 @@ switch (buf[0]) { goto parse_error; case 'i': { switch (buf[5]) { - case '3': - if (op == "ref.i31"sv) { - CHECK_ERR(makeRefI31(ctx, pos, annotations)); - return Ok{}; + case '3': { + switch (buf[7]) { + case '\0': + if (op == "ref.i31"sv) { + CHECK_ERR(makeRefI31(ctx, pos, annotations, Unshared)); + return Ok{}; + } + goto parse_error; + case '_': + if (op == "ref.i31_shared"sv) { + CHECK_ERR(makeRefI31(ctx, pos, annotations, Shared)); + return Ok{}; + } + goto parse_error; + default: goto parse_error; } - goto parse_error; + } case 's': if (op == "ref.is_null"sv) { CHECK_ERR(makeRefIsNull(ctx, pos, annotations)); diff --git a/src/ir/properties.h b/src/ir/properties.h index ccb2392b0..09486ee34 100644 --- a/src/ir/properties.h +++ b/src/ir/properties.h @@ -119,7 +119,8 @@ inline Literal getLiteral(const Expression* curr) { return Literal(r->func, r->type.getHeapType()); } else if (auto* i = curr->dynCast<RefI31>()) { if (auto* c = i->value->dynCast<Const>()) { - return Literal::makeI31(c->value.geti32()); + return Literal::makeI31(c->value.geti32(), + i->type.getHeapType().getShared()); } } else if (auto* s = curr->dynCast<StringConst>()) { return Literal(s->string.toString()); diff --git a/src/literal.h b/src/literal.h index 1268448fb..45f76f247 100644 --- a/src/literal.h +++ b/src/literal.h @@ -243,8 +243,8 @@ public: static Literal makeFunc(Name func, HeapType type) { return Literal(func, type); } - static Literal makeI31(int32_t value) { - auto lit = Literal(Type(HeapType::i31, NonNullable)); + static Literal makeI31(int32_t value, Shareability share) { + auto lit = Literal(Type(HeapTypes::i31.getBasic(share), NonNullable)); lit.i32 = value | 0x80000000; return lit; } @@ -281,7 +281,7 @@ public: return i32; } int32_t geti31(bool signed_ = true) const { - assert(type.getHeapType() == HeapType::i31); + assert(type.getHeapType().getBasic(Unshared) == HeapType::i31); // Cast to unsigned for the left shift to avoid undefined behavior. return signed_ ? int32_t((uint32_t(i32) << 1)) >> 1 : (i32 & 0x7fffffff); } diff --git a/src/parser/contexts.h b/src/parser/contexts.h index f58275d71..96a70663d 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -695,7 +695,10 @@ struct NullInstrParserCtx { Result<> makeCallRef(Index, const std::vector<Annotation>&, HeapTypeT, bool) { return Ok{}; } - Result<> makeRefI31(Index, const std::vector<Annotation>&) { return Ok{}; } + Result<> + makeRefI31(Index, const std::vector<Annotation>&, Shareability share) { + return Ok{}; + } Result<> makeI31Get(Index, const std::vector<Annotation>&, bool) { return Ok{}; } @@ -2363,8 +2366,10 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { return withLoc(pos, irBuilder.makeCallRef(type, isReturn)); } - Result<> makeRefI31(Index pos, const std::vector<Annotation>& annotations) { - return withLoc(pos, irBuilder.makeRefI31()); + Result<> makeRefI31(Index pos, + const std::vector<Annotation>& annotations, + Shareability share) { + return withLoc(pos, irBuilder.makeRefI31(share)); } Result<> makeI31Get(Index pos, diff --git a/src/parser/parsers.h b/src/parser/parsers.h index db450e3c6..2c3916fa3 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -221,7 +221,8 @@ template<typename Ctx> Result<> makeCallRef(Ctx&, Index, const std::vector<Annotation>&, bool isReturn); template<typename Ctx> -Result<> makeRefI31(Ctx&, Index, const std::vector<Annotation>&); +Result<> +makeRefI31(Ctx&, Index, const std::vector<Annotation>&, Shareability share); template<typename Ctx> Result<> makeI31Get(Ctx&, Index, const std::vector<Annotation>&, bool signed_); template<typename Ctx> @@ -2127,9 +2128,11 @@ Result<> makeCallRef(Ctx& ctx, } template<typename Ctx> -Result<> -makeRefI31(Ctx& ctx, Index pos, const std::vector<Annotation>& annotations) { - return ctx.makeRefI31(pos, annotations); +Result<> makeRefI31(Ctx& ctx, + Index pos, + const std::vector<Annotation>& annotations, + Shareability share) { + return ctx.makeRefI31(pos, annotations, share); } template<typename Ctx> diff --git a/src/parser/wast-parser.cpp b/src/parser/wast-parser.cpp index 137ef0df1..a3a6c14ce 100644 --- a/src/parser/wast-parser.cpp +++ b/src/parser/wast-parser.cpp @@ -207,6 +207,13 @@ Result<ExpectedResult> result(Lexer& in) { return RefResult{HeapType::func}; } + if (in.takeSExprStart("ref.i31_shared")) { + if (!in.takeRParen()) { + return in.err("expected end of ref.i31_shared"); + } + return RefResult{HeapTypes::i31.getBasic(Shared)}; + } + return in.err("unrecognized result"); } diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 2e9800775..ede49ab38 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2076,7 +2076,11 @@ struct PrintExpressionContents o << std::max(curr->tuple->type.size(), size_t(2)) << " "; o << curr->index; } - void visitRefI31(RefI31* curr) { printMedium(o, "ref.i31"); } + void visitRefI31(RefI31* curr) { + bool shared = + curr->type != Type::unreachable && curr->type.getHeapType().isShared(); + printMedium(o, shared ? "ref.i31_shared" : "ref.i31"); + } void visitI31Get(I31Get* curr) { printMedium(o, curr->signed_ ? "i31.get_s" : "i31.get_u"); } diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 0b9615c7e..3e45b4969 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1125,6 +1125,7 @@ enum ASTNodes { RefI31 = 0x1c, I31GetS = 0x1d, I31GetU = 0x1e, + RefI31Shared = 0x1f, // stringref opcodes diff --git a/src/wasm-builder.h b/src/wasm-builder.h index a20ba46a6..1e768b11c 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -873,9 +873,10 @@ public: ret->finalize(); return ret; } - RefI31* makeRefI31(Expression* value) { + RefI31* makeRefI31(Expression* value, Shareability share = Unshared) { auto* ret = wasm.allocator.alloc<RefI31>(); ret->value = value; + ret->type = Type(HeapTypes::i31.getBasic(share), NonNullable); ret->finalize(); return ret; } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 93739d1c9..9bdf0e72c 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1426,7 +1426,8 @@ public: } const auto& value = flow.getSingleValue(); NOTE_EVAL1(value); - return Literal::makeI31(value.geti32()); + return Literal::makeI31(value.geti32(), + curr->type.getHeapType().getShared()); } Flow visitI31Get(I31Get* curr) { NOTE_ENTER("I31Get"); diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index 16c3b7570..eff8c85ad 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -181,7 +181,7 @@ public: [[nodiscard]] Result<> makeTupleMake(uint32_t arity); [[nodiscard]] Result<> makeTupleExtract(uint32_t arity, uint32_t index); [[nodiscard]] Result<> makeTupleDrop(uint32_t arity); - [[nodiscard]] Result<> makeRefI31(); + [[nodiscard]] Result<> makeRefI31(Shareability share); [[nodiscard]] Result<> makeI31Get(bool signed_); [[nodiscard]] Result<> makeCallRef(HeapType type, bool isReturn); [[nodiscard]] Result<> makeRefTest(Type type); diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index f13ea504f..20b6b7234 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -57,7 +57,8 @@ Literal::Literal(Type type) : type(type) { return; } - if (type.isRef() && type.getHeapType() == HeapType::i31) { + if (type.isRef() && type.getHeapType().isBasic() && + type.getHeapType().getBasic(Unshared) == HeapType::i31) { assert(type.isNonNullable()); i32 = 0; return; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 78470324c..74d74f473 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -7244,13 +7244,19 @@ void WasmBinaryReader::visitCallRef(CallRef* curr) { } bool WasmBinaryReader::maybeVisitRefI31(Expression*& out, uint32_t code) { - if (code != BinaryConsts::RefI31) { - return false; + Shareability share; + switch (code) { + case BinaryConsts::RefI31: + share = Unshared; + break; + case BinaryConsts::RefI31Shared: + share = Shared; + break; + default: + return false; } - auto* curr = allocator.alloc<RefI31>(); - curr->value = popNonVoidExpression(); - curr->finalize(); - out = curr; + auto* value = popNonVoidExpression(); + out = Builder(wasm).makeRefI31(value, share); return true; } diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 63f5df4c0..3db6238c4 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -1605,10 +1605,10 @@ Result<> IRBuilder::makeTupleDrop(uint32_t arity) { return Ok{}; } -Result<> IRBuilder::makeRefI31() { +Result<> IRBuilder::makeRefI31(Shareability share) { RefI31 curr; CHECK_ERR(visitRefI31(&curr)); - push(builder.makeRefI31(curr.value)); + push(builder.makeRefI31(curr.value, share)); return Ok{}; } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 40a50706a..cd0a9928e 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2114,7 +2114,9 @@ void BinaryInstWriter::visitTupleExtract(TupleExtract* curr) { } void BinaryInstWriter::visitRefI31(RefI31* curr) { - o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefI31); + o << int8_t(BinaryConsts::GCPrefix) + << U32LEB(curr->type.getHeapType().isShared() ? BinaryConsts::RefI31Shared + : BinaryConsts::RefI31); } void BinaryInstWriter::visitI31Get(I31Get* curr) { diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 8a2b4755c..c4f02128e 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -964,7 +964,8 @@ void RefI31::finalize() { if (value->type == Type::unreachable) { type = Type::unreachable; } else { - type = Type(HeapType::i31, NonNullable); + assert(type.isRef() && type.getHeapType().isBasic() && + type.getHeapType().getBasic(Unshared) == HeapType::i31); } } diff --git a/test/binaryen.js/expressions.js b/test/binaryen.js/expressions.js index bd8ec6793..c05e820a7 100644 --- a/test/binaryen.js/expressions.js +++ b/test/binaryen.js/expressions.js @@ -1777,9 +1777,6 @@ console.log("# RefI31"); theRefI31.value = value = module.local.get(2, binaryen.i32); assert(theRefI31.value === value); - theRefI31.type = binaryen.f64; - theRefI31.finalize(); - // assert(theRefI31.type === binaryen.?); // TODO: (ref i31) console.log(theRefI31.toText()); assert( diff --git a/test/lit/basic/shared-i31.wast b/test/lit/basic/shared-i31.wast new file mode 100644 index 000000000..b448bcad3 --- /dev/null +++ b/test/lit/basic/shared-i31.wast @@ -0,0 +1,37 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; RUN: wasm-opt %s -all -S -o - | filecheck %s +;; RUN: wasm-opt %s -all --roundtrip -S -o - | filecheck %s + +(module + ;; CHECK: (type $0 (func (param (ref null (shared i31))) (result i32))) + + ;; CHECK: (type $1 (func (param i32) (result (ref (shared i31))))) + + ;; CHECK: (func $make (type $1) (param $0 i32) (result (ref (shared i31))) + ;; CHECK-NEXT: (ref.i31_shared + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $make (param i32) (result (ref (shared i31))) + (ref.i31_shared (local.get 0)) + ) + + ;; CHECK: (func $get_s (type $0) (param $0 (ref null (shared i31))) (result i32) + ;; CHECK-NEXT: (i31.get_s + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $get_s (param (ref null (shared i31))) (result i32) + (i31.get_s (local.get 0)) + ) + + ;; CHECK: (func $get_u (type $0) (param $0 (ref null (shared i31))) (result i32) + ;; CHECK-NEXT: (i31.get_u + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $get_u (param (ref null (shared i31))) (result i32) + (i31.get_u (local.get 0)) + ) +) diff --git a/test/spec/shared-i31.wast b/test/spec/shared-i31.wast new file mode 100644 index 000000000..ef1e2a9f1 --- /dev/null +++ b/test/spec/shared-i31.wast @@ -0,0 +1,230 @@ +(module + (func (export "new") (param $i i32) (result (ref (shared i31))) + (ref.i31_shared (local.get $i)) + ) + + (func (export "get_u") (param $i i32) (result i32) + (i31.get_u (ref.i31_shared (local.get $i))) + ) + (func (export "get_s") (param $i i32) (result i32) + (i31.get_s (ref.i31_shared (local.get $i))) + ) + + (func (export "get_u-null") (result i32) + (i31.get_u (ref.null (shared i31))) + ) + (func (export "get_s-null") (result i32) + (i31.get_u (ref.null (shared i31))) + ) + + (global $i (ref (shared i31)) (ref.i31_shared (i32.const 2))) + (global $m (mut (ref (shared i31))) (ref.i31_shared (i32.const 3))) + + (func (export "get_globals") (result i32 i32) + (i31.get_u (global.get $i)) + (i31.get_u (global.get $m)) + ) + + (func (export "set_global") (param i32) + (global.set $m (ref.i31_shared (local.get 0))) + ) +) + +(assert_return (invoke "new" (i32.const 1)) (ref.i31_shared)) + +(assert_return (invoke "get_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "get_u" (i32.const 100)) (i32.const 100)) +(assert_return (invoke "get_u" (i32.const -1)) (i32.const 0x7fff_ffff)) +(assert_return (invoke "get_u" (i32.const 0x3fff_ffff)) (i32.const 0x3fff_ffff)) +(assert_return (invoke "get_u" (i32.const 0x4000_0000)) (i32.const 0x4000_0000)) +(assert_return (invoke "get_u" (i32.const 0x7fff_ffff)) (i32.const 0x7fff_ffff)) +(assert_return (invoke "get_u" (i32.const 0xaaaa_aaaa)) (i32.const 0x2aaa_aaaa)) +(assert_return (invoke "get_u" (i32.const 0xcaaa_aaaa)) (i32.const 0x4aaa_aaaa)) + +(assert_return (invoke "get_s" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "get_s" (i32.const 100)) (i32.const 100)) +(assert_return (invoke "get_s" (i32.const -1)) (i32.const -1)) +(assert_return (invoke "get_s" (i32.const 0x3fff_ffff)) (i32.const 0x3fff_ffff)) +(assert_return (invoke "get_s" (i32.const 0x4000_0000)) (i32.const -0x4000_0000)) +(assert_return (invoke "get_s" (i32.const 0x7fff_ffff)) (i32.const -1)) +(assert_return (invoke "get_s" (i32.const 0xaaaa_aaaa)) (i32.const 0x2aaa_aaaa)) +(assert_return (invoke "get_s" (i32.const 0xcaaa_aaaa)) (i32.const 0xcaaa_aaaa)) + +(assert_trap (invoke "get_u-null") "null i31 reference") +(assert_trap (invoke "get_s-null") "null i31 reference") + +(assert_return (invoke "get_globals") (i32.const 2) (i32.const 3)) + +(invoke "set_global" (i32.const 1234)) +(assert_return (invoke "get_globals") (i32.const 2) (i32.const 1234)) + +(module $tables_of_i31ref + (table $table 3 10 (ref null (shared i31))) + (elem (table $table) (i32.const 0) (ref null (shared i31)) + (item (ref.i31_shared (i32.const 999))) + (item (ref.i31_shared (i32.const 888))) + (item (ref.i31_shared (i32.const 777)))) + + (func (export "size") (result i32) + table.size $table + ) + + (func (export "get") (param i32) (result i32) + (i31.get_u (table.get $table (local.get 0))) + ) + + (func (export "grow") (param i32 i32) (result i32) + (table.grow $table (ref.i31_shared (local.get 1)) (local.get 0)) + ) + + (func (export "fill") (param i32 i32 i32) + (table.fill $table (local.get 0) (ref.i31_shared (local.get 1)) (local.get 2)) + ) + + (func (export "copy") (param i32 i32 i32) + (table.copy $table $table (local.get 0) (local.get 1) (local.get 2)) + ) + + (elem $elem (ref null (shared i31)) (item (ref.i31_shared (i32.const 123))) + (item (ref.i31_shared (i32.const 456))) + (item (ref.i31_shared (i32.const 789)))) + ;; (func (export "init") (param i32 i32 i32) + ;; (table.init $table $elem (local.get 0) (local.get 1) (local.get 2)) + ;; ) +) + +;; Initial state. +(assert_return (invoke "size") (i32.const 3)) +(assert_return (invoke "get" (i32.const 0)) (i32.const 999)) +(assert_return (invoke "get" (i32.const 1)) (i32.const 888)) +(assert_return (invoke "get" (i32.const 2)) (i32.const 777)) + +;; Grow from size 3 to size 5. +(assert_return (invoke "grow" (i32.const 2) (i32.const 333)) (i32.const 3)) +(assert_return (invoke "size") (i32.const 5)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 333)) +(assert_return (invoke "get" (i32.const 4)) (i32.const 333)) + +;; Fill table[2..4] = 111. +(invoke "fill" (i32.const 2) (i32.const 111) (i32.const 2)) +(assert_return (invoke "get" (i32.const 2)) (i32.const 111)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 111)) + +;; Copy from table[0..2] to table[3..5]. +(invoke "copy" (i32.const 3) (i32.const 0) (i32.const 2)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 999)) +(assert_return (invoke "get" (i32.const 4)) (i32.const 888)) + +;; ;; Initialize the passive element at table[1..4]. +;; (invoke "init" (i32.const 1) (i32.const 0) (i32.const 3)) +;; (assert_return (invoke "get" (i32.const 1)) (i32.const 123)) +;; (assert_return (invoke "get" (i32.const 2)) (i32.const 456)) +;; (assert_return (invoke "get" (i32.const 3)) (i32.const 789)) + +(module $env + (global (export "g") i32 (i32.const 42)) +) +(register "env") + +;; (module $i31ref_of_global_table_initializer +;; (global $g (import "env" "g") i32) +;; (table $t 3 3 (ref (shared i31)) (ref.i31_shared (global.get $g))) +;; (func (export "get") (param i32) (result i32) +;; (i31.get_u (local.get 0) (table.get $t)) +;; ) +;; ) + +;; (assert_return (invoke "get" (i32.const 0)) (i32.const 42)) +;; (assert_return (invoke "get" (i32.const 1)) (i32.const 42)) +;; (assert_return (invoke "get" (i32.const 2)) (i32.const 42)) + +(module $i31ref_of_global_global_initializer + (global $g0 (import "env" "g") i32) + (global $g1 (ref null (shared i31)) (ref.i31_shared (global.get $g0))) + (func (export "get") (result i32) + (i31.get_u (global.get $g1)) + ) +) + +(assert_return (invoke "get") (i32.const 42)) + +(module $anyref_global_of_i31ref + (global $c (ref null (shared any)) (ref.i31_shared (i32.const 1234))) + (global $m (mut (ref null (shared any))) (ref.i31_shared (i32.const 5678))) + + (func (export "get_globals") (result i32 i32) + (i31.get_u (ref.cast (ref null (shared i31)) (global.get $c))) + (i31.get_u (ref.cast (ref null (shared i31)) (global.get $m))) + ) + + (func (export "set_global") (param i32) + (global.set $m (ref.i31_shared (local.get 0))) + ) +) + +(assert_return (invoke "get_globals") (i32.const 1234) (i32.const 5678)) +(invoke "set_global" (i32.const 0)) +(assert_return (invoke "get_globals") (i32.const 1234) (i32.const 0)) + +(module $anyref_table_of_i31ref + (table $table 3 10 (ref null (shared any))) + (elem (table $table) (i32.const 0) (ref null (shared i31)) + (item (ref.i31_shared (i32.const 999))) + (item (ref.i31_shared (i32.const 888))) + (item (ref.i31_shared (i32.const 777)))) + + (func (export "size") (result i32) + table.size $table + ) + + (func (export "get") (param i32) (result i32) + (i31.get_u (ref.cast (ref null (shared i31)) (table.get $table (local.get 0)))) + ) + + (func (export "grow") (param i32 i32) (result i32) + (table.grow $table (ref.i31_shared (local.get 1)) (local.get 0)) + ) + + (func (export "fill") (param i32 i32 i32) + (table.fill $table (local.get 0) (ref.i31_shared (local.get 1)) (local.get 2)) + ) + + (func (export "copy") (param i32 i32 i32) + (table.copy $table $table (local.get 0) (local.get 1) (local.get 2)) + ) + + (elem $elem (ref null (shared i31)) (item (ref.i31_shared (i32.const 123))) + (item (ref.i31_shared (i32.const 456))) + (item (ref.i31_shared (i32.const 789)))) + ;; (func (export "init") (param i32 i32 i32) + ;; (table.init $table $elem (local.get 0) (local.get 1) (local.get 2)) + ;; ) +) + +;; Initial state. +(assert_return (invoke "size") (i32.const 3)) +(assert_return (invoke "get" (i32.const 0)) (i32.const 999)) +(assert_return (invoke "get" (i32.const 1)) (i32.const 888)) +(assert_return (invoke "get" (i32.const 2)) (i32.const 777)) + +;; Grow from size 3 to size 5. +(assert_return (invoke "grow" (i32.const 2) (i32.const 333)) (i32.const 3)) +(assert_return (invoke "size") (i32.const 5)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 333)) +(assert_return (invoke "get" (i32.const 4)) (i32.const 333)) + +;; Fill table[2..4] = 111. +(invoke "fill" (i32.const 2) (i32.const 111) (i32.const 2)) +(assert_return (invoke "get" (i32.const 2)) (i32.const 111)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 111)) + +;; Copy from table[0..2] to table[3..5]. +(invoke "copy" (i32.const 3) (i32.const 0) (i32.const 2)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 999)) +(assert_return (invoke "get" (i32.const 4)) (i32.const 888)) + +;; ;; Initialize the passive element at table[1..4]. +;; (invoke "init" (i32.const 1) (i32.const 0) (i32.const 3)) +;; (assert_return (invoke "get" (i32.const 1)) (i32.const 123)) +;; (assert_return (invoke "get" (i32.const 2)) (i32.const 456)) +;; (assert_return (invoke "get" (i32.const 3)) (i32.const 789)) |