From 1d615b38dd4152494d2f4d3520c8b1d917624a30 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 8 Dec 2023 15:03:09 -0800 Subject: [PATCH] [EH] Add exnref type back (#6149) At the Oct hybrid CG meeting, we decided to add back `exnref`, which was removed in 2020: https://github.com/WebAssembly/meetings/blob/main/main/2023/CG-10.md The new version of the proposal reflected in the explainer: https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md While adding support for `exnref` in the current codebase which has all GC subtype hierarchies, I noticed we might need `noexn` heap type for the bottom type of `exn`. We don't have it now so I just set it to 0xff for the moment. --- src/binaryen-c.cpp | 4 +++ src/tools/fuzzing/fuzzing.cpp | 14 +++++++- src/tools/fuzzing/heap-types.cpp | 9 +++-- src/wasm-binary.h | 19 +++++++---- src/wasm-type.h | 9 ++++- src/wasm/literal.cpp | 8 +++++ src/wasm/wasm-binary.cpp | 30 ++++++++++++++++ src/wasm/wasm-s-parser.cpp | 15 ++++++++ src/wasm/wasm-type.cpp | 34 +++++++++++++++++++ test/example/c-api-kitchen-sink.txt | 14 ++++---- test/exception-handling.wast | 18 ++++++++++ test/exception-handling.wast.from-wast | 14 ++++++++ test/exception-handling.wast.fromBinary | 14 ++++++++ ...ption-handling.wast.fromBinary.noDebugInfo | 14 ++++++++ 14 files changed, 198 insertions(+), 18 deletions(-) diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index b53f5fd0c11..c273a3af42e 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -87,6 +87,7 @@ BinaryenLiteral toBinaryenLiteral(Literal x) { case HeapType::func: case HeapType::struct_: case HeapType::array: + case HeapType::exn: WASM_UNREACHABLE("invalid type"); case HeapType::string: case HeapType::stringview_wtf8: @@ -96,6 +97,7 @@ BinaryenLiteral toBinaryenLiteral(Literal x) { case HeapType::none: case HeapType::noext: case HeapType::nofunc: + case HeapType::noexn: // Null. return ret; } @@ -140,6 +142,7 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) { case HeapType::func: case HeapType::struct_: case HeapType::array: + case HeapType::exn: WASM_UNREACHABLE("invalid type"); case HeapType::string: case HeapType::stringview_wtf8: @@ -149,6 +152,7 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) { case HeapType::none: case HeapType::noext: case HeapType::nofunc: + case HeapType::noexn: assert(type.isNullable()); return Literal::makeNull(heapType); } diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index d9e0f6baf77..07464af9dfd 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -2429,6 +2429,14 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) { HeapType(Array(Field(Field::PackedType::i8, Immutable))); return builder.makeArrayNewFixed(trivialArray, {}); } + case HeapType::exn: { + auto null = builder.makeRefNull(HeapType::ext); + if (!type.isNullable()) { + assert(funcContext); + return builder.makeRefAs(RefAsNonNull, null); + } + return null; + } case HeapType::string: return builder.makeStringConst(std::to_string(upTo(1024))); case HeapType::stringview_wtf8: @@ -2437,7 +2445,8 @@ Expression* TranslateToFuzzReader::makeBasicRef(Type type) { WASM_UNREACHABLE("TODO: strings"); case HeapType::none: case HeapType::noext: - case HeapType::nofunc: { + case HeapType::nofunc: + case HeapType::noexn: { auto null = builder.makeRefNull(heapType); if (!type.isNullable()) { assert(funcContext); @@ -3888,6 +3897,8 @@ HeapType TranslateToFuzzReader::getSubType(HeapType type) { return pick(HeapType::struct_, HeapType::none); case HeapType::array: return pick(HeapType::array, HeapType::none); + case HeapType::exn: + return HeapType::exn; case HeapType::string: return HeapType::string; case HeapType::stringview_wtf8: @@ -3897,6 +3908,7 @@ HeapType TranslateToFuzzReader::getSubType(HeapType type) { case HeapType::none: case HeapType::noext: case HeapType::nofunc: + case HeapType::noexn: break; } } diff --git a/src/tools/fuzzing/heap-types.cpp b/src/tools/fuzzing/heap-types.cpp index 32a3fd960c7..13ad0147450 100644 --- a/src/tools/fuzzing/heap-types.cpp +++ b/src/tools/fuzzing/heap-types.cpp @@ -378,8 +378,6 @@ struct HeapTypeGeneratorImpl { return type.getBottom(); } switch (type.getBasic()) { - case HeapType::ext: - return HeapType::ext; case HeapType::func: return pickSubFunc(); case HeapType::any: @@ -392,6 +390,8 @@ struct HeapTypeGeneratorImpl { return pickSubStruct(); case HeapType::array: return pickSubArray(); + case HeapType::ext: + case HeapType::exn: case HeapType::string: case HeapType::stringview_wtf8: case HeapType::stringview_wtf16: @@ -399,6 +399,7 @@ struct HeapTypeGeneratorImpl { case HeapType::none: case HeapType::noext: case HeapType::nofunc: + case HeapType::noexn: return type; } WASM_UNREACHABLE("unexpected type"); @@ -440,6 +441,7 @@ struct HeapTypeGeneratorImpl { switch (type.getBasic()) { case HeapType::ext: case HeapType::func: + case HeapType::exn: case HeapType::any: break; case HeapType::eq: @@ -464,6 +466,9 @@ struct HeapTypeGeneratorImpl { case HeapType::noext: candidates.push_back(HeapType::ext); break; + case HeapType::noexn: + candidates.push_back(HeapType::exn); + break; } assert(!candidates.empty()); return rand.pick(candidates); diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 752f306fe37..58d641dc949 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -412,6 +412,9 @@ enum EncodedType { nullable = -0x14, // 0x6c nonnullable = -0x15, // 0x6b #endif + // exception handling + exnref = -0x17, // 0x69 + nullexnref = -0xff, // TODO // string reference types #if STANDARD_GC_ENCODINGS stringref = -0x19, // 0x67 @@ -449,14 +452,16 @@ enum EncodedHeapType { noext = -0xe, // 0x72 none = -0xf, // 0x71 #else - noext = -0x17, // 0x69 - nofunc = -0x18, // 0x68 - none = -0x1b, // 0x65 + noext = -0x17, // 0x69 + nofunc = -0x18, // 0x68 + none = -0x1b, // 0x65 #endif - func = -0x10, // 0x70 - ext = -0x11, // 0x6f - any = -0x12, // 0x6e - eq = -0x13, // 0x6d + func = -0x10, // 0x70 + ext = -0x11, // 0x6f + any = -0x12, // 0x6e + eq = -0x13, // 0x6d + exn = -0x17, // 0x69 + noexn = -0xff, // TODO #if STANDARD_GC_ENCODINGS i31 = -0x14, // 0x6c struct_ = -0x15, // 0x6b diff --git a/src/wasm-type.h b/src/wasm-type.h index 573cd9102b3..5c47f405191 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -137,6 +137,9 @@ class Type { // │ eqref ║ x │ │ x │ x │ n │ │ n_ullable // │ i31ref ║ x │ │ x │ x │ n │ │ // │ structref ║ x │ │ x │ x │ n │ │ + // │ arrayref ║ x │ │ x │ x │ n │ │ + // │ exnref ║ x │ │ x │ x │ n │ │ + // │ stringref ║ x │ │ x │ x │ n │ │ // ├─ Compound ──╫───┼───┼───┼───┤───────┤ │ // │ Ref ║ │ x │ x │ x │ f? n? │◄┘ // │ Tuple ║ │ x │ │ x │ │ @@ -167,6 +170,7 @@ class Type { bool isSignature() const; bool isStruct() const; bool isArray() const; + bool isException() const; bool isString() const; bool isDefaultable() const; @@ -322,6 +326,7 @@ class HeapType { i31, struct_, array, + exn, string, stringview_wtf8, stringview_wtf16, @@ -329,8 +334,9 @@ class HeapType { none, noext, nofunc, + noexn, }; - static constexpr BasicHeapType _last_basic_type = nofunc; + static constexpr BasicHeapType _last_basic_type = noexn; // BasicHeapType can be implicitly upgraded to HeapType constexpr HeapType(BasicHeapType id) : id(id) {} @@ -364,6 +370,7 @@ class HeapType { bool isContinuation() const; bool isStruct() const; bool isArray() const; + bool isException() const; bool isString() const; bool isBottom() const; bool isOpen() const; diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 4bae54693ab..7c674ffc516 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -133,12 +133,14 @@ Literal::Literal(const Literal& other) : type(other.type) { case HeapType::none: case HeapType::noext: case HeapType::nofunc: + case HeapType::noexn: WASM_UNREACHABLE("null literals should already have been handled"); case HeapType::any: case HeapType::eq: case HeapType::func: case HeapType::struct_: case HeapType::array: + case HeapType::exn: WASM_UNREACHABLE("invalid type"); case HeapType::string: case HeapType::stringview_wtf8: @@ -613,9 +615,15 @@ std::ostream& operator<<(std::ostream& o, Literal literal) { case HeapType::nofunc: o << "nullfuncref"; break; + case HeapType::noexn: + o << "nullexnref"; + break; case HeapType::ext: o << "externref"; break; + case HeapType::exn: + o << "exnref"; + break; case HeapType::any: case HeapType::eq: case HeapType::func: diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 3c01e5df5ff..be1c27d039a 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -1472,6 +1472,10 @@ void WasmBinaryWriter::writeType(Type type) { o << S32LEB(BinaryConsts::EncodedType::externref); return; } + if (Type::isSubType(type, Type(HeapType::exn, Nullable))) { + o << S32LEB(BinaryConsts::EncodedType::exnref); + return; + } if (Type::isSubType(type, Type(HeapType::string, Nullable))) { o << S32LEB(BinaryConsts::EncodedType::stringref); return; @@ -1502,6 +1506,9 @@ void WasmBinaryWriter::writeType(Type type) { case HeapType::array: o << S32LEB(BinaryConsts::EncodedType::arrayref); return; + case HeapType::exn: + o << S32LEB(BinaryConsts::EncodedType::exnref); + return; case HeapType::string: o << S32LEB(BinaryConsts::EncodedType::stringref); return; @@ -1523,6 +1530,9 @@ void WasmBinaryWriter::writeType(Type type) { case HeapType::nofunc: o << S32LEB(BinaryConsts::EncodedType::nullfuncref); return; + case HeapType::noexn: + o << S32LEB(BinaryConsts::EncodedType::nullexnref); + return; } } if (type.isNullable()) { @@ -1570,6 +1580,8 @@ void WasmBinaryWriter::writeHeapType(HeapType type) { type = HeapType::func; } else if (HeapType::isSubType(type, HeapType::ext)) { type = HeapType::ext; + } else if (HeapType::isSubType(type, HeapType::exn)) { + type = HeapType::exn; } else if (wasm->features.hasStrings()) { // Strings are enabled, and this isn't a func or an ext, so it must be a // string type (string or stringview), which we'll emit below, or a bottom @@ -1609,6 +1621,9 @@ void WasmBinaryWriter::writeHeapType(HeapType type) { case HeapType::array: ret = BinaryConsts::EncodedHeapType::array; break; + case HeapType::exn: + ret = BinaryConsts::EncodedHeapType::exn; + break; case HeapType::string: ret = BinaryConsts::EncodedHeapType::string; break; @@ -1630,6 +1645,9 @@ void WasmBinaryWriter::writeHeapType(HeapType type) { case HeapType::nofunc: ret = BinaryConsts::EncodedHeapType::nofunc; break; + case HeapType::noexn: + ret = BinaryConsts::EncodedHeapType::noexn; + break; } o << S64LEB(ret); // TODO: Actually s33 } @@ -1980,6 +1998,9 @@ bool WasmBinaryReader::getBasicType(int32_t code, Type& out) { case BinaryConsts::EncodedType::arrayref: out = Type(HeapType::array, Nullable); return true; + case BinaryConsts::EncodedType::exnref: + out = Type(HeapType::exn, Nullable); + return true; case BinaryConsts::EncodedType::stringref: out = Type(HeapType::string, Nullable); return true; @@ -2001,6 +2022,9 @@ bool WasmBinaryReader::getBasicType(int32_t code, Type& out) { case BinaryConsts::EncodedType::nullfuncref: out = Type(HeapType::nofunc, Nullable); return true; + case BinaryConsts::EncodedType::nullexnref: + out = Type(HeapType::noexn, Nullable); + return true; default: return false; } @@ -2029,6 +2053,9 @@ bool WasmBinaryReader::getBasicHeapType(int64_t code, HeapType& out) { case BinaryConsts::EncodedHeapType::array: out = HeapType::array; return true; + case BinaryConsts::EncodedHeapType::exn: + out = HeapType::exn; + return true; case BinaryConsts::EncodedHeapType::string: out = HeapType::string; return true; @@ -2050,6 +2077,9 @@ bool WasmBinaryReader::getBasicHeapType(int64_t code, HeapType& out) { case BinaryConsts::EncodedHeapType::nofunc: out = HeapType::nofunc; return true; + case BinaryConsts::EncodedHeapType::noexn: + out = HeapType::noexn; + return true; default: return false; } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 7b415813ec6..9e16d34e6c8 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -1279,6 +1279,9 @@ Type SExpressionWasmBuilder::stringToType(std::string_view str, if (str.substr(0, 8) == "arrayref" && (prefix || str.size() == 8)) { return Type(HeapType::array, Nullable); } + if (str.substr(0, 6) == "exnref" && (prefix || str.size() == 6)) { + return Type(HeapType::exn, Nullable); + } if (str.substr(0, 9) == "stringref" && (prefix || str.size() == 9)) { return Type(HeapType::string, Nullable); } @@ -1300,6 +1303,9 @@ Type SExpressionWasmBuilder::stringToType(std::string_view str, if (str.substr(0, 11) == "nullfuncref" && (prefix || str.size() == 11)) { return Type(HeapType::nofunc, Nullable); } + if (str.substr(0, 10) == "nullexnref" && (prefix || str.size() == 10)) { + return Type(HeapType::noexn, Nullable); + } if (allowError) { return Type::none; } @@ -1330,6 +1336,9 @@ HeapType SExpressionWasmBuilder::stringToHeapType(std::string_view str, if (str.substr(0, 5) == "array" && (prefix || str.size() == 5)) { return HeapType::array; } + if (str.substr(0, 3) == "exn" && (prefix || str.size() == 3)) { + return HeapType::exn; + } if (str.substr(0, 6) == "string" && (prefix || str.size() == 6)) { return HeapType::string; } @@ -1351,6 +1360,12 @@ HeapType SExpressionWasmBuilder::stringToHeapType(std::string_view str, if (str.substr(0, 6) == "nofunc" && (prefix || str.size() == 6)) { return HeapType::nofunc; } + if (str.substr(0, 6) == "nofunc" && (prefix || str.size() == 6)) { + return HeapType::nofunc; + } + if (str.substr(0, 5) == "noexn" && (prefix || str.size() == 5)) { + return HeapType::noexn; + } throw ParseException(std::string("invalid wasm heap type: ") + std::string(str.data(), str.size())); } diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index dce0eb64583..97a8cba0ee2 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -472,6 +472,7 @@ std::optional getBasicHeapTypeLUB(HeapType::BasicHeapType a, switch (a) { case HeapType::ext: case HeapType::func: + case HeapType::exn: return std::nullopt; case HeapType::any: return {HeapType::any}; @@ -500,6 +501,7 @@ std::optional getBasicHeapTypeLUB(HeapType::BasicHeapType a, case HeapType::none: case HeapType::noext: case HeapType::nofunc: + case HeapType::noexn: // Bottom types already handled. break; } @@ -801,6 +803,10 @@ bool Type::isStruct() const { return isRef() && getHeapType().isStruct(); } bool Type::isArray() const { return isRef() && getHeapType().isArray(); } +bool Type::isException() const { + return isRef() && getHeapType().isException(); +} + bool Type::isString() const { return isRef() && getHeapType().isString(); } bool Type::isDefaultable() const { @@ -917,6 +923,11 @@ FeatureSet Type::getFeatures() const { // ref.null with just reference types. feats |= FeatureSet::ReferenceTypes; return; + case HeapType::exn: + case HeapType::noexn: + feats |= + FeatureSet::ExceptionHandling | FeatureSet::ReferenceTypes; + return; } } @@ -1190,6 +1201,8 @@ bool HeapType::isArray() const { } } +bool HeapType::isException() const { return *this == HeapType::exn; } + bool HeapType::isString() const { return *this == HeapType::string; } bool HeapType::isBottom() const { @@ -1202,6 +1215,7 @@ bool HeapType::isBottom() const { case i31: case struct_: case array: + case exn: case string: case stringview_wtf8: case stringview_wtf16: @@ -1210,6 +1224,7 @@ bool HeapType::isBottom() const { case none: case noext: case nofunc: + case noexn: return true; } } @@ -1270,6 +1285,8 @@ std::optional HeapType::getSuperType() const { case nofunc: case any: case none: + case exn: + case noexn: case string: case stringview_wtf8: case stringview_wtf16: @@ -1326,6 +1343,7 @@ size_t HeapType::getDepth() const { case HeapType::ext: case HeapType::func: case HeapType::any: + case HeapType::exn: break; case HeapType::eq: depth++; @@ -1342,6 +1360,7 @@ size_t HeapType::getDepth() const { case HeapType::none: case HeapType::nofunc: case HeapType::noext: + case HeapType::noexn: // Bottom types are infinitely deep. depth = size_t(-1l); } @@ -1356,6 +1375,8 @@ HeapType::BasicHeapType HeapType::getBottom() const { return noext; case func: return nofunc; + case exn: + return noexn; case any: case eq: case i31: @@ -1371,6 +1392,8 @@ HeapType::BasicHeapType HeapType::getBottom() const { return noext; case nofunc: return nofunc; + case noexn: + return noexn; } } auto* info = getHeapTypeInfo(*this); @@ -1672,6 +1695,8 @@ bool SubTyper::isSubType(HeapType a, HeapType b) { return a.getBottom() == HeapType::noext; case HeapType::func: return a.getBottom() == HeapType::nofunc; + case HeapType::exn: + return a.getBottom() == HeapType::noexn; case HeapType::any: return a.getBottom() == HeapType::none; case HeapType::eq: @@ -1692,6 +1717,7 @@ bool SubTyper::isSubType(HeapType a, HeapType b) { case HeapType::none: case HeapType::noext: case HeapType::nofunc: + case HeapType::noexn: return false; } } @@ -1816,6 +1842,8 @@ std::ostream& TypePrinter::print(Type type) { return os << "structref"; case HeapType::array: return os << "arrayref"; + case HeapType::exn: + return os << "exnref"; case HeapType::string: return os << "stringref"; case HeapType::stringview_wtf8: @@ -1830,6 +1858,8 @@ std::ostream& TypePrinter::print(Type type) { return os << "nullexternref"; case HeapType::nofunc: return os << "nullfuncref"; + case HeapType::noexn: + return os << "nullexnref"; } } } @@ -1862,6 +1892,8 @@ std::ostream& TypePrinter::print(HeapType type) { return os << "struct"; case HeapType::array: return os << "array"; + case HeapType::exn: + return os << "exn"; case HeapType::string: return os << "string"; case HeapType::stringview_wtf8: @@ -1876,6 +1908,8 @@ std::ostream& TypePrinter::print(HeapType type) { return os << "noextern"; case HeapType::nofunc: return os << "nofunc"; + case HeapType::noexn: + return os << "noexn"; } } diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt index 2a3ecea9dab..d682285d16f 100644 --- a/test/example/c-api-kitchen-sink.txt +++ b/test/example/c-api-kitchen-sink.txt @@ -30,13 +30,13 @@ BinaryenHeapTypeEq: 3 BinaryenHeapTypeI31: 4 BinaryenHeapTypeStruct: 5 BinaryenHeapTypeArray: 6 -BinaryenHeapTypeString: 7 -BinaryenHeapTypeStringviewWTF8: 8 -BinaryenHeapTypeStringviewWTF16: 9 -BinaryenHeapTypeStringviewIter: 10 -BinaryenHeapTypeNone: 11 -BinaryenHeapTypeNoext: 12 -BinaryenHeapTypeNofunc: 13 +BinaryenHeapTypeString: 8 +BinaryenHeapTypeStringviewWTF8: 9 +BinaryenHeapTypeStringviewWTF16: 10 +BinaryenHeapTypeStringviewIter: 11 +BinaryenHeapTypeNone: 12 +BinaryenHeapTypeNoext: 13 +BinaryenHeapTypeNofunc: 14 BinaryenFeatureMVP: 0 BinaryenFeatureAtomics: 1 BinaryenFeatureBulkMemory: 16 diff --git a/test/exception-handling.wast b/test/exception-handling.wast index d37cc322bef..1a484f9ac96 100644 --- a/test/exception-handling.wast +++ b/test/exception-handling.wast @@ -8,6 +8,9 @@ (func $foo) (func $bar) + ;; --------------------------------------------------------------------------- + ;; Old Phase 3 exception handling + (func $eh-test (local $x (i32 i64)) ;; Simple try-catch (try @@ -365,4 +368,19 @@ ) (nop) ) + + ;; --------------------------------------------------------------------------- + ;; New exception handling + + (func $exnref-test (result exnref) (local $exn exnref) (local $null-exn nullexnref) + (if (result exnref) + (i32.const 1) + (if (result nullexnref) + (i32.const 1) + (local.get $null-exn) + (ref.null noexn) + ) + (local.get $exn) + ) + ) ) diff --git a/test/exception-handling.wast.from-wast b/test/exception-handling.wast.from-wast index da9a1031ee2..7e7bec6ffbe 100644 --- a/test/exception-handling.wast.from-wast +++ b/test/exception-handling.wast.from-wast @@ -4,6 +4,7 @@ (type $2 (func (param i64))) (type $3 (func (param i32 i64))) (type $4 (func (param eqref))) + (type $5 (func (result exnref))) (tag $e-i32 (param i32)) (tag $e-i64 (param i64)) (tag $e-i32-i64 (param i32 i64)) @@ -406,4 +407,17 @@ ) (nop) ) + (func $exnref-test (type $5) (result exnref) + (local $exn exnref) + (local $null-exn nullexnref) + (if (result exnref) + (i32.const 1) + (if (result nullexnref) + (i32.const 1) + (local.get $null-exn) + (ref.null noexn) + ) + (local.get $exn) + ) + ) ) diff --git a/test/exception-handling.wast.fromBinary b/test/exception-handling.wast.fromBinary index e9cfce4092f..93678bc6fdc 100644 --- a/test/exception-handling.wast.fromBinary +++ b/test/exception-handling.wast.fromBinary @@ -4,6 +4,7 @@ (type $2 (func (param i64))) (type $3 (func (param i32 i64))) (type $4 (func (param eqref))) + (type $5 (func (result exnref))) (tag $e-i32 (param i32)) (tag $e-i64 (param i64)) (tag $e-i32-i64 (param i32 i64)) @@ -428,5 +429,18 @@ ) (nop) ) + (func $exnref-test (type $5) (result exnref) + (local $exn exnref) + (local $null-exn nullexnref) + (if (result exnref) + (i32.const 1) + (if (result nullexnref) + (i32.const 1) + (local.get $null-exn) + (ref.null noexn) + ) + (local.get $exn) + ) + ) ) diff --git a/test/exception-handling.wast.fromBinary.noDebugInfo b/test/exception-handling.wast.fromBinary.noDebugInfo index 4bc460630ae..beea8498bd3 100644 --- a/test/exception-handling.wast.fromBinary.noDebugInfo +++ b/test/exception-handling.wast.fromBinary.noDebugInfo @@ -4,6 +4,7 @@ (type $2 (func (param i64))) (type $3 (func (param i32 i64))) (type $4 (func (param eqref))) + (type $5 (func (result exnref))) (tag $tag$0 (param i32)) (tag $tag$1 (param i64)) (tag $tag$2 (param i32 i64)) @@ -428,5 +429,18 @@ ) (nop) ) + (func $8 (type $5) (result exnref) + (local $0 exnref) + (local $1 nullexnref) + (if (result exnref) + (i32.const 1) + (if (result nullexnref) + (i32.const 1) + (local.get $1) + (ref.null noexn) + ) + (local.get $0) + ) + ) )