From 1cd89d57c0d2aba20245174e9b2642320e2b3b27 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 31 Jul 2020 22:29:44 -0700 Subject: [PATCH] Implement changes in reference types proposal This updates reference types proposal up-to-date, per WebAssembly/reference-types#87. Only maybe half of tests have been updated, so CI will not pass. I was in the process of updating them fully, but then I noticed #3084, so I'm not sure if I should continue to do this anymore. I asked him if he wanted to do it himself to prevent this situation but apparently my questions weren't answered and I didn't know that he was working on this at the same time. I'm uploading this anyway in case this is necessary for discussions. --- check.py | 5 +- scripts/gen-s-parser.py | 1 - scripts/test/wasm_opt.py | 6 +- src/asmjs/asm_v_wasm.cpp | 3 - src/binaryen-c.cpp | 11 +- src/binaryen-c.h | 4 +- src/gen-s-parser.inc | 14 +- src/ir/ExpressionManipulator.cpp | 4 +- src/ir/abstract.h | 2 - src/ir/properties.h | 2 +- src/js/binaryen.js-post.js | 11 +- src/literal.h | 26 ++- src/parsing.h | 1 - src/passes/ConstHoisting.cpp | 1 - src/passes/Flatten.cpp | 16 +- src/passes/FuncCastEmulation.cpp | 2 - src/passes/InstrumentLocals.cpp | 16 -- src/passes/Precompute.cpp | 10 +- src/passes/Print.cpp | 13 ++ src/shell-interface.h | 4 +- src/tools/fuzzing.h | 42 +--- src/tools/spec-wrapper.h | 7 +- src/tools/wasm-reduce.cpp | 7 +- src/wasm-binary.h | 5 - src/wasm-builder.h | 9 +- src/wasm-interpreter.h | 10 +- src/wasm-type.h | 2 - src/wasm.h | 4 +- src/wasm/literal.cpp | 38 ++-- src/wasm/wasm-binary.cpp | 3 +- src/wasm/wasm-s-parser.cpp | 18 +- src/wasm/wasm-stack.cpp | 5 +- src/wasm/wasm-type.cpp | 27 +-- src/wasm/wasm-validator.cpp | 10 +- src/wasm/wasm.cpp | 4 +- test/binaryen.js/kitchen-sink.js | 1 - test/example/c-api-kitchen-sink.c | 20 +- test/multivalue.wast | 8 +- test/passes/dce_all-features.wast | 10 +- test/passes/merge-locals_all-features.wast | 12 -- test/passes/precompute_all-features.wast | 16 +- test/reference-types.wast | 236 ++++++--------------- 42 files changed, 219 insertions(+), 427 deletions(-) diff --git a/check.py b/check.py index e91dfda85f5..368e31883b6 100755 --- a/check.py +++ b/check.py @@ -240,10 +240,7 @@ def check_expected(actual, expected): # some wast files cannot be split: # * comments.wast: contains characters that are not valid utf-8, # so our string splitting code fails there - - # FIXME Remove reference type tests from this list after nullref is - # implemented in V8 - if base not in ['comments.wast', 'ref_null.wast', 'ref_is_null.wast', 'ref_func.wast', 'old_select.wast']: + if base not in ['comments.wast', 'old_select.wast']: split_num = 0 actual = '' for module, asserts in support.split_wast(wast): diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py index 2d22c2cbdf8..f105e640783 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -50,7 +50,6 @@ ("v128.pop", "makePop(Type::v128)"), ("funcref.pop", "makePop(Type::funcref)"), ("externref.pop", "makePop(Type::externref)"), - ("nullref.pop", "makePop(Type::nullref)"), ("exnref.pop", "makePop(Type::exnref)"), ("i32.load", "makeLoad(s, Type::i32, /*isAtomic=*/false)"), ("i64.load", "makeLoad(s, Type::i64, /*isAtomic=*/false)"), diff --git a/scripts/test/wasm_opt.py b/scripts/test/wasm_opt.py index 2c7d49eb7ef..41ca4d43980 100644 --- a/scripts/test/wasm_opt.py +++ b/scripts/test/wasm_opt.py @@ -113,10 +113,8 @@ def check(): shared.fail_if_not_identical_to_file(actual, f) - # FIXME Remove this condition after nullref is implemented in V8 - if 'reference-types.wast' not in t: - shared.binary_format_check(t, wasm_as_args=['-g']) # test with debuginfo - shared.binary_format_check(t, wasm_as_args=[], binary_suffix='.fromBinary.noDebugInfo') # test without debuginfo + shared.binary_format_check(t, wasm_as_args=['-g']) # test with debuginfo + shared.binary_format_check(t, wasm_as_args=[], binary_suffix='.fromBinary.noDebugInfo') # test without debuginfo shared.minify_check(t) diff --git a/src/asmjs/asm_v_wasm.cpp b/src/asmjs/asm_v_wasm.cpp index 4a79d9caf48..ddcb27d3dc9 100644 --- a/src/asmjs/asm_v_wasm.cpp +++ b/src/asmjs/asm_v_wasm.cpp @@ -56,7 +56,6 @@ AsmType wasmToAsmType(Type type) { assert(false && "v128 not implemented yet"); case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: assert(false && "reference types are not supported by asm2wasm"); case Type::none: @@ -84,8 +83,6 @@ char getSig(Type type) { return 'F'; case Type::externref: return 'X'; - case Type::nullref: - return 'N'; case Type::exnref: return 'E'; case Type::none: diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index db9258d59be..8d8fd64b64c 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -71,8 +71,6 @@ BinaryenLiteral toBinaryenLiteral(Literal x) { case Type::funcref: ret.func = x.getFunc().c_str(); break; - case Type::nullref: - break; case Type::externref: case Type::exnref: case Type::none: @@ -96,8 +94,6 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) { return Literal(x.v128); case Type::funcref: return Literal::makeFuncref(x.func); - case Type::nullref: - return Literal::makeNullref(); case Type::externref: case Type::exnref: case Type::none: @@ -133,7 +129,6 @@ BinaryenType BinaryenTypeFloat64(void) { return Type::f64; } BinaryenType BinaryenTypeVec128(void) { return Type::v128; } BinaryenType BinaryenTypeFuncref(void) { return Type::funcref; } BinaryenType BinaryenTypeExternref(void) { return Type::externref; } -BinaryenType BinaryenTypeNullref(void) { return Type::nullref; } BinaryenType BinaryenTypeExnref(void) { return Type::exnref; } BinaryenType BinaryenTypeUnreachable(void) { return Type::unreachable; } BinaryenType BinaryenTypeAuto(void) { return uintptr_t(-1); } @@ -1264,8 +1259,10 @@ BinaryenExpressionRef BinaryenPop(BinaryenModuleRef module, BinaryenType type) { Builder(*(Module*)module).makePop(Type(type))); } -BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module) { - return static_cast(Builder(*(Module*)module).makeRefNull()); +BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module, + BinaryenType type) { + return static_cast( + Builder(*(Module*)module).makeRefNull(Type(type))); } BinaryenExpressionRef BinaryenRefIsNull(BinaryenModuleRef module, diff --git a/src/binaryen-c.h b/src/binaryen-c.h index 6239befd23a..a8aa7249699 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -100,7 +100,6 @@ BINARYEN_API BinaryenType BinaryenTypeFloat64(void); BINARYEN_API BinaryenType BinaryenTypeVec128(void); BINARYEN_API BinaryenType BinaryenTypeFuncref(void); BINARYEN_API BinaryenType BinaryenTypeExternref(void); -BINARYEN_API BinaryenType BinaryenTypeNullref(void); BINARYEN_API BinaryenType BinaryenTypeExnref(void); BINARYEN_API BinaryenType BinaryenTypeUnreachable(void); // Not a real type. Used as the last parameter to BinaryenBlock to let @@ -826,7 +825,8 @@ BinaryenMemoryFill(BinaryenModuleRef module, BinaryenExpressionRef dest, BinaryenExpressionRef value, BinaryenExpressionRef size); -BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module); +BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module, + BinaryenType type); BINARYEN_API BinaryenExpressionRef BinaryenRefIsNull(BinaryenModuleRef module, BinaryenExpressionRef value); BINARYEN_API BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module, diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 5e6beb4ac66..97ba15c32a3 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -2560,17 +2560,9 @@ switch (op[0]) { default: goto parse_error; } } - case 'n': { - switch (op[1]) { - case 'o': - if (strcmp(op, "nop") == 0) { return makeNop(); } - goto parse_error; - case 'u': - if (strcmp(op, "nullref.pop") == 0) { return makePop(Type::nullref); } - goto parse_error; - default: goto parse_error; - } - } + case 'n': + if (strcmp(op, "nop") == 0) { return makeNop(); } + goto parse_error; case 'r': { switch (op[2]) { case 'f': { diff --git a/src/ir/ExpressionManipulator.cpp b/src/ir/ExpressionManipulator.cpp index 57048b9bd49..6f64ec77b9c 100644 --- a/src/ir/ExpressionManipulator.cpp +++ b/src/ir/ExpressionManipulator.cpp @@ -227,7 +227,9 @@ flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) { builder.makeHost(curr->op, curr->nameOperand, std::move(operands)); return ret; } - Expression* visitRefNull(RefNull* curr) { return builder.makeRefNull(); } + Expression* visitRefNull(RefNull* curr) { + return builder.makeRefNull(curr->type); + } Expression* visitRefIsNull(RefIsNull* curr) { return builder.makeRefIsNull(copy(curr->value)); } diff --git a/src/ir/abstract.h b/src/ir/abstract.h index f706e9972d9..b00537bf59f 100644 --- a/src/ir/abstract.h +++ b/src/ir/abstract.h @@ -103,7 +103,6 @@ inline UnaryOp getUnary(Type type, Op op) { } case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: { @@ -268,7 +267,6 @@ inline BinaryOp getBinary(Type type, Op op) { } case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: { diff --git a/src/ir/properties.h b/src/ir/properties.h index 0c6824e4a1e..61190e01259 100644 --- a/src/ir/properties.h +++ b/src/ir/properties.h @@ -94,7 +94,7 @@ inline Literal getSingleLiteral(const Expression* curr) { if (auto* c = curr->dynCast()) { return c->value; } else if (curr->is()) { - return Literal(Type::nullref); + return Literal::makeNull(curr->type); } else if (auto* c = curr->dynCast()) { return Literal(c->func); } else { diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 057252f78f5..a3d65da5cdf 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -35,7 +35,6 @@ function initializeConstants() { ['v128', 'Vec128'], ['funcref', 'Funcref'], ['externref', 'Externref'], - ['nullref', 'Nullref'], ['exnref', 'Exnref'], ['unreachable', 'Unreachable'], ['auto', 'Auto'] @@ -2058,12 +2057,6 @@ function wrapModule(module, self = {}) { } }; - self['nullref'] = { - 'pop'() { - return Module['_BinaryenPop'](module, Module['nullref']); - } - }; - self['exnref'] = { 'pop'() { return Module['_BinaryenPop'](module, Module['exnref']); @@ -2071,8 +2064,8 @@ function wrapModule(module, self = {}) { }; self['ref'] = { - 'null'() { - return Module['_BinaryenRefNull'](module); + 'null'(type) { + return Module['_BinaryenRefNull'](module, type); }, 'is_null'(value) { return Module['_BinaryenRefIsNull'](module, value); diff --git a/src/literal.h b/src/literal.h index 5c72bf96ccc..923970035a0 100644 --- a/src/literal.h +++ b/src/literal.h @@ -39,7 +39,7 @@ class Literal { int32_t i32; int64_t i64; uint8_t v128[16]; - Name func; // function name for funcref + std::unique_ptr func; // function name for funcref std::unique_ptr exn; }; @@ -66,12 +66,15 @@ class Literal { explicit Literal(const std::array&); explicit Literal(const std::array&); explicit Literal(const std::array&); - explicit Literal(Name func) : func(func), type(Type::funcref) {} + explicit Literal(Name func) : func(new Name(func)), type(Type::funcref) {} explicit Literal(std::unique_ptr exn) : exn(std::move(exn)), type(Type::exnref) {} Literal(const Literal& other); Literal& operator=(const Literal& other); ~Literal() { + if (type == Type::funcref) { + func.~unique_ptr(); + } if (type == Type::exnref) { exn.~unique_ptr(); } @@ -79,6 +82,9 @@ class Literal { bool isConcrete() const { return type != Type::none; } bool isNone() const { return type == Type::none; } + bool isNull() const { + return (type == Type::funcref && !func) || (type == Type::exnref && !exn); + } static Literal makeFromInt32(int32_t x, Type type) { switch (type.getBasic()) { @@ -103,7 +109,11 @@ class Literal { static Literals makeZero(Type type); static Literal makeSingleZero(Type type); - static Literal makeNullref() { return Literal(Type(Type::nullref)); } + static Literal makeNull(Type type) { + assert(type == Type::funcref || type == Type::exnref); + // This creates a literal with null pointer for its func / exn + return Literal(type); + } static Literal makeFuncref(Name func) { return Literal(func.c_str()); } static Literal makeExnref(std::unique_ptr exn) { return Literal(std::move(exn)); @@ -132,11 +142,11 @@ class Literal { } std::array getv128() const; Name getFunc() const { - assert(type == Type::funcref); - return func; + assert(type == Type::funcref && func); + return *func.get(); } const ExceptionPackage& getExceptionPackage() const { - assert(type == Type::exnref); + assert(type == Type::exnref && exn); return *exn.get(); } @@ -503,6 +513,9 @@ class Literals : public SmallVector { struct ExceptionPackage { Name event; Literals values; + bool operator==(const ExceptionPackage& other) const { + return event == other.event && values == other.values; + } }; std::ostream& operator<<(std::ostream& o, wasm::Literal literal); @@ -555,7 +568,6 @@ template<> struct less { return memcmp(a.getv128Ptr(), b.getv128Ptr(), 16) < 0; case wasm::Type::funcref: case wasm::Type::externref: - case wasm::Type::nullref: case wasm::Type::exnref: case wasm::Type::none: case wasm::Type::unreachable: diff --git a/src/parsing.h b/src/parsing.h index a3eab1af3cd..663b901fdce 100644 --- a/src/parsing.h +++ b/src/parsing.h @@ -265,7 +265,6 @@ parseConst(cashew::IString s, Type type, MixedArena& allocator) { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: WASM_UNREACHABLE("unexpected const type"); case Type::none: diff --git a/src/passes/ConstHoisting.cpp b/src/passes/ConstHoisting.cpp index 3cef0773c8e..e3583d3bbfd 100644 --- a/src/passes/ConstHoisting.cpp +++ b/src/passes/ConstHoisting.cpp @@ -96,7 +96,6 @@ struct ConstHoisting : public WalkerPass> { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: { return false; } diff --git a/src/passes/Flatten.cpp b/src/passes/Flatten.cpp index 54da8a86e41..b1e88c9eb2e 100644 --- a/src/passes/Flatten.cpp +++ b/src/passes/Flatten.cpp @@ -210,20 +210,20 @@ struct Flatten // out. The local we created using 'getTempForBreakTarget' returns // the return type of the block this branch is targetting, which may // not be the same with the innermost block's return type. For - // example, - // (block $any (result externref) - // (block (result nullref) + // example, when 'subtype' is a subtype of 'supertype', + // (block $super (result supertype) + // (block (result subtype) // (local.tee $0 - // (br_if $any - // (ref.null) + // (br_if $super + // (produce_subtype_value) ;; pseudo instruction // (i32.const 0) // ) // ) // ) // ) - // In this case we need two locals to store (ref.null); one with - // externref type that's for the target block ($label0) and one more - // with nullref type in case for flowing out. Here we create the + // In this case we need two locals to store (produce_subtype_value); + // one with supertype that's for the target block ($super) and one + // more with subtype in case for flowing out. Here we create the // second 'flowing out' local in case two block's types are // different. if (type != blockType) { diff --git a/src/passes/FuncCastEmulation.cpp b/src/passes/FuncCastEmulation.cpp index 13fb8998851..160895f23be 100644 --- a/src/passes/FuncCastEmulation.cpp +++ b/src/passes/FuncCastEmulation.cpp @@ -67,7 +67,6 @@ static Expression* toABI(Expression* value, Module* module) { } case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: { WASM_UNREACHABLE("reference types cannot be converted to i64"); } @@ -111,7 +110,6 @@ static Expression* fromABI(Expression* value, Type type, Module* module) { } case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: { WASM_UNREACHABLE("reference types cannot be converted from i64"); } diff --git a/src/passes/InstrumentLocals.cpp b/src/passes/InstrumentLocals.cpp index f95d169e96c..ee288c103b2 100644 --- a/src/passes/InstrumentLocals.cpp +++ b/src/passes/InstrumentLocals.cpp @@ -58,7 +58,6 @@ Name get_f32("get_f32"); Name get_f64("get_f64"); Name get_funcref("get_funcref"); Name get_externref("get_externref"); -Name get_nullref("get_nullref"); Name get_exnref("get_exnref"); Name get_v128("get_v128"); @@ -68,7 +67,6 @@ Name set_f32("set_f32"); Name set_f64("set_f64"); Name set_funcref("set_funcref"); Name set_externref("set_externref"); -Name set_nullref("set_nullref"); Name set_exnref("set_exnref"); Name set_v128("set_v128"); @@ -98,9 +96,6 @@ struct InstrumentLocals : public WalkerPass> { case Type::externref: import = get_externref; break; - case Type::nullref: - import = get_nullref; - break; case Type::exnref: import = get_exnref; break; @@ -147,9 +142,6 @@ struct InstrumentLocals : public WalkerPass> { case Type::externref: import = set_externref; break; - case Type::nullref: - import = set_nullref; - break; case Type::exnref: import = set_exnref; break; @@ -192,14 +184,6 @@ struct InstrumentLocals : public WalkerPass> { set_externref, {Type::i32, Type::i32, Type::externref}, Type::externref); - addImport(curr, - get_nullref, - {Type::i32, Type::i32, Type::nullref}, - Type::nullref); - addImport(curr, - set_nullref, - {Type::i32, Type::i32, Type::nullref}, - Type::nullref); } if (curr->features.hasExceptionHandling()) { addImport( diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp index 695b62ab200..55cad8d2115 100644 --- a/src/passes/Precompute.cpp +++ b/src/passes/Precompute.cpp @@ -134,9 +134,13 @@ struct Precompute curr->finalize(); return; } - } else if (singleValue.type == Type::nullref && - curr->value->template is()) { - return; + } else if (singleValue.isNull()) { + if (auto *n = curr->value->template dynCast()) { + n->type = singleValue.type; + n->finalize(); + curr->finalize(); + return; + } } else if (singleValue.type == Type::funcref) { if (auto* r = curr->value->template dynCast()) { r->func = singleValue.getFunc(); diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index f35f0d6261d..3533f1193b9 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -1957,6 +1957,19 @@ struct PrintSExpression : public OverriddenVisitor { void visitRefNull(RefNull* curr) { o << '('; PrintExpressionContents(currFunction, o).visit(curr); + switch (curr->type.getBasic()) { + case Type::externref: + o << " extern"; + break; + case Type::funcref: + o << " func"; + break; + case Type::exnref: + o << " exn"; + break; + default: + WASM_UNREACHABLE("ref.null's argument should be a reference type"); + } o << ')'; } void visitRefIsNull(RefIsNull* curr) { diff --git a/src/shell-interface.h b/src/shell-interface.h index a32ae6344fb..e41ceb47da9 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -117,9 +117,9 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { assert(false && "v128 not implemented yet"); case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: - globals[import->name] = {Literal::makeNullref()}; + globals[import->name] = { + Literal::makeNull(import->type.getBasic())}; break; case Type::none: case Type::unreachable: diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index b3c1212d4c9..456ee9c5338 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -313,24 +313,9 @@ class TranslateToFuzzReader { } return Type(types); } - SmallVector options; - options.push_back(type); // includes itself - TODO_SINGLE_COMPOUND(type); - switch (type.getBasic()) { - case Type::externref: - if (wasm.features.hasExceptionHandling()) { - options.push_back(Type::exnref); - } - options.push_back(Type::funcref); - // falls through - case Type::funcref: - case Type::exnref: - options.push_back(Type::nullref); - break; - default: - break; - } - return pick(options); + // Currently reference types proposal doesn't have any subtype relationship, + // so return itself. This can change later when we add more subtypes. + return type; } void setupMemory() { @@ -1362,7 +1347,6 @@ class TranslateToFuzzReader { } case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1466,7 +1450,6 @@ class TranslateToFuzzReader { } case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1595,7 +1578,6 @@ class TranslateToFuzzReader { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1640,7 +1622,6 @@ class TranslateToFuzzReader { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1708,7 +1689,6 @@ class TranslateToFuzzReader { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1735,7 +1715,6 @@ class TranslateToFuzzReader { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1763,7 +1742,7 @@ class TranslateToFuzzReader { } return builder.makeRefFunc(target->name); } - return builder.makeRefNull(); + return builder.makeRefNull(type); } if (type.isTuple()) { std::vector operands; @@ -1845,7 +1824,6 @@ class TranslateToFuzzReader { } case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: return makeTrivial(type); case Type::none: @@ -1990,7 +1968,6 @@ class TranslateToFuzzReader { } case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -2227,7 +2204,6 @@ class TranslateToFuzzReader { } case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -2434,7 +2410,6 @@ class TranslateToFuzzReader { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -2612,10 +2587,9 @@ class TranslateToFuzzReader { assert(wasm.features.hasReferenceTypes()); Type refType; if (wasm.features.hasExceptionHandling()) { - refType = - pick(Type::funcref, Type::externref, Type::nullref, Type::exnref); + refType = pick(Type::funcref, Type::externref, Type::exnref); } else { - refType = pick(Type::funcref, Type::externref, Type::nullref); + refType = pick(Type::funcref, Type::externref); } return builder.makeRefIsNull(make(refType)); } @@ -2682,8 +2656,7 @@ class TranslateToFuzzReader { .add(FeatureSet::SIMD, Type::v128) .add(FeatureSet::ReferenceTypes, Type::funcref, - Type::externref, - Type::nullref) + Type::externref) .add(FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling, Type::exnref)); } @@ -2732,7 +2705,6 @@ class TranslateToFuzzReader { FeatureOptions() .add(FeatureSet::MVP, Type::i32, Type::i64, Type::f32, Type::f64) .add(FeatureSet::SIMD, Type::v128) - .add(FeatureSet::ReferenceTypes, Type::nullref) .add(FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling, Type::exnref)); } diff --git a/src/tools/spec-wrapper.h b/src/tools/spec-wrapper.h index 44f92b56d33..c073a994cc8 100644 --- a/src/tools/spec-wrapper.h +++ b/src/tools/spec-wrapper.h @@ -50,10 +50,13 @@ static std::string generateSpecWrapper(Module& wasm) { ret += "(v128.const i32x4 0 0 0 0)"; break; case Type::funcref: + ret += "(ref.null func)"; + break; case Type::externref: - case Type::nullref: + ret += "(ref.null extern)"; + break; case Type::exnref: - ret += "(ref.null)"; + ret += "(ref.null exn)"; break; case Type::none: case Type::unreachable: diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp index 9c9978b6354..38d89bd5aef 100644 --- a/src/tools/wasm-reduce.cpp +++ b/src/tools/wasm-reduce.cpp @@ -597,7 +597,6 @@ struct Reducer case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: continue; // not implemented yet case Type::none: @@ -623,7 +622,6 @@ struct Reducer case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: continue; // not implemented yet case Type::none: @@ -649,7 +647,6 @@ struct Reducer case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: continue; // not implemented yet case Type::none: @@ -675,7 +672,6 @@ struct Reducer case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: continue; // not implemented yet case Type::none: @@ -687,7 +683,6 @@ struct Reducer case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: continue; // not implemented yet case Type::none: @@ -1016,7 +1011,7 @@ struct Reducer } // try to replace with a trivial value if (curr->type.isRef()) { - RefNull* n = builder->makeRefNull(); + RefNull* n = builder->makeRefNull(curr->type); return tryToReplaceCurrent(n); } if (curr->type.isTuple()) { diff --git a/src/wasm-binary.h b/src/wasm-binary.h index ab9ee515250..c7a401cba9e 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -347,8 +347,6 @@ enum EncodedType { funcref = -0x10, // 0x70 // opaque host reference type externref = -0x11, // 0x6f - // null reference type - nullref = -0x12, // 0x6e // exception reference type exnref = -0x18, // 0x68 // func_type form @@ -968,9 +966,6 @@ inline S32LEB binaryType(Type type) { case Type::externref: ret = BinaryConsts::EncodedType::externref; break; - case Type::nullref: - ret = BinaryConsts::EncodedType::nullref; - break; case Type::exnref: ret = BinaryConsts::EncodedType::exnref; break; diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 4e94da090f5..ff98d6a4499 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -528,8 +528,10 @@ class Builder { ret->finalize(); return ret; } - RefNull* makeRefNull() { + RefNull* makeRefNull(Type type) { + assert(type.isRef()); auto* ret = allocator.alloc(); + ret->type = type; ret->finalize(); return ret; } @@ -624,13 +626,11 @@ class Builder { Expression* makeConstantExpression(Literal value) { TODO_SINGLE_COMPOUND(value.type); switch (value.type.getBasic()) { - case Type::nullref: - return makeRefNull(); case Type::funcref: if (value.getFunc()[0] != 0) { return makeRefFunc(value.getFunc()); } - return makeRefNull(); + return makeRefNull(Type::funcref); default: assert(value.type.isNumber()); return makeConst(value); @@ -822,7 +822,6 @@ class Builder { } case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: return ExpressionManipulator::refNull(curr); case Type::none: diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index baeda061290..6021eeb2f7b 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1242,7 +1242,7 @@ class ExpressionRunner : public OverriddenVisitor { Flow visitPop(Pop* curr) { WASM_UNREACHABLE("unimp"); } Flow visitRefNull(RefNull* curr) { NOTE_ENTER("RefNull"); - return Literal::makeNullref(); + return Literal::makeNull(curr->type); } Flow visitRefIsNull(RefIsNull* curr) { NOTE_ENTER("RefIsNull"); @@ -1252,7 +1252,7 @@ class ExpressionRunner : public OverriddenVisitor { } Literal value = flow.getSingleValue(); NOTE_EVAL1(value); - return Literal(value.type == Type::nullref); + return Literal(value.isNull()); } Flow visitRefFunc(RefFunc* curr) { NOTE_ENTER("RefFunc"); @@ -1282,7 +1282,7 @@ class ExpressionRunner : public OverriddenVisitor { if (flow.breaking()) { return flow; } - if (flow.getType() == Type::nullref) { + if (flow.getSingleValue().isNull()) { trap("rethrow: argument is null"); } throwException(flow.getSingleValue()); @@ -1294,7 +1294,7 @@ class ExpressionRunner : public OverriddenVisitor { if (flow.breaking()) { return flow; } - if (flow.getType() == Type::nullref) { + if (flow.getSingleValue().isNull()) { trap("br_on_exn: argument is null"); } const ExceptionPackage& ex = flow.getSingleValue().getExceptionPackage(); @@ -1644,7 +1644,6 @@ template class ModuleInstanceBase { return Literal(load128(addr).data()); case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1701,7 +1700,6 @@ template class ModuleInstanceBase { break; case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: diff --git a/src/wasm-type.h b/src/wasm-type.h index 8a9e58ec975..8c68da7a7fd 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -49,7 +49,6 @@ class Type { v128, funcref, externref, - nullref, exnref, _last_basic_id = exnref }; @@ -93,7 +92,6 @@ class Type { // │ anyref ║ x │ │ x │ x │ f? n │ │ ┐ // │ eqref ║ x │ │ x │ x │ n │ │ │ TODO (GC) // │ i31ref ║ x │ │ x │ x │ │ │ ┘ - // │ nullref ║ x │ │ x │ x │ f? n │ │ ◄ TODO (removed) // │ exnref ║ x │ │ x │ x │ n │ │ // ├─ Compound ──╫───┼───┼───┼───┤───────┤ │ // │ Ref ║ │ x │ x │ x │ f? n? │◄┘ diff --git a/src/wasm.h b/src/wasm.h index 3d658d3670e..cf17d4cf8ae 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -1090,11 +1090,9 @@ class Pop : public SpecificExpression { }; class RefNull : public SpecificExpression { -public: +public : RefNull() = default; RefNull(MixedArena& allocator) {} - - void finalize(); }; class RefIsNull : public SpecificExpression { diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index ffb007cf3a2..00592cec48f 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -51,13 +51,12 @@ Literal& Literal::operator=(const Literal& other) { memcpy(&v128, other.v128, 16); break; case Type::funcref: - func = other.func; + new (&func) auto(std::make_unique(*other.func)); break; case Type::exnref: new (&exn) auto(std::make_unique(*other.exn)); break; case Type::none: - case Type::nullref: break; case Type::externref: case Type::unreachable: @@ -111,7 +110,7 @@ Literals Literal::makeZero(Type type) { Literal Literal::makeSingleZero(Type type) { assert(type.isSingle()); if (type.isRef()) { - return makeNullref(); + return makeNull(type); } else { return makeFromInt32(0, type); } @@ -190,8 +189,6 @@ void Literal::getBits(uint8_t (&buf)[16]) const { memcpy(buf, &v128, sizeof(v128)); break; case Type::funcref: - case Type::nullref: - break; case Type::externref: case Type::exnref: case Type::none: @@ -201,22 +198,22 @@ void Literal::getBits(uint8_t (&buf)[16]) const { } bool Literal::operator==(const Literal& other) const { - if (type.isRef() && other.type.isRef()) { - if (type == Type::nullref && other.type == Type::nullref) { - return true; - } - if (type == Type::funcref && other.type == Type::funcref && - func == other.func) { - return true; - } - return false; - } if (type != other.type) { return false; } if (type == Type::none) { return true; } + if (type.isRef() && other.type.isRef()) { + if (type == Type::funcref && other.type == Type::funcref) { + return (isNull() && other.isNull() )|| (getFunc() == other.getFunc()); + } + if (type == Type::exnref && other.type == Type::exnref) { + return (isNull() && other.isNull()) || + (getExceptionPackage() == other.getExceptionPackage()); + } + return false; + } uint8_t bits[16], other_bits[16]; getBits(bits); other.getBits(other_bits); @@ -342,9 +339,6 @@ std::ostream& operator<<(std::ostream& o, Literal literal) { case Type::funcref: o << "funcref(" << literal.getFunc() << ")"; break; - case Type::nullref: - o << "nullref"; - break; case Type::exnref: o << "exnref(" << literal.getExceptionPackage() << ")"; break; @@ -572,7 +566,6 @@ Literal Literal::eqz() const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -594,7 +587,6 @@ Literal Literal::neg() const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -616,7 +608,6 @@ Literal Literal::abs() const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -721,7 +712,6 @@ Literal Literal::add(const Literal& other) const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -743,7 +733,6 @@ Literal Literal::sub(const Literal& other) const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -836,7 +825,6 @@ Literal Literal::mul(const Literal& other) const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1090,7 +1078,6 @@ Literal Literal::eq(const Literal& other) const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1112,7 +1099,6 @@ Literal Literal::ne(const Literal& other) const { case Type::v128: case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index ae10687fb02..ffc609f7e23 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -1136,8 +1136,6 @@ Type WasmBinaryBuilder::getType() { return Type::funcref; case BinaryConsts::EncodedType::externref: return Type::externref; - case BinaryConsts::EncodedType::nullref: - return Type::nullref; case BinaryConsts::EncodedType::exnref: return Type::exnref; default: @@ -4689,6 +4687,7 @@ void WasmBinaryBuilder::visitDrop(Drop* curr) { void WasmBinaryBuilder::visitRefNull(RefNull* curr) { BYN_TRACE("zz node: RefNull\n"); + curr->type = getType(); curr->finalize(); } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 931cd1bf0d6..473a8124fef 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -869,9 +869,6 @@ Type SExpressionWasmBuilder::stringToType(const char* str, if (strncmp(str, "externref", 9) == 0 && (prefix || str[9] == 0)) { return Type::externref; } - if (strncmp(str, "nullref", 7) == 0 && (prefix || str[7] == 0)) { - return Type::nullref; - } if (strncmp(str, "exnref", 6) == 0 && (prefix || str[6] == 0)) { return Type::exnref; } @@ -1779,7 +1776,22 @@ Expression* SExpressionWasmBuilder::makeReturn(Element& s) { } Expression* SExpressionWasmBuilder::makeRefNull(Element& s) { + std::string errMsg = "ref.null should take a second argument, which is one " + "of func, extern, or exn"; + if (s.size() != 2) { + throw ParseException(errMsg, s.line, s.col); + } + const char* str = s[1]->c_str(); auto ret = allocator.alloc(); + if (strncmp(str, "func", 4) == 0 && str[4] == 0) { + ret->type = Type::funcref; + } else if (strncmp(str, "extern", 6) == 0 && str[6] == 0) { + ret->type = Type::externref; + } else if (strncmp(str, "exn", 4) == 0 && str[3] == 0) { + ret->type = Type::exnref; + } else { + throw ParseException(errMsg, s[1]->line, s[1]->col); + } ret->finalize(); return ret; } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 88f90378c76..49de76256c5 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -190,7 +190,6 @@ void BinaryInstWriter::visitLoad(Load* curr) { return; case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: WASM_UNREACHABLE("unexpected type"); @@ -292,7 +291,6 @@ void BinaryInstWriter::visitStore(Store* curr) { break; case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -695,7 +693,6 @@ void BinaryInstWriter::visitConst(Const* curr) { } case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -1686,7 +1683,7 @@ void BinaryInstWriter::visitHost(Host* curr) { } void BinaryInstWriter::visitRefNull(RefNull* curr) { - o << int8_t(BinaryConsts::RefNull); + o << int8_t(BinaryConsts::RefNull) << binaryType(curr->type); } void BinaryInstWriter::visitRefIsNull(RefIsNull* curr) { diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index e46cb58866c..c147b14bdb3 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -260,7 +260,6 @@ std::unordered_map indices = { // * `(ref null any) == anyref` // * `(ref null eq) == eqref` // * `(ref i31) == i31ref` - {TypeInfo({Type::nullref}), Type::nullref}, // TODO (removed) {TypeInfo({Type::exnref}), Type::exnref}, {TypeInfo(HeapType(HeapType::ExnKind), true), Type::exnref}, }; @@ -389,7 +388,6 @@ unsigned Type::getByteSize() const { return 16; case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: case Type::unreachable: @@ -432,7 +430,6 @@ FeatureSet Type::getFeatures() const { return FeatureSet::SIMD; case Type::funcref: case Type::externref: - case Type::nullref: return FeatureSet::ReferenceTypes; case Type::exnref: return FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling; @@ -468,13 +465,12 @@ Type Type::get(unsigned byteSize, bool float_) { } bool Type::isSubType(Type left, Type right) { + // Currently reference types proposal doesn't have any subtype relationship, + // so single type A is a subtype of B only if they are the same type. This + // can change later when we add more subtypes. if (left == right) { return true; } - if (left.isRef() && right.isRef() && - (right == Type::externref || left == Type::nullref)) { - return true; - } if (left.isTuple() && right.isTuple()) { if (left.size() != right.size()) { return false; @@ -513,16 +509,10 @@ Type Type::getLeastUpperBound(Type a, Type b) { } return Type(types); } - if (!a.isRef() || !b.isRef()) { - return Type::none; - } - if (a == Type::nullref) { - return b; - } - if (b == Type::nullref) { - return a; - } - return Type::externref; + // Currently reference types proposal doesn't have any subtype relationship, + // so at this point we return none. This will change when we add subtype + // relationship between types. + return Type::none; } Type::Iterator Type::end() const { @@ -708,9 +698,6 @@ std::ostream& operator<<(std::ostream& os, Type type) { case Type::externref: os << "externref"; break; - case Type::nullref: - os << "nullref"; - break; case Type::exnref: os << "exnref"; break; diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 8410cc0b217..08eaae3987f 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -313,6 +313,7 @@ struct FunctionValidator : public WalkerPass> { void visitDrop(Drop* curr); void visitReturn(Return* curr); void visitHost(Host* curr); + void visitRefNull(RefNull* curr); void visitRefIsNull(RefIsNull* curr); void visitRefFunc(RefFunc* curr); void visitTry(Try* curr); @@ -1265,7 +1266,6 @@ void FunctionValidator::validateMemBytes(uint8_t bytes, break; case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: WASM_UNREACHABLE("unexpected type"); @@ -1820,6 +1820,13 @@ void FunctionValidator::visitHost(Host* curr) { } } +void FunctionValidator::visitRefNull(RefNull* curr) { + shouldBeTrue(curr->type == Type::funcref || curr->type == Type::externref || + curr->type == Type::exnref, + curr, + "ref.null's type should be one of func|extern}exn"); +} + void FunctionValidator::visitRefIsNull(RefIsNull* curr) { shouldBeTrue(curr->value->type == Type::unreachable || curr->value->type.isRef(), @@ -2075,7 +2082,6 @@ void FunctionValidator::validateAlignment( break; case Type::funcref: case Type::externref: - case Type::nullref: case Type::exnref: case Type::none: WASM_UNREACHABLE("invalid type"); diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 387ea577fea..996fd35212d 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -210,7 +210,7 @@ Literal getSingleLiteralFromConstExpression(Expression* curr) { if (auto* c = curr->dynCast()) { return c->value; } else if (curr->is()) { - return Literal::makeNullref(); + return Literal::makeNull(curr->type); } else if (auto* r = curr->dynCast()) { return Literal::makeFuncref(r->func); } else { @@ -896,8 +896,6 @@ void Host::finalize() { } } -void RefNull::finalize() { type = Type::nullref; } - void RefIsNull::finalize() { if (value->type == Type::unreachable) { type = Type::unreachable; diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js index 93ed273340b..9751024afd5 100644 --- a/test/binaryen.js/kitchen-sink.js +++ b/test/binaryen.js/kitchen-sink.js @@ -563,7 +563,6 @@ function test_core() { module.v128.pop(), module.externref.pop(), module.funcref.pop(), - module.nullref.pop(), module.exnref.pop(), // TODO: Host module.nop(), diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c index b1dbae7d53b..97eca45f867 100644 --- a/test/example/c-api-kitchen-sink.c +++ b/test/example/c-api-kitchen-sink.c @@ -205,12 +205,6 @@ void test_types() { BinaryenTypeExpand(externref, &valueType); assert(valueType == externref); - BinaryenType nullref = BinaryenTypeNullref(); - printf(" // BinaryenTypeNullref: %d\n", nullref); - assert(BinaryenTypeArity(nullref) == 1); - BinaryenTypeExpand(nullref, &valueType); - assert(valueType == nullref); - BinaryenType exnref = BinaryenTypeExnref(); printf(" // BinaryenTypeExnref: %d\n", exnref); assert(BinaryenTypeArity(exnref) == 1); @@ -294,7 +288,9 @@ void test_core() { temp10 = makeInt32(module, 1), temp11 = makeInt32(module, 3), temp12 = makeInt32(module, 5), temp13 = makeInt32(module, 10), temp14 = makeInt32(module, 11), temp15 = makeInt32(module, 110), temp16 = makeInt64(module, 111); - BinaryenExpressionRef nullrefExpr = BinaryenRefNull(module); + BinaryenExpressionRef nullExternExpr = BinaryenRefNull(module, BinaryenTypeExternref()); + BinaryenExpressionRef nullFuncExpr = BinaryenRefNull(module, BinaryenTypeFuncref()); + BinaryenExpressionRef nullExnExpr = BinaryenRefNull(module, BinaryenTypeExnref()); BinaryenExpressionRef funcrefExpr = BinaryenRefFunc(module, "kitchen()sinker"); @@ -718,10 +714,12 @@ void test_core() { iIfF, BinaryenTypeInt32()), // Reference types - BinaryenRefIsNull(module, nullrefExpr), + BinaryenRefIsNull(module, nullExternExpr), + BinaryenRefIsNull(module, nullFuncExpr), + BinaryenRefIsNull(module, nullExnExpr), BinaryenRefIsNull(module, funcrefExpr), BinaryenSelect( - module, temp10, nullrefExpr, funcrefExpr, BinaryenTypeFuncref()), + module, temp10, nullFuncExpr, funcrefExpr, BinaryenTypeFuncref()), // Exception handling BinaryenTry(module, tryBody, catchBody), // Atomics @@ -746,12 +744,8 @@ void test_core() { BinaryenPop(module, BinaryenTypeInt64()), BinaryenPop(module, BinaryenTypeFloat32()), BinaryenPop(module, BinaryenTypeFloat64()), - BinaryenPop(module, BinaryenTypeFuncref()), BinaryenPop(module, BinaryenTypeExternref()), - BinaryenPop(module, BinaryenTypeNullref()), - BinaryenPop(module, BinaryenTypeExnref()), BinaryenPop(module, BinaryenTypeFuncref()), - BinaryenPop(module, BinaryenTypeNullref()), BinaryenPop(module, BinaryenTypeExnref()), // TODO: Host diff --git a/test/multivalue.wast b/test/multivalue.wast index 01e1237f37f..3923a0eea3c 100644 --- a/test/multivalue.wast +++ b/test/multivalue.wast @@ -129,17 +129,17 @@ ) ) (func $mv-if (result i32 i64 externref) - (if (result i32 i64 nullref) + (if (result i32 i64 externref) (i32.const 1) (tuple.make (i32.const 42) (i64.const 42) - (ref.null) + (ref.null extern) ) (tuple.make (i32.const 42) (i64.const 42) - (ref.null) + (ref.null extern) ) ) ) @@ -164,4 +164,4 @@ ) ) ) -) \ No newline at end of file +) diff --git a/test/passes/dce_all-features.wast b/test/passes/dce_all-features.wast index 77e781097b8..8a33f975d6f 100644 --- a/test/passes/dce_all-features.wast +++ b/test/passes/dce_all-features.wast @@ -779,7 +779,7 @@ (func $throw (drop - (block $label$0 (result nullref) + (block $label$0 (result externref) (if (i32.clz (block $label$1 (result i32) @@ -788,25 +788,25 @@ ) (nop) ) - (ref.null) + (ref.null extern) ) ) ) (func $rethrow (drop - (block $label$0 (result nullref) + (block $label$0 (result externref) (if (i32.clz (block $label$1 (result i32) (rethrow - (ref.null) + (ref.null extern) ) ) ) (nop) ) - (ref.null) + (ref.null extern) ) ) ) diff --git a/test/passes/merge-locals_all-features.wast b/test/passes/merge-locals_all-features.wast index 2a0a3d2922d..c47dfd12510 100644 --- a/test/passes/merge-locals_all-features.wast +++ b/test/passes/merge-locals_all-features.wast @@ -375,17 +375,5 @@ ) ) ) - (func $subtype-test - (local $0 externref) - (local $1 nullref) - (local $2 nullref) - (local.set $0 - (local.get $1) - ) - (local.set $2 - ;; This should NOT become $0, because types of $0 and $1 are different - (local.get $1) - ) - ) ) diff --git a/test/passes/precompute_all-features.wast b/test/passes/precompute_all-features.wast index 343b01ff144..24ebeced9f4 100644 --- a/test/passes/precompute_all-features.wast +++ b/test/passes/precompute_all-features.wast @@ -385,13 +385,13 @@ ) ;; Check if Precompute pass does not crash on reference types - (func $reftype-test (result nullref) - (ref.null) + (func $reftype-test (result externref) + (ref.null extern) ) ;; Check if constant nodes (const, ref.null, and ref.func) are correctly ;; reused. (We shouldn't reuse a const node for something like ref.null, which - ;; will incorrectly cause an expression like 'nullref.const'.) + ;; will incorrectly cause an expression like 'funcref.const'.) (func $dummy) (func $br_reuse_node (drop @@ -418,7 +418,7 @@ ) (drop - (block $l2 (result nullref) + (block $l2 (result externref) (drop (block $l3 (result i32) (global.set $global-mut @@ -428,14 +428,14 @@ (i32.const 1) (ref.is_null (br_if $l2 - (ref.null) + (ref.null extern) (i32.const 3) ) ) ) ) ) - (ref.null) + (ref.null extern) ) ) @@ -457,7 +457,7 @@ ) ) ) - (ref.null) + (ref.null func) ) ) ) @@ -469,7 +469,7 @@ (block $label$1 (drop (br_on_exn $label$1 $event$0 - (loop $label$2 (result nullref) + (loop $label$2 (result externref) (br $label$2) ) ) diff --git a/test/reference-types.wast b/test/reference-types.wast index 8bea4e8e418..53cca8ffcce 100644 --- a/test/reference-types.wast +++ b/test/reference-types.wast @@ -1,88 +1,60 @@ -;; reftype :: externref | funcref | exnref | nullref - -;; t <: externref for all reftypes t -;; nullref <: externref, nullref <: funcref and nullref <: exnref -;; TODO: the subtyping relationship has been removed from the current proposal -;; so it also needs to be removed from Binaryen still both in the tests but -;; also inside the validation, fuzzing, etc. -;; https://github.com/WebAssembly/reference-types/pull/87 +;; reftype :: externref | funcref | exnref (module (type $sig_externref (func (param externref))) (type $sig_funcref (func (param funcref))) (type $sig_exnref (func (param exnref))) - (type $sig_nullref (func (param nullref))) (func $take_externref (param externref)) (func $take_funcref (param funcref)) (func $take_exnref (param exnref)) - (func $take_nullref (param nullref)) (func $foo) - (table funcref (elem $take_externref $take_funcref $take_exnref $take_nullref)) + (table funcref (elem $take_externref $take_funcref $take_exnref)) (import "env" "import_func" (func $import_func (param externref) (result funcref))) (import "env" "import_global" (global $import_global externref)) (export "export_func" (func $import_func (param externref) (result funcref))) (export "export_global" (global $import_global)) - ;; Test subtype relationship in global initializer expressions - (global $global_externref (mut externref) (ref.null)) - (global $global_funcref (mut funcref) (ref.null)) - (global $global_exnref (mut exnref) (ref.null)) - (global $global_nullref (mut nullref) (ref.null)) - (global $global_externref2 (mut externref) (ref.func $foo)) + ;; Global initializer expressions + (global $global_externref (mut externref) (ref.null extern)) + (global $global_funcref (mut funcref) (ref.null func)) (global $global_funcref2 (mut funcref) (ref.func $foo)) + (global $global_exnref (mut exnref) (ref.null exn)) (func $test (local $local_externref externref) (local $local_funcref funcref) - (local $local_exnref exnref) (local $local_nullref nullref) - ;; Test subtype relationship for local.set & Test types for local.get + (local $local_exnref exnref) + ;; local.set / local.get (local.set $local_externref (local.get $local_externref)) - (local.set $local_externref (local.get $local_funcref)) - (local.set $local_externref (local.get $local_exnref)) - (local.set $local_externref (local.get $local_nullref)) - (local.set $local_externref (ref.null)) - (local.set $local_externref (ref.func $foo)) + (local.set $local_externref (ref.null extern)) (local.set $local_funcref (local.get $local_funcref)) - (local.set $local_funcref (ref.null)) + (local.set $local_funcref (ref.null func)) (local.set $local_funcref (ref.func $foo)) (local.set $local_exnref (local.get $local_exnref)) - (local.set $local_exnref (ref.null)) - (local.set $local_nullref (local.get $local_nullref)) - (local.set $local_nullref (ref.null)) + (local.set $local_exnref (ref.null exn)) - ;; Test subtype relationship for global.set & Test types for global.get + ;; global.set / global.get (global.set $global_externref (global.get $global_externref)) - (global.set $global_externref (global.get $global_funcref)) - (global.set $global_externref (global.get $global_exnref)) - (global.set $global_externref (global.get $global_nullref)) - (global.set $global_externref (ref.null)) - (global.set $global_externref (ref.func $foo)) + (global.set $global_externref (ref.null extern)) (global.set $global_funcref (global.get $global_funcref)) - (global.set $global_funcref (ref.null)) + (global.set $global_funcref (ref.null func)) (global.set $global_funcref (ref.func $foo)) (global.set $global_exnref (global.get $global_exnref)) - (global.set $global_exnref (ref.null)) - (global.set $global_nullref (global.get $global_nullref)) - (global.set $global_nullref (ref.null)) + (global.set $global_exnref (ref.null exn)) - ;; Test subtype relationship for function call / call_indirect params + ;; Function call / call_indirect params (call $take_externref (local.get $local_externref)) - (call $take_externref (local.get $local_funcref)) - (call $take_externref (local.get $local_exnref)) - (call $take_externref (ref.null)) + (call $take_externref (ref.null extern)) (call_indirect (type $sig_externref) (local.get $local_externref) (i32.const 0)) - (call_indirect (type $sig_externref) (local.get $local_funcref) (i32.const 0)) - (call_indirect (type $sig_externref) (local.get $local_exnref) (i32.const 0)) - (call_indirect (type $sig_externref) (ref.null) (i32.const 0)) + (call_indirect (type $sig_externref) (ref.null extern) (i32.const 0)) (call_indirect (type $sig_funcref) (local.get $local_funcref) (i32.const 1)) - (call_indirect (type $sig_funcref) (ref.null) (i32.const 1)) + (call_indirect (type $sig_funcref) (ref.null func) (i32.const 1)) + (call_indirect (type $sig_funcref) (ref.func $foo) (i32.const 1)) (call_indirect (type $sig_exnref) (local.get $local_exnref) (i32.const 2)) - (call_indirect (type $sig_exnref) (ref.null) (i32.const 2)) - (call_indirect (type $sig_nullref) (local.get $local_nullref) (i32.const 3)) - (call_indirect (type $sig_nullref) (ref.null) (i32.const 3)) + (call_indirect (type $sig_exnref) (ref.null exn) (i32.const 2)) - ;; Test subtype relationship for block return type + ;; block return type (drop (block (result externref) (br_if 0 (local.get $local_externref) (i32.const 1)) @@ -90,36 +62,36 @@ ) (drop (block (result externref) - (br_if 0 (local.get $local_funcref) (i32.const 1)) + (br_if 0 (ref.null extern) (i32.const 1)) ) ) (drop - (block (result externref) - (br_if 0 (local.get $local_exnref) (i32.const 1)) + (block (result funcref) + (br_if 0 (local.get $local_funcref) (i32.const 1)) ) ) (drop - (block (result externref) - (br_if 0 (ref.null) (i32.const 1)) + (block (result funcref) + (br_if 0 (ref.null func) (i32.const 1)) ) ) (drop (block (result funcref) - (br_if 0 (ref.null) (i32.const 1)) + (br_if 0 (ref.func $foo) (i32.const 1)) ) ) (drop (block (result exnref) - (br_if 0 (ref.null) (i32.const 1)) + (br_if 0 (local.get $local_exnref) (i32.const 1)) ) ) (drop - (block (result nullref) - (br_if 0 (ref.null) (i32.const 1)) + (block (result exnref) + (br_if 0 (ref.null exn) (i32.const 1)) ) ) - ;; Test subtype relationship for loop return type + ;; loop return type (drop (loop (result externref) (local.get $local_externref) @@ -127,27 +99,22 @@ ) (drop (loop (result externref) - (local.get $local_funcref) - ) - ) - (drop - (loop (result externref) - (local.get $local_exnref) + (ref.null extern) ) ) (drop - (loop (result externref) - (ref.null) + (loop (result funcref) + (local.get $local_funcref) ) ) (drop (loop (result funcref) - (local.get $local_funcref) + (ref.null func) ) ) (drop (loop (result funcref) - (ref.null) + (ref.func $foo) ) ) (drop @@ -157,71 +124,42 @@ ) (drop (loop (result exnref) - (ref.null) - ) - ) - (drop - (loop (result nullref) - (ref.null) + (ref.null exn) ) ) - ;; Test subtype relationship for if return type + ;; if return type (drop (if (result externref) (i32.const 1) (local.get $local_externref) - (local.get $local_exnref) - ) - ) - (drop - (if (result externref) - (i32.const 1) - (ref.func $foo) - (ref.null) + (ref.null extern) ) ) (drop (if (result funcref) (i32.const 1) (ref.func $foo) - (ref.null) + (ref.null func) ) ) (drop (if (result exnref) (i32.const 1) (local.get $local_exnref) - (ref.null) - ) - ) - (drop - (if (result nullref) - (i32.const 1) - (local.get $local_nullref) - (ref.null) + (ref.null exn) ) ) - ;; Test subtype relationship for try return type + ;; try return type (drop (try (result externref) (do (local.get $local_externref) ) - (catch - (exnref.pop) - ) - ) - ) - (drop - (try (result externref) - (do - (ref.func $foo) - ) (catch (drop (exnref.pop)) - (ref.null) + (ref.null extern) ) ) ) @@ -232,79 +170,40 @@ ) (catch (drop (exnref.pop)) - (ref.null) + (ref.null func) ) ) ) (drop (try (result exnref) (do - (ref.null) + (ref.null exn) ) (catch (exnref.pop) ) ) ) - (drop - (try (result nullref) - (do - (ref.null) - ) - (catch - (drop (exnref.pop)) - (ref.null) - ) - ) - ) - ;; Test subtype relationship for typed select + ;; Typed select (drop (select (result externref) (local.get $local_externref) - (ref.func $foo) - (i32.const 1) - ) - ) - (drop - (select (result externref) - (local.get $local_exnref) - (local.get $local_externref) - (i32.const 1) - ) - ) - (drop - (select (result externref) - (local.get $local_externref) - (ref.null) - (i32.const 1) - ) - ) - (drop - (select (result externref) - (ref.null) - (ref.func $foo) + (ref.null extern) (i32.const 1) ) ) (drop (select (result funcref) (ref.func $foo) - (ref.null) + (ref.null func) (i32.const 1) ) ) (drop (select (result exnref) - (ref.null) (local.get $local_exnref) - (i32.const 1) - ) - ) - (drop - (select (result nullref) - (ref.null) - (ref.null) + (ref.null exn) (i32.const 1) ) ) @@ -320,56 +219,43 @@ (drop (ref.is_null (local.get $local_externref))) (drop (ref.is_null (local.get $local_exnref))) (drop (ref.is_null (ref.func $foo))) - (drop (ref.is_null (ref.null))) + (drop (ref.is_null (ref.null extern))) + (drop (ref.is_null (ref.null func))) + (drop (ref.is_null (ref.null exn))) ) - ;; Test subtype relationship in function return type + ;; Function return type (func $return_externref (result externref) (local $local_externref externref) (local.get $local_externref) ) (func $return_externref2 (result externref) - (ref.func $foo) - ) - (func $return_externref3 (result externref) (local $local_exnref exnref) - (local.get $local_exnref) - ) - (func $return_externref4 (result externref) - (ref.null) + (ref.null extern) ) (func $return_funcref (result funcref) (ref.func $foo) ) (func $return_funcref2 (result funcref) - (ref.null) + (ref.null func) ) (func $return_exnref (result exnref) (local $local_exnref exnref) (local.get $local_exnref) ) (func $return_exnref2 (result exnref) - (ref.null) - ) - (func $return_nullref (result nullref) (local $local_nullref nullref) - (local.get $local_nullref) + (ref.null exn) ) - ;; Test subtype relationship in returns + ;; Returns (func $return_externref_returns (result externref) (local $local_externref externref) (local $local_exnref exnref) (return (local.get $local_externref)) - (return (local.get $local_exnref)) - (return (ref.func $foo)) - (return (ref.null)) + (return (ref.null extern)) ) (func $return_funcref_returns (result funcref) (return (ref.func $foo)) - (return (ref.null)) + (return (ref.null func)) ) (func $return_exnref_returns (result exnref) (local $local_exnref exnref) (return (local.get $local_exnref)) - (return (ref.null)) - ) - (func $return_nullref_returns (result nullref) (local $local_nullref nullref) - (return (local.get $local_nullref)) - (return (ref.null)) + (return (ref.null exn)) ) )