diff options
33 files changed, 990 insertions, 687 deletions
diff --git a/src/asmjs/asm_v_wasm.cpp b/src/asmjs/asm_v_wasm.cpp index 8d2894f13..e7b4d6edd 100644 --- a/src/asmjs/asm_v_wasm.cpp +++ b/src/asmjs/asm_v_wasm.cpp @@ -58,6 +58,8 @@ AsmType wasmToAsmType(Type type) { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: assert(false && "reference types are not supported by asm2wasm"); case Type::none: return ASM_NONE; @@ -88,6 +90,10 @@ char getSig(Type type) { return 'E'; case Type::anyref: return 'A'; + case Type::eqref: + return 'Q'; + case Type::i31ref: + return 'I'; case Type::none: return 'v'; case Type::unreachable: diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 1c938faab..2f1d3f5ff 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -74,8 +74,11 @@ BinaryenLiteral toBinaryenLiteral(Literal x) { case Type::externref: case Type::exnref: case Type::anyref: - assert(x.isNull()); + case Type::eqref: + assert(x.isNull() && "unexpected non-null reference type literal"); break; + case Type::i31ref: + WASM_UNREACHABLE("TODO: i31ref"); case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -100,7 +103,10 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: return Literal::makeNull(Type(x.type)); + case Type::i31ref: + WASM_UNREACHABLE("TODO: i31ref"); case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -136,6 +142,8 @@ BinaryenType BinaryenTypeFuncref(void) { return Type::funcref; } BinaryenType BinaryenTypeExternref(void) { return Type::externref; } BinaryenType BinaryenTypeExnref(void) { return Type::exnref; } BinaryenType BinaryenTypeAnyref(void) { return Type::anyref; } +BinaryenType BinaryenTypeEqref(void) { return Type::eqref; } +BinaryenType BinaryenTypeI31ref(void) { return Type::i31ref; } BinaryenType BinaryenTypeUnreachable(void) { return Type::unreachable; } BinaryenType BinaryenTypeAuto(void) { return uintptr_t(-1); } diff --git a/src/binaryen-c.h b/src/binaryen-c.h index f368ad122..3a3be4608 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -102,6 +102,8 @@ BINARYEN_API BinaryenType BinaryenTypeFuncref(void); BINARYEN_API BinaryenType BinaryenTypeExternref(void); BINARYEN_API BinaryenType BinaryenTypeExnref(void); BINARYEN_API BinaryenType BinaryenTypeAnyref(void); +BINARYEN_API BinaryenType BinaryenTypeEqref(void); +BINARYEN_API BinaryenType BinaryenTypeI31ref(void); BINARYEN_API BinaryenType BinaryenTypeUnreachable(void); // Not a real type. Used as the last parameter to BinaryenBlock to let // the API figure out the type instead of providing one. diff --git a/src/ir/abstract.h b/src/ir/abstract.h index ce5b6b008..ac67a59b3 100644 --- a/src/ir/abstract.h +++ b/src/ir/abstract.h @@ -103,6 +103,8 @@ inline UnaryOp getUnary(Type type, Op op) { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: { return InvalidUnary; @@ -266,6 +268,8 @@ inline BinaryOp getBinary(Type type, Op op) { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: { return InvalidBinary; diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 87a6bacda..4703abc54 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -37,6 +37,8 @@ function initializeConstants() { ['externref', 'Externref'], ['exnref', 'Exnref'], ['anyref', 'Anyref'], + ['eqref', 'Eqref'], + ['i31ref', 'I31ref'], ['unreachable', 'Unreachable'], ['auto', 'Auto'] ].forEach(entry => { @@ -2070,6 +2072,18 @@ function wrapModule(module, self = {}) { } }; + self['eqref'] = { + 'pop'() { + return Module['_BinaryenPop'](module, Module['eqref']); + } + }; + + self['i31ref'] = { + 'pop'() { + return Module['_BinaryenPop'](module, Module['i31ref']); + } + }; + self['ref'] = { 'null'(type) { return Module['_BinaryenRefNull'](module, type); diff --git a/src/literal.h b/src/literal.h index c617f56f0..698063cbe 100644 --- a/src/literal.h +++ b/src/literal.h @@ -595,6 +595,8 @@ template<> struct less<wasm::Literal> { case wasm::Type::externref: case wasm::Type::exnref: case wasm::Type::anyref: + case wasm::Type::eqref: + case wasm::Type::i31ref: case wasm::Type::none: case wasm::Type::unreachable: return false; diff --git a/src/parsing.h b/src/parsing.h index d809cbedd..bdc3e63b7 100644 --- a/src/parsing.h +++ b/src/parsing.h @@ -267,6 +267,8 @@ parseConst(cashew::IString s, Type type, MixedArena& allocator) { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: WASM_UNREACHABLE("unexpected const type"); case Type::none: case Type::unreachable: { diff --git a/src/passes/ConstHoisting.cpp b/src/passes/ConstHoisting.cpp index 3b34751ff..a972c05fb 100644 --- a/src/passes/ConstHoisting.cpp +++ b/src/passes/ConstHoisting.cpp @@ -97,7 +97,9 @@ private: case Type::funcref: case Type::externref: case Type::exnref: - case Type::anyref: { + case Type::anyref: + case Type::eqref: + case Type::i31ref: { return false; } case Type::none: diff --git a/src/passes/FuncCastEmulation.cpp b/src/passes/FuncCastEmulation.cpp index 101834790..6f5e9d611 100644 --- a/src/passes/FuncCastEmulation.cpp +++ b/src/passes/FuncCastEmulation.cpp @@ -68,7 +68,9 @@ static Expression* toABI(Expression* value, Module* module) { case Type::funcref: case Type::externref: case Type::exnref: - case Type::anyref: { + case Type::anyref: + case Type::eqref: + case Type::i31ref: { WASM_UNREACHABLE("reference types cannot be converted to i64"); } case Type::none: { @@ -112,7 +114,9 @@ static Expression* fromABI(Expression* value, Type type, Module* module) { case Type::funcref: case Type::externref: case Type::exnref: - case Type::anyref: { + case Type::anyref: + case Type::eqref: + case Type::i31ref: { WASM_UNREACHABLE("reference types cannot be converted from i64"); } case Type::none: { diff --git a/src/passes/InstrumentLocals.cpp b/src/passes/InstrumentLocals.cpp index f9c26d788..8803a7811 100644 --- a/src/passes/InstrumentLocals.cpp +++ b/src/passes/InstrumentLocals.cpp @@ -60,6 +60,8 @@ Name get_funcref("get_funcref"); Name get_externref("get_externref"); Name get_exnref("get_exnref"); Name get_anyref("get_anyref"); +Name get_eqref("get_eqref"); +Name get_i31ref("get_i31ref"); Name get_v128("get_v128"); Name set_i32("set_i32"); @@ -70,6 +72,8 @@ Name set_funcref("set_funcref"); Name set_externref("set_externref"); Name set_exnref("set_exnref"); Name set_anyref("set_anyref"); +Name set_eqref("set_eqref"); +Name set_i31ref("set_i31ref"); Name set_v128("set_v128"); struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> { @@ -104,6 +108,12 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> { case Type::anyref: import = get_anyref; break; + case Type::eqref: + import = get_eqref; + break; + case Type::i31ref: + import = get_i31ref; + break; case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -153,6 +163,12 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> { case Type::anyref: import = set_anyref; break; + case Type::eqref: + import = set_eqref; + break; + case Type::i31ref: + import = set_i31ref; + break; case Type::unreachable: return; // nothing to do here case Type::none: @@ -203,6 +219,14 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> { curr, get_anyref, {Type::i32, Type::i32, Type::anyref}, Type::anyref); addImport( curr, set_anyref, {Type::i32, Type::i32, Type::anyref}, Type::anyref); + addImport( + curr, get_eqref, {Type::i32, Type::i32, Type::eqref}, Type::eqref); + addImport( + curr, set_eqref, {Type::i32, Type::i32, Type::eqref}, Type::eqref); + addImport( + curr, get_i31ref, {Type::i32, Type::i32, Type::i31ref}, Type::i31ref); + addImport( + curr, set_i31ref, {Type::i32, Type::i32, Type::i31ref}, Type::i31ref); } } if (curr->features.hasSIMD()) { diff --git a/src/shell-interface.h b/src/shell-interface.h index ae86d13ec..8d35905ee 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -119,8 +119,11 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: globals[import->name] = {Literal::makeNull(import->type)}; break; + case Type::i31ref: + WASM_UNREACHABLE("TODO: i31ref"); case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index e6cc4e444..0783588cd 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -324,6 +324,15 @@ private: if (wasm.features.hasExceptionHandling()) { options.push_back(Type::exnref); } + if (wasm.features.hasGC()) { + options.push_back(Type::eqref); + // TODO: i31ref + } + } + break; + case Type::eqref: + if (wasm.features.hasGC()) { + // TODO: i31ref } break; default: @@ -1362,6 +1371,8 @@ private: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("invalid type"); @@ -1466,6 +1477,8 @@ private: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("invalid type"); @@ -1595,6 +1608,8 @@ private: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("invalid type"); @@ -1640,6 +1655,8 @@ private: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -1708,6 +1725,8 @@ private: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -1735,6 +1754,8 @@ private: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -1845,6 +1866,8 @@ private: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: return makeTrivial(type); case Type::none: case Type::unreachable: @@ -1990,6 +2013,8 @@ private: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -2227,6 +2252,8 @@ private: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -2434,6 +2461,8 @@ private: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -2674,7 +2703,9 @@ private: .add(FeatureSet::ReferenceTypes, Type::funcref, Type::externref) .add(FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling, Type::exnref) - .add(FeatureSet::ReferenceTypes | FeatureSet::GC, Type::anyref)); + .add(FeatureSet::ReferenceTypes | FeatureSet::GC, + Type::anyref, + Type::eqref)); // TODO: i31ref } Type getSingleConcreteType() { return pick(getSingleConcreteTypes()); } @@ -2685,7 +2716,9 @@ private: .add(FeatureSet::ReferenceTypes, Type::funcref, Type::externref) .add(FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling, Type::exnref) - .add(FeatureSet::ReferenceTypes | FeatureSet::GC, Type::anyref)); + .add(FeatureSet::ReferenceTypes | FeatureSet::GC, + Type::anyref, + Type::eqref)); // TODO: i31ref } Type getReferenceType() { return pick(getReferenceTypes()); } diff --git a/src/tools/spec-wrapper.h b/src/tools/spec-wrapper.h index 200571fd0..5a61d72b6 100644 --- a/src/tools/spec-wrapper.h +++ b/src/tools/spec-wrapper.h @@ -61,6 +61,11 @@ static std::string generateSpecWrapper(Module& wasm) { case Type::anyref: ret += "(ref.null any)"; break; + case Type::eqref: + ret += "(ref.null eq)"; + break; + case Type::i31ref: + WASM_UNREACHABLE("TODO: i31ref"); case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp index 7410ff91e..7a81007dc 100644 --- a/src/tools/wasm-reduce.cpp +++ b/src/tools/wasm-reduce.cpp @@ -599,6 +599,8 @@ struct Reducer case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: continue; // not implemented yet case Type::none: case Type::unreachable: @@ -625,6 +627,8 @@ struct Reducer case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: continue; // not implemented yet case Type::none: case Type::unreachable: @@ -651,6 +655,8 @@ struct Reducer case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: continue; // not implemented yet case Type::none: case Type::unreachable: @@ -677,6 +683,8 @@ struct Reducer case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: continue; // not implemented yet case Type::none: case Type::unreachable: @@ -689,6 +697,8 @@ struct Reducer case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: continue; // not implemented yet case Type::none: case Type::unreachable: diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 7666fa842..39980ee04 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -346,6 +346,10 @@ enum EncodedType { externref = -0x11, // 0x6f // any reference type anyref = -0x12, // 0x6e + // comparable reference type + eqref = -0x13, // 0x6d + // integer reference type + i31ref = -0x16, // 0x6a // exception reference type exnref = -0x18, // 0x68 // func_type form @@ -358,6 +362,8 @@ enum EncodedHeapType { func = -0x10, // 0x70 extern_ = -0x11, // 0x6f any = -0x12, // 0x6e + eq = -0x13, // 0x6d + i31 = -0x17, // 0x69, != i31ref exn = -0x18, // 0x68 }; @@ -981,6 +987,12 @@ inline S32LEB binaryType(Type type) { case Type::anyref: ret = BinaryConsts::EncodedType::anyref; break; + case Type::eqref: + ret = BinaryConsts::EncodedType::eqref; + break; + case Type::i31ref: + ret = BinaryConsts::EncodedType::i31ref; + break; case Type::unreachable: WASM_UNREACHABLE("unexpected type"); } @@ -1003,11 +1015,15 @@ inline S32LEB binaryHeapType(HeapType type) { ret = BinaryConsts::EncodedHeapType::any; break; case HeapType::EqKind: + ret = BinaryConsts::EncodedHeapType::eq; + break; case HeapType::I31Kind: + ret = BinaryConsts::EncodedHeapType::i31; + break; case HeapType::SignatureKind: case HeapType::StructKind: case HeapType::ArrayKind: - WASM_UNREACHABLE("TODO: GC types"); + WASM_UNREACHABLE("TODO: compound GC types"); } return S32LEB(ret); // TODO: Actually encoded as s33 } diff --git a/src/wasm-builder.h b/src/wasm-builder.h index b35fde376..737dad16a 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -645,8 +645,11 @@ public: case Type::externref: case Type::exnref: // TODO: ExceptionPackage? case Type::anyref: - assert(value.isNull()); + case Type::eqref: + assert(value.isNull() && "unexpected non-null reference type literal"); return makeRefNull(value.type); + case Type::i31ref: + WASM_UNREACHABLE("TODO: i31ref"); default: assert(value.type.isNumber()); return makeConst(value); @@ -840,7 +843,10 @@ public: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: return ExpressionManipulator::refNull(curr, curr->type); + case Type::i31ref: + WASM_UNREACHABLE("TODO: i31ref"); case Type::none: return ExpressionManipulator::nop(curr); case Type::unreachable: diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 51cc24d01..69d6ff771 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1653,6 +1653,8 @@ public: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -1710,6 +1712,8 @@ public: case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); diff --git a/src/wasm-type.h b/src/wasm-type.h index f3973068f..4a55d7b33 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -51,7 +51,9 @@ public: externref, exnref, anyref, - _last_basic_id = anyref + eqref, + i31ref, + _last_basic_id = i31ref, }; Type() = default; diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 39a4cea3c..4a89b5cd1 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -70,7 +70,10 @@ Literal::Literal(const Literal& other) : type(other.type) { break; case Type::externref: case Type::anyref: + case Type::eqref: break; // null + case Type::i31ref: + WASM_UNREACHABLE("TODO: i31ref"); case Type::funcref: case Type::exnref: case Type::unreachable: @@ -223,10 +226,11 @@ void Literal::getBits(uint8_t (&buf)[16]) const { case Type::externref: case Type::exnref: case Type::anyref: - if (isNull()) { - break; - } - // falls through + case Type::eqref: + assert(isNull() && "unexpected non-null reference type literal"); + break; + case Type::i31ref: + WASM_UNREACHABLE("TODO: i31ref"); case Type::none: case Type::unreachable: WASM_UNREACHABLE("invalid type"); @@ -379,6 +383,10 @@ std::ostream& operator<<(std::ostream& o, Literal literal) { o << "funcref(" << literal.getFunc() << ")"; } break; + case Type::externref: + assert(literal.isNull() && "unexpected non-null externref literal"); + o << "externref(null)"; + break; case Type::exnref: if (literal.isNull()) { o << "exnref(null)"; @@ -387,13 +395,15 @@ std::ostream& operator<<(std::ostream& o, Literal literal) { } break; case Type::anyref: - assert(literal.isNull() && "TODO: non-null anyref values"); + assert(literal.isNull() && "unexpected non-null anyref literal"); o << "anyref(null)"; break; - case Type::externref: - assert(literal.isNull() && "TODO: non-null externref values"); - o << "externref(null)"; + case Type::eqref: + assert(literal.isNull() && "unexpected non-null eqref literal"); + o << "eqref(null)"; break; + case Type::i31ref: + WASM_UNREACHABLE("TODO: i31ref"); case Type::unreachable: WASM_UNREACHABLE("invalid type"); } @@ -619,6 +629,8 @@ Literal Literal::eqz() const { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -641,6 +653,8 @@ Literal Literal::neg() const { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -663,6 +677,8 @@ Literal Literal::abs() const { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -768,6 +784,8 @@ Literal Literal::add(const Literal& other) const { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -790,6 +808,8 @@ Literal Literal::sub(const Literal& other) const { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -908,6 +928,8 @@ Literal Literal::mul(const Literal& other) const { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -1154,6 +1176,8 @@ Literal Literal::eq(const Literal& other) const { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -1176,6 +1200,8 @@ Literal Literal::ne(const Literal& other) const { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 18a66fb2c..a6299c892 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -1206,10 +1206,14 @@ Type WasmBinaryBuilder::getType() { return Type::exnref; case BinaryConsts::EncodedType::anyref: return Type::anyref; + case BinaryConsts::EncodedType::eqref: + return Type::eqref; + case BinaryConsts::EncodedType::i31ref: + return Type::i31ref; default: throwError("invalid wasm type: " + std::to_string(type)); } - WASM_UNREACHABLE("unexpeced type"); + WASM_UNREACHABLE("unexpected type"); } HeapType WasmBinaryBuilder::getHeapType() { @@ -1230,10 +1234,14 @@ HeapType WasmBinaryBuilder::getHeapType() { return HeapType::ExnKind; case BinaryConsts::EncodedHeapType::any: return HeapType::AnyKind; + case BinaryConsts::EncodedHeapType::eq: + return HeapType::EqKind; + case BinaryConsts::EncodedHeapType::i31: + return HeapType::I31Kind; default: throwError("invalid wasm heap type: " + std::to_string(type)); } - WASM_UNREACHABLE("unexpeced type"); + WASM_UNREACHABLE("unexpected type"); } Type WasmBinaryBuilder::getConcreteType() { diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 8bbcc9ac0..2aa60979f 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -875,6 +875,12 @@ Type SExpressionWasmBuilder::stringToType(const char* str, if (strncmp(str, "anyref", 6) == 0 && (prefix || str[6] == 0)) { return Type::anyref; } + if (strncmp(str, "eqref", 5) == 0 && (prefix || str[5] == 0)) { + return Type::eqref; + } + if (strncmp(str, "i31ref", 6) == 0 && (prefix || str[6] == 0)) { + return Type::i31ref; + } if (allowError) { return Type::none; } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 30816546a..66f9e02dd 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -192,6 +192,8 @@ void BinaryInstWriter::visitLoad(Load* curr) { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: WASM_UNREACHABLE("unexpected type"); } @@ -294,6 +296,8 @@ void BinaryInstWriter::visitStore(Store* curr) { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -697,6 +701,8 @@ void BinaryInstWriter::visitConst(Const* curr) { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index d88b7b027..cf68d92e9 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -260,9 +260,10 @@ std::unordered_map<TypeInfo, uintptr_t> indices = { {TypeInfo(HeapType(HeapType::ExnKind), true), Type::exnref}, {TypeInfo({Type::anyref}), Type::anyref}, {TypeInfo(HeapType(HeapType::AnyKind), true), Type::anyref}, - // TODO (GC): Add canonical ids - // * `(ref null eq) == eqref` - // * `(ref i31) == i31ref` + {TypeInfo({Type::eqref}), Type::eqref}, + {TypeInfo(HeapType(HeapType::EqKind), true), Type::eqref}, + {TypeInfo({Type::i31ref}), Type::i31ref}, + {TypeInfo(HeapType(HeapType::I31Kind), false), Type::i31ref}, }; } // anonymous namespace @@ -341,7 +342,7 @@ bool Type::isTuple() const { bool Type::isRef() const { if (isBasic()) { - return id >= funcref && id <= anyref; + return id >= funcref && id <= i31ref; } else { return getTypeInfo(*this)->isRef(); } @@ -367,7 +368,7 @@ bool Type::isException() const { bool Type::isNullable() const { if (isBasic()) { - return id >= funcref && id <= anyref; + return id >= funcref && id <= eqref; // except i31ref } else { return getTypeInfo(*this)->isNullable(); } @@ -409,6 +410,8 @@ unsigned Type::getByteSize() const { case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: case Type::unreachable: break; @@ -454,6 +457,8 @@ FeatureSet Type::getFeatures() const { case Type::exnref: return FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling; case Type::anyref: + case Type::eqref: + case Type::i31ref: return FeatureSet::ReferenceTypes | FeatureSet::GC; default: return FeatureSet::MVP; @@ -484,6 +489,10 @@ HeapType Type::getHeapType() const { return HeapType::ExnKind; case anyref: return HeapType::AnyKind; + case eqref: + return HeapType::EqKind; + case i31ref: + return HeapType::I31Kind; default: break; } @@ -512,7 +521,8 @@ bool Type::isSubType(Type left, Type right) { return true; } if (left.isRef() && right.isRef()) { - return right == Type::anyref; + return right == Type::anyref || + (left == Type::i31ref && right == Type::eqref); } if (left.isTuple() && right.isTuple()) { if (left.size() != right.size()) { @@ -543,6 +553,10 @@ Type Type::getLeastUpperBound(Type a, Type b) { } if (a.isRef()) { if (b.isRef()) { + if ((a == Type::i31ref && b == Type::eqref) || + (a == Type::eqref && b == Type::i31ref)) { + return Type::eqref; + } // The LUB of two different reference types is anyref, which may or may // not be a valid type depending on whether the anyref feature is enabled. // When anyref is disabled, it is possible for the finalization of invalid @@ -754,6 +768,12 @@ std::ostream& operator<<(std::ostream& os, Type type) { case Type::anyref: os << "anyref"; break; + case Type::eqref: + os << "eqref"; + break; + case Type::i31ref: + os << "i31ref"; + break; } } else { os << *getTypeInfo(type); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 505753c88..16ba60d72 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -1396,6 +1396,8 @@ void FunctionValidator::validateMemBytes(uint8_t bytes, case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: WASM_UNREACHABLE("unexpected type"); } @@ -2204,6 +2206,8 @@ void FunctionValidator::validateAlignment( case Type::externref: case Type::exnref: case Type::anyref: + case Type::eqref: + case Type::i31ref: case Type::none: WASM_UNREACHABLE("invalid type"); } diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js index d985b39aa..342315682 100644 --- a/test/binaryen.js/kitchen-sink.js +++ b/test/binaryen.js/kitchen-sink.js @@ -80,6 +80,12 @@ function test_types() { console.log(" // BinaryenTypeAnyref: " + binaryen.anyref); console.log(" //", binaryen.expandType(binaryen.anyref).join(",")); + console.log(" // BinaryenTypeEqref: " + binaryen.eqref); + console.log(" //", binaryen.expandType(binaryen.eqref).join(",")); + + console.log(" // BinaryenTypeI31ref: " + binaryen.i31ref); + console.log(" //", binaryen.expandType(binaryen.i31ref).join(",")); + console.log(" // BinaryenTypeAuto: " + binaryen.auto); var i32_pair = binaryen.createType([binaryen.i32, binaryen.i32]); @@ -570,9 +576,12 @@ function test_core() { module.f32.pop(), module.f64.pop(), module.v128.pop(), - module.externref.pop(), module.funcref.pop(), + module.externref.pop(), module.exnref.pop(), + module.anyref.pop(), + module.eqref.pop(), + module.i31ref.pop(), // Memory module.memory.size(), diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt index 6bd8329e0..413a2236c 100644 --- a/test/binaryen.js/kitchen-sink.js.txt +++ b/test/binaryen.js/kitchen-sink.js.txt @@ -20,6 +20,10 @@ // 9 // BinaryenTypeAnyref: 10 // 10 + // BinaryenTypeEqref: 11 + // 11 + // BinaryenTypeI31ref: 12 + // 12 // BinaryenTypeAuto: -1 // 2,2 // 2,2 @@ -1912,15 +1916,24 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7} (pop v128) ) (drop - (pop externref) + (pop funcref) ) (drop - (pop funcref) + (pop externref) ) (drop (pop exnref) ) (drop + (pop anyref) + ) + (drop + (pop eqref) + ) + (drop + (pop i31ref) + ) + (drop (memory.size) ) (drop @@ -3760,15 +3773,24 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7} (pop v128) ) (drop - (pop externref) + (pop funcref) ) (drop - (pop funcref) + (pop externref) ) (drop (pop exnref) ) (drop + (pop anyref) + ) + (drop + (pop eqref) + ) + (drop + (pop i31ref) + ) + (drop (memory.size) ) (drop diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c index f619e6db5..442394e12 100644 --- a/test/example/c-api-kitchen-sink.c +++ b/test/example/c-api-kitchen-sink.c @@ -217,6 +217,18 @@ void test_types() { BinaryenTypeExpand(anyref, &valueType); assert(valueType == anyref); + BinaryenType eqref = BinaryenTypeEqref(); + printf(" // BinaryenTypeEqref: %d\n", eqref); + assert(BinaryenTypeArity(eqref) == 1); + BinaryenTypeExpand(eqref, &valueType); + assert(valueType == eqref); + + BinaryenType i31ref = BinaryenTypeI31ref(); + printf(" // BinaryenTypeI31ref: %d\n", i31ref); + assert(BinaryenTypeArity(i31ref) == 1); + BinaryenTypeExpand(i31ref, &valueType); + assert(valueType == i31ref); + printf(" // BinaryenTypeAuto: %d\n", BinaryenTypeAuto()); BinaryenType pair[] = {i32, i32}; diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt index 807730e27..405848140 100644 --- a/test/example/c-api-kitchen-sink.txt +++ b/test/example/c-api-kitchen-sink.txt @@ -9,6 +9,8 @@ // BinaryenTypeExternref: 8 // BinaryenTypeExnref: 9 // BinaryenTypeAnyref: 10 + // BinaryenTypeEqref: 11 + // BinaryenTypeI31ref: 12 // BinaryenTypeAuto: -1 BinaryenFeatureMVP: 0 BinaryenFeatureAtomics: 1 diff --git a/test/example/typeinfo.txt b/test/example/typeinfo.txt index 539f305db..4ba628925 100644 --- a/test/example/typeinfo.txt +++ b/test/example/typeinfo.txt @@ -9,11 +9,11 @@ any anyref (ref any) eq -(ref null eq) +eqref (ref eq) i31 (ref null i31) -(ref i31) +i31ref exn exnref (ref exn) diff --git a/test/passes/instrument-locals_all-features.txt b/test/passes/instrument-locals_all-features.txt index 8943c2d56..a606813cb 100644 --- a/test/passes/instrument-locals_all-features.txt +++ b/test/passes/instrument-locals_all-features.txt @@ -8,6 +8,8 @@ (type $i32_i32_externref_=>_externref (func (param i32 i32 externref) (result externref))) (type $i32_i32_exnref_=>_exnref (func (param i32 i32 exnref) (result exnref))) (type $i32_i32_anyref_=>_anyref (func (param i32 i32 anyref) (result anyref))) + (type $i32_i32_eqref_=>_eqref (func (param i32 i32 eqref) (result eqref))) + (type $i32_i32_i31ref_=>_i31ref (func (param i32 i32 i31ref) (result i31ref))) (type $none_=>_none (func)) (import "env" "get_i32" (func $get_i32 (param i32 i32 i32) (result i32))) (import "env" "get_i64" (func $get_i64 (param i32 i32 i64) (result i64))) @@ -25,6 +27,10 @@ (import "env" "set_exnref" (func $set_exnref (param i32 i32 exnref) (result exnref))) (import "env" "get_anyref" (func $get_anyref (param i32 i32 anyref) (result anyref))) (import "env" "set_anyref" (func $set_anyref (param i32 i32 anyref) (result anyref))) + (import "env" "get_eqref" (func $get_eqref (param i32 i32 eqref) (result eqref))) + (import "env" "set_eqref" (func $set_eqref (param i32 i32 eqref) (result eqref))) + (import "env" "get_i31ref" (func $get_i31ref (param i32 i32 i31ref) (result i31ref))) + (import "env" "set_i31ref" (func $set_i31ref (param i32 i32 i31ref) (result i31ref))) (import "env" "get_v128" (func $get_v128 (param i32 i32 v128) (result v128))) (import "env" "set_v128" (func $set_v128 (param i32 i32 v128) (result v128))) (func $test diff --git a/test/passes/translate-to-fuzz_all-features.txt b/test/passes/translate-to-fuzz_all-features.txt index 80552e2d5..b03dbbb20 100644 --- a/test/passes/translate-to-fuzz_all-features.txt +++ b/test/passes/translate-to-fuzz_all-features.txt @@ -1,18 +1,24 @@ (module - (type $none_=>_none (func)) - (type $none_=>_i32_anyref_externref (func (result i32 anyref externref))) (type $f32_=>_none (func (param f32))) - (type $exnref_=>_none (func (param exnref))) - (type $none_=>_externref_anyref_anyref_anyref (func (result externref anyref anyref anyref))) + (type $none_=>_none (func)) + (type $none_=>_f32_i64_funcref (func (result f32 i64 funcref))) (type $i32_=>_none (func (param i32))) + (type $i32_f64_=>_none (func (param i32 f64))) (type $i64_=>_none (func (param i64))) (type $f64_=>_none (func (param f64))) - (type $f64_i32_i64_f64_v128_=>_none (func (param f64 i32 i64 f64 v128))) (type $v128_=>_none (func (param v128))) + (type $exnref_=>_none (func (param exnref))) (type $none_=>_i32 (func (result i32))) - (type $anyref_funcref_externref_=>_f32 (func (param anyref funcref externref) (result f32))) - (type $none_=>_v128 (func (result v128))) - (type $none_=>_anyref (func (result anyref))) + (type $funcref_anyref_=>_f64 (func (param funcref anyref) (result f64))) + (type $anyref_eqref_=>_f64 (func (param anyref eqref) (result f64))) + (type $funcref_f64_=>_v128 (func (param funcref f64) (result v128))) + (type $none_=>_funcref (func (result funcref))) + (type $v128_=>_funcref (func (param v128) (result funcref))) + (type $v128_anyref_f32_=>_funcref (func (param v128 anyref f32) (result funcref))) + (type $externref_i32_v128_i64_=>_externref (func (param externref i32 v128 i64) (result externref))) + (type $f32_eqref_=>_anyref (func (param f32 eqref) (result anyref))) + (type $none_=>_eqref_eqref_eqref_eqref_eqref (func (result eqref eqref eqref eqref eqref))) + (type $exnref_=>_eqref_eqref_eqref_eqref_eqref (func (param exnref) (result eqref eqref eqref eqref eqref))) (import "fuzzing-support" "log-i32" (func $log-i32 (param i32))) (import "fuzzing-support" "log-i64" (func $log-i64 (param i64))) (import "fuzzing-support" "log-f32" (func $log-f32 (param f32))) @@ -21,29 +27,31 @@ (import "fuzzing-support" "log-exnref" (func $log-exnref (param exnref))) (memory $0 (shared 1 1)) (data (i32.const 0) "N\0fN\f5\f9\b1\ff\fa\eb\e5\fe\a7\ec\fb\fc\f4\a6\e4\ea\f0\ae\e3") - (table $0 2 funcref) - (elem (i32.const 0) $func_7 $func_11) - (global $global$5 (mut f32) (f32.const 74)) - (global $global$4 (mut exnref) (ref.null exn)) - (global $global$3 (mut i32) (i32.const 1263230471)) - (global $global$2 (mut i32) (i32.const -131072)) - (global $global$1 (mut (funcref exnref exnref externref anyref f64)) (tuple.make + (table $0 12 12 funcref) + (elem (i32.const 0) $func_7 $func_7 $func_8 $func_8 $func_9 $func_9 $func_9 $func_13 $func_13 $func_13 $func_17 $func_19) + (global $global$5 (mut eqref) (ref.null eq)) + (global $global$4 (mut externref) (ref.null extern)) + (global $global$3 (mut exnref) (ref.null exn)) + (global $global$2 (mut funcref) (ref.null func)) + (global $global$1 (mut (v128 funcref i64 anyref eqref exnref)) (tuple.make + (v128.const i32x4 0x0c0d0c62 0x48060d0d 0x000000ff 0x00000000) (ref.null func) - (ref.null exn) - (ref.null exn) - (ref.null extern) + (i64.const -2199023255552) (ref.null any) - (f64.const 1.1754943508222875e-38) + (ref.null eq) + (ref.null exn) )) (global $hangLimit (mut i32) (i32.const 10)) - (event $event$0 (attr 0) (param exnref)) - (event $event$1 (attr 0) (param f32)) (export "hashMemory" (func $hashMemory)) (export "memory" (memory $0)) - (export "func_7" (func $func_7)) - (export "func_7_invoker" (func $func_7_invoker)) - (export "func_10" (func $func_10)) - (export "func_11_invoker" (func $func_11_invoker)) + (export "func_9" (func $func_9)) + (export "func_10_invoker" (func $func_10_invoker)) + (export "func_12" (func $func_12)) + (export "func_13_invoker" (func $func_13_invoker)) + (export "func_17" (func $func_17)) + (export "func_19" (func $func_19)) + (export "func_19_invoker" (func $func_19_invoker)) + (export "func_21" (func $func_21)) (export "hangLimitInitializer" (func $hangLimitInitializer)) (func $hashMemory (result i32) (local $0 i32) @@ -276,18 +284,20 @@ ) (local.get $0) ) - (func $func_7 (result anyref) - (local $0 i64) - (local $1 i64) - (local $2 anyref) + (func $func_7 (param $0 f32) + (local $1 (anyref externref)) + (local $2 i32) + (local $3 i64) + (local $4 funcref) + (local $5 v128) + (local $6 (funcref anyref f32 i32 exnref)) + (local $7 i32) (block (if (i32.eqz (global.get $hangLimit) ) - (return - (ref.null any) - ) + (return) ) (global.set $hangLimit (i32.sub @@ -296,38 +306,87 @@ ) ) ) - (ref.null any) - ) - (func $func_7_invoker - (drop - (call $func_7) - ) - (drop - (call $func_7) - ) - (call $log-i32 - (call $hashMemory) - ) - (drop - (call $func_7) - ) - (call $log-i32 - (call $hashMemory) + (block $label$0 + (call $log-f64 + (if (result f64) + (i32.eqz + (i32.const 32768) + ) + (block $label$1 (result f64) + (br_if $label$0 + (i32.eqz + (loop $label$2 (result i32) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block $label$3 (result i32) + (nop) + (local.tee $7 + (local.tee $2 + (local.tee $7 + (local.tee $2 + (local.tee $2 + (local.tee $2 + (local.tee $2 + (local.tee $2 + (local.get $7) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + (call $log-exnref + (ref.null exn) + ) + (f64.const 11839) + ) + (block $label$4 (result f64) + (nop) + (f64.nearest + (f64.const 1.6005841300030413e-215) + ) + ) + ) + ) + (call $log-exnref + (ref.null exn) + ) ) ) - (func $func_9 (result externref anyref anyref anyref) + (func $func_8 (param $0 funcref) (param $1 anyref) (result f64) + (local $2 i64) + (local $3 (f64 i32 anyref i64 exnref)) + (local $4 v128) + (local $5 (v128 f32 exnref)) + (local $6 f32) + (local $7 i32) + (local $8 (funcref eqref)) + (local $9 i64) (block (if (i32.eqz (global.get $hangLimit) ) (return - (tuple.make - (ref.null extern) - (ref.null any) - (ref.null any) - (ref.null any) - ) + (f64.const 4806734720588042541890704e256) ) ) (global.set $hangLimit @@ -337,15 +396,11 @@ ) ) ) - (tuple.make - (ref.null extern) - (ref.null any) - (ref.null any) - (ref.null any) - ) + (f64.const 9223372036854775808) ) - (func $func_10 (param $0 f64) (param $1 i32) (param $2 i64) (param $3 f64) (param $4 v128) - (local $5 exnref) + (func $func_9 (param $0 i32) (param $1 f64) + (local $2 i32) + (local $3 funcref) (block (if (i32.eqz @@ -361,17 +416,29 @@ ) ) (block $label$0 - (call $log-i32 - (call $hashMemory) - ) - (call $log-f32 - (i32.load offset=4 align=2 - (i32.and - (local.tee $1 + (f32.store offset=3 align=2 + (i32.and + (local.get $0) + (i32.const 15) + ) + (if (result f32) + (local.tee $2 + (local.tee $2 (block $label$1 - (call $log-i32 - (block $label$2 (result i32) - (loop $label$3 + (call_indirect (type $f32_=>_none) + (f32.div + (f32.const 4189) + (f32.const 1396855168) + ) + (i32.atomic.rmw8.cmpxchg_u offset=3 + (i32.and + (call $hashMemory) + (i32.const 15) + ) + (local.tee $0 + (local.get $2) + ) + (loop $label$3 (result i32) (block (if (i32.eqz @@ -386,452 +453,221 @@ ) ) ) - (block - (block $label$4 - (call $log-f32 - (global.get $global$5) - ) + (loop $label$4 (result i32) + (block (if - (local.tee $1 - (local.get $1) + (i32.eqz + (global.get $hangLimit) ) - (block $label$5 - (call $log-f64 - (f64.reinterpret_i64 - (local.tee $2 - (block $label$6 - (call $log-f32 - (f32.min - (f32.const -1) - (f32.demote_f64 - (f64.copysign - (f64.const 28) - (local.get $3) - ) - ) - ) - ) - (br $label$5) - ) - ) - ) - ) - (call $log-i32 - (br_if $label$2 - (global.get $global$3) - (f64.lt - (f64.min - (tuple.extract 0 - (tuple.make - (f64.const 16240) - (ref.null any) - ) - ) - (f64.const -9223372036854775808) - ) - (f64x2.extract_lane 1 - (local.get $4) - ) + (return) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block $label$5 (result i32) + (v128.store offset=22 align=8 + (i32.and + (i32.load16_u offset=4 align=1 + (i32.and + (ref.is_null + (ref.null extern) ) + (i32.const 15) ) ) + (i32.const 15) ) - (block $label$7 - (local.set $0 - (loop $label$8 (result f64) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) + (i16x8.ne + (i16x8.gt_u + (select + (if (result v128) + (i32.eqz + (i32.const 2147483647) + ) + (block $label$8 (result v128) + (nop) + (v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) + (block $label$9 (result v128) + (if (result v128) + (i32.const -96) + (v128.const i32x4 0xffffff99 0xffffffff 0x00000000 0x40648000) + (v128.const i32x4 0x00005f01 0x0000b03f 0x644b1d80 0x4fb2ff39) ) ) ) - (block (result f64) - (block $label$9 - (call $log-v128 - (local.get $4) - ) - (call $log-i32 - (call $hashMemory) + (v128.const i32x4 0x00000000 0x40eff640 0x00000000 0xc1300000) + (local.tee $0 + (if (result i32) + (local.tee $0 + (local.get $0) ) - ) - (br_if $label$8 - (i32.eqz - (local.tee $1 - (i32.const 977223545) + (block $label$6 (result i32) + (local.set $0 + (local.get $2) ) - ) - ) - (local.get $3) - ) - ) - ) - (call $log-f32 - (f32.const 2147483648) - ) - ) - ) - ) - (br_if $label$3 - (br_if $label$2 - (select - (i32.const 4612) - (local.get $1) - (local.get $1) - ) - (if - (i32.eqz - (i64.le_s - (local.get $2) - (local.get $2) - ) - ) - (block $label$10 - (br $label$3) - ) - (local.tee $1 - (if - (if (result i32) - (i32.const -16) - (block - (select (if (result i32) - (i32.popcnt - (call $hashMemory) - ) - (block $label$15 (result i32) - (call $log-f32 - (f32.const 1291) - ) - (global.get $global$3) - ) - (block $label$16 - (call $log-i64 - (i64.const 1304720377604164420) - ) - (br $label$3) - ) - ) - (block $label$17 - (call $log-v128 - (i32x4.ne - (local.get $4) - (v128.const i32x4 0xffe3e76d 0x41dfffff 0xd70a3d70 0x3ffb70a3) + (if (result i32) + (i32.eqz + (local.get $2) ) - ) - (br $label$3) - ) - (if (result i32) - (block $label$11 (result i32) - (nop) (i32.const 127) + (i32.const -128) ) - (block $label$12 (result i32) - (call $log-v128 - (if (result v128) - (f32.ge - (f32.const -nan:0x7fffed) - (f32.mul - (f32.const -nan:0x7ffffc) - (f32.const -nan:0x7ffffc) - ) - ) - (v128.const i32x4 0x110b0c03 0x241c171e 0xffffffe9 0xffffffff) - (local.tee $4 - (local.tee $4 - (v128.const i32x4 0x00000000 0xfe000000 0xffffffff 0x00000fff) - ) - ) - ) - ) - (br_if $label$12 - (local.get $1) - (local.get $1) - ) - ) - (block $label$13 (result i32) - (v128.store offset=4 align=1 - (i32.and - (local.get $1) - (i32.const 15) - ) - (loop $label$14 (result v128) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (i64x2.splat - (i64.const 32767) - ) - ) - ) - (local.get $1) - ) + (i32.const 26) + (i32.const -32768) ) ) - (drop - (i32.atomic.load offset=4 - (i32.and - (i64.lt_u - (local.get $2) - (local.tee $2 - (i64.extend_i32_u - (local.get $1) - ) - ) - ) - (i32.const 15) - ) - ) + (block $label$7 + (atomic.fence) + (br $label$3) ) ) - (block $label$18 (result i32) - (call $log-i32 - (br_if $label$18 - (local.tee $1 - (br_if $label$18 - (ref.is_null - (ref.null exn) - ) - (i32.eqz - (i32.const 1997038858) - ) - ) - ) - (i32.eqz - (i8x16.extract_lane_u 3 - (tuple.extract 1 - (tuple.make - (f64.const 2) - (select - (local.get $4) - (v128.const i32x4 0x5b800000 0x4e800000 0x53000000 0x5f800000) - (i32.const -255) - ) - (ref.null any) - (ref.null func) - (f32x4.extract_lane 1 - (local.get $4) - ) - ) - ) - ) - ) - ) - ) - (br $label$3) + ) + ) + (tuple.extract 4 + (tuple.make + (ref.null extern) + (i32.const 126) + (f32.const 2.5923033978570846e-30) + (i64.const 6796583934299212805) + (v128.const i32x4 0x00000008 0x00000000 0x000000fe 0x00000000) + ) + ) + ) + (v128.const i32x4 0x0057ff7f 0x00470000 0x00014359 0x007f3028) + ) + ) + (atomic.notify offset=3 + (i32.and + (if (result i32) + (i32.eqz + (f32.ge + (f32.sqrt + (f32.const -0.1029999852180481) + ) + (f32x4.extract_lane 0 + (v128.const i32x4 0x080a617e 0xcf000000 0xda800000 0xc20c0000) ) ) - (block $label$19 - (loop $label$20 - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$21 - (call $log-f64 - (local.tee $0 - (local.tee $0 - (local.get $3) - ) - ) - ) - (call $log-i32 - (local.get $1) + ) + (select + (local.tee $0 + (local.tee $2 + (local.tee $2 + (local.tee $2 + (local.get $2) ) ) ) - (br $label$3) ) - (block $label$22 - (call $log-v128 - (local.tee $4 - (loop $label$23 (result v128) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block (result v128) - (block $label$24 - (call $log-i64 - (local.tee $2 - (i64.const 576460752303423488) - ) - ) - (loop $label$25 - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block - (block $label$26 - (local.set $5 - (local.get $5) - ) - (call $log-v128 - (v128.const i32x4 0x00000014 0xffff8000 0x00000800 0xffffffe5) - ) - ) - (br_if $label$25 - (i32.eqz - (local.get $1) - ) - ) - (call $log-i32 - (call $hashMemory) - ) - ) - ) - ) - (br_if $label$23 - (i32.eqz - (loop $label$27 (result i32) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block (result i32) - (call $log-f32 - (loop $label$28 (result f32) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (f32.const 1) - ) - ) - (br_if $label$27 - (i32.eqz - (i32.atomic.load16_u offset=1 - (i32.and - (i32.const -11) - (i32.const 15) - ) - ) - ) - ) - (if (result i32) - (i32.const 358420504) - (local.get $1) - (block $label$29 (result i32) - (nop) - (local.get $1) - ) - ) - ) - ) - ) - ) - (local.get $4) + (local.get $2) + (i32.const 0) + ) + (local.tee $0 + (br_if $label$5 + (f64.gt + (select + (local.get $1) + (if (result f64) + (i32.eqz + (local.get $2) ) + (local.get $1) + (f64.const 2.5823598491911832e-236) ) + (local.get $0) ) + (local.get $1) ) - (br $label$3) + (i32.const 609887560) ) ) ) + (i32.const 15) + ) + (i64.eq + (tuple.extract 0 + (tuple.make + (i64.const 82) + (i32.const 0) + ) + ) + (i64.const 2147483646) ) ) ) - (v128.store offset=22 - (i32.and - (global.get $global$3) - (i32.const 15) - ) - (local.get $4) - ) ) ) - (block $label$31 - (return) - ) ) ) - (return) + (br $label$0) + ) + ) + ) + (f32.demote_f64 + (block $label$2 + (call_indirect (type $f32_=>_none) + (f32.div + (f32.const 4189) + (f32.const 1396855168) + ) + (i32.atomic.rmw8.cmpxchg_u offset=3 + (i32.and + (call $hashMemory) + (i32.const 15) + ) + (local.tee $0 + (local.get $2) + ) + (i32.const -94) + ) ) + (br $label$0) ) - (i32.const 15) ) + (f32.const -2147483648) + ) + ) + (call_indirect (type $f32_=>_none) + (f32.sqrt + (f32.const -0.1029999852180481) + ) + (i32.atomic.rmw8.cmpxchg_u offset=3 + (i32.and + (call $hashMemory) + (i32.const 2147483647) + ) + (local.tee $0 + (local.get $2) + ) + (i32.const 536870912) ) ) ) ) - (func $func_11 (param $0 anyref) (param $1 funcref) (param $2 externref) (result f32) + (func $func_10 (result f32 i64 funcref) + (local $0 i64) + (local $1 (exnref exnref exnref exnref f32)) + (local $2 externref) + (local $3 (v128 funcref)) + (local $4 externref) + (local $5 (i32 f32)) (block (if (i32.eqz (global.get $hangLimit) ) (return - (f32.const 510.8139953613281) + (tuple.make + (f32.const 2047.8480224609375) + (i64.const -127) + (ref.null func) + ) ) ) (global.set $hangLimit @@ -841,38 +677,50 @@ ) ) ) - (f32.const 4503599627370496) + (block $label$0 (result f32 i64 funcref) + (call $log-f64 + (f64.const 1.44) + ) + (call $log-i32 + (call $hashMemory) + ) + (tuple.make + (f32.const 527435904) + (i64.const 2147483648) + (ref.null func) + ) + ) ) - (func $func_11_invoker + (func $func_10_invoker (drop - (call $func_11 - (ref.null any) - (ref.func $func_7) - (ref.null extern) - ) + (call $func_10) + ) + (call $log-i32 + (call $hashMemory) ) (drop - (call $func_11 - (ref.null any) - (ref.func $log-f64) - (ref.null extern) - ) + (call $func_10) ) (call $log-i32 (call $hashMemory) ) ) - (func $func_13 (result v128) - (local $0 i32) - (local $1 exnref) - (local $2 f64) + (func $func_12 (result funcref) + (local $0 anyref) + (local $1 eqref) + (local $2 i64) + (local $3 (anyref exnref i64 i32 anyref v128)) + (local $4 externref) + (local $5 anyref) + (local $6 f32) + (local $7 v128) (block (if (i32.eqz (global.get $hangLimit) ) (return - (v128.const i32x4 0x016d0001 0x7a01017f 0x7901016d 0x00800056) + (ref.func $func_10) ) ) (global.set $hangLimit @@ -882,29 +730,270 @@ ) ) ) - (tuple.extract 0 - (tuple.make - (v128.const i32x4 0x41430000 0x00405556 0x2020ffdd 0x0005080a) - (i32.const 32768) + (ref.null func) + ) + (func $func_13 (param $0 exnref) (result eqref eqref eqref eqref eqref) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return + (tuple.make + (ref.null eq) + (ref.null eq) + (ref.null eq) + (ref.null eq) + (ref.null eq) + ) + ) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block $label$0 + (return + (tuple.make + (ref.null eq) + (ref.null eq) + (ref.null eq) + (ref.null eq) + (ref.null eq) + ) ) ) ) - (func $func_14 (result i32 anyref externref) - (local $0 i64) - (local $1 i32) + (func $func_13_invoker + (drop + (call $func_13 + (ref.null exn) + ) + ) + ) + (func $func_15 (param $0 anyref) (param $1 eqref) (result f64) + (local $2 (f64 eqref funcref i32)) + (local $3 v128) + (local $4 i64) (block (if (i32.eqz (global.get $hangLimit) ) (return - (tuple.make - (i32.const 127) - (ref.null any) - (ref.null extern) + (f64.const 303201560) + ) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (f64.const 1.8039635330443502e-221) + ) + (func $func_16 (param $0 funcref) (param $1 f64) (result v128) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return + (v128.const i32x4 0x00000000 0x41400000 0x00000000 0x40458000) + ) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block $label$0 + (if + (i32.const 10793) + (call_indirect (type $f32_=>_none) + (f32.const 3402823466385288598117041e14) + (i32.const 0) + ) + (block $label$1 + (call $log-i32 + (call $hashMemory) + ) + (call $log-f32 + (loop $label$2 (result f32) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return + (v128.const i32x4 0x41700000 0x5f000000 0x3f800000 0x41a00000) + ) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block (result f32) + (block $label$3 + (call $log-i32 + (call $hashMemory) + ) + (call $log-v128 + (loop $label$4 (result v128) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return + (v128.const i32x4 0x152dffff 0x8000ffa4 0x1f484608 0x02193720) + ) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block $label$5 (result v128) + (call $log-i32 + (i32.const -1) + ) + (v128.const i32x4 0x00020000 0xff8000b0 0xffb40001 0xffff5657) + ) + ) + ) + ) + (br_if $label$2 + (if (result i32) + (i32.eqz + (f32.ge + (f32.const 3402823466385288598117041e14) + (f32.const 3402823466385288598117041e14) + ) + ) + (i32.const 0) + (i32.const -65537) + ) + ) + (f32.const 0.004999999888241291) + ) + ) ) ) ) + (return + (v128.const i32x4 0x1b145c08 0xffffffe0 0x00400000 0x00000052) + ) + ) + ) + (func $func_17 (param $0 v128) (param $1 anyref) (param $2 f32) (result funcref) + (local $3 i64) + (local $4 (externref i32)) + (local $5 i32) + (local $6 f64) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return + (ref.func $log-exnref) + ) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (ref.null func) + ) + (func $func_18 (param $0 externref) (param $1 i32) (param $2 v128) (param $3 i64) (result externref) + (local $4 funcref) + (local $5 eqref) + (local $6 eqref) + (local $7 (f64 funcref f64 i32)) + (local $8 externref) + (local $9 i32) + (local $10 i64) + (local $11 eqref) + (local $12 externref) + (local $13 funcref) + (local $14 f64) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return + (local.get $8) + ) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (block $label$0 (result externref) + (nop) + (local.get $0) + ) + ) + (func $func_19 (param $0 f32) (param $1 eqref) (result anyref) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return + (ref.null any) + ) + ) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) + ) + ) + (ref.null any) + ) + (func $func_19_invoker + (drop + (call $func_19 + (f32.const 58) + (ref.null eq) + ) + ) + (call $log-i32 + (call $hashMemory) + ) + ) + (func $func_21 (param $0 v128) (result funcref) + (local $1 i64) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return + (ref.func $hashMemory) + ) + ) (global.set $hangLimit (i32.sub (global.get $hangLimit) @@ -912,25 +1001,28 @@ ) ) ) - (block $label$0 (result i32 anyref externref) - (f64.store offset=2 - (select - (local.get $1) - (local.get $1) - (if - (i32.eqz - (loop $label$6 (result i32) + (block $label$0 (result funcref) + (drop + (tuple.make + (ref.null exn) + (ref.null eq) + (i32.const 26) + (v128.const i32x4 0x1715037b 0x00000027 0x000007ff 0xf8000000) + (f64.const 9.532824124368358e-130) + ) + ) + (block $label$1 + (block $label$2 + (local.tee $1 + (i64.shr_s + (loop $label$3 (result i64) (block (if (i32.eqz (global.get $hangLimit) ) (return - (tuple.make - (i32.const 40) - (ref.null any) - (ref.null extern) - ) + (ref.func $log-f32) ) ) (global.set $hangLimit @@ -940,173 +1032,96 @@ ) ) ) - (block (result i32) + (block (result i64) (nop) - (br_if $label$6 + (br_if $label$3 (i32.eqz - (i32x4.extract_lane 0 - (v128.load offset=2 align=4 - (i16x8.extract_lane_u 5 - (if (result v128) - (local.get $1) - (block $label$7 (result v128) - (nop) - (v128.const i32x4 0xffff8001 0xffffffff 0x4d2b4835 0x00000000) - ) - (block $label$8 (result v128) - (block $label$9 - (call $log-i32 - (call $hashMemory) - ) - (nop) - ) - (v128.const i32x4 0x0d756b0d 0x0d0f0301 0x60626c7f 0x07092727) - ) - ) - ) - ) - ) + (i32.const -32766) ) ) - (block $label$10 (result i32) - (loop $label$11 - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (tuple.make - (i32.const 1499027801) - (ref.null any) - (ref.null extern) - ) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) + (i64.trunc_f32_s + (f32.min + (f32.load offset=3 + (i32.and + (i32.const 454758683) + (i32.const 15) ) ) - (block - (br_if $label$6 - (loop $label$12 (result i32) - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (tuple.make - (i32.const -90) - (ref.null any) - (ref.null extern) - ) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (block $label$13 (result i32) - (data.drop 0) - (i32.const 2) - ) - ) - ) - (br_if $label$11 - (local.get $1) - ) - (loop $label$14 - (block - (if - (i32.eqz - (global.get $hangLimit) - ) - (return - (tuple.make - (i32.const -88) - (ref.null any) - (ref.null extern) - ) - ) - ) - (global.set $hangLimit - (i32.sub - (global.get $hangLimit) - (i32.const 1) - ) - ) - ) - (f32.store offset=4 align=2 - (i32.and - (i32.atomic.rmw8.or_u offset=4 - (i32.and - (i32.const 13) - (i32.const 15) - ) - (atomic.notify offset=22 - (i32.and - (local.get $1) - (i32.const 15) - ) - (br_if $label$10 - (local.get $1) - (i32.eqz - (local.get $1) - ) - ) - ) - ) - (i32.const 15) - ) - (f32.const 18446744073709551615) - ) + (f32.const 1023.5869750976562) + ) + ) + ) + ) + (if + (i32.eqz + (i32.const 2049) + ) + (block $label$4 + (nop) + (br $label$1) + ) + (block $label$5 + (i64.store16 offset=2 + (i32.and + (block $label$6 (result i32) + (call $log-i64 + (i64.const 1949228928397086024) ) + (i32.const 2) ) + (i32.const 15) ) - (br $label$6) + (local.get $1) ) + (br $label$2) ) ) ) - (block $label$16 - (nop) - (return - (tuple.make - (i32.const 33554433) - (ref.null any) - (ref.null extern) + ) + (nop) + ) + (block $label$7 + (nop) + ) + ) + (call $func_21 + (if (result v128) + (i32.eqz + (i32.const 760829235) + ) + (block $label$8 + (return + (ref.null func) + ) + ) + (loop $label$9 (result v128) + (block + (if + (i32.eqz + (global.get $hangLimit) + ) + (return + (ref.func $func_19) ) ) - ) - (block $label$17 - (call $log-i32 - (call $hashMemory) + (global.set $hangLimit + (i32.sub + (global.get $hangLimit) + (i32.const 1) + ) ) - (return - (tuple.make - (i32.const 0) - (ref.null any) - (ref.null extern) + ) + (block (result v128) + (nop) + (br_if $label$9 + (ref.is_null + (global.get $global$2) ) ) + (local.get $0) ) ) ) - (f64x2.extract_lane 0 - (v128.const i32x4 0x14171109 0x0109440d 0x10031007 0x021d1401) - ) - ) - (tuple.make - (i32.const 65534) - (ref.null any) - (ref.null extern) ) ) ) diff --git a/test/unit/input/gc_target_feature.wasm b/test/unit/input/gc_target_feature.wasm Binary files differindex cd094ca3a..ccabbc16e 100644 --- a/test/unit/input/gc_target_feature.wasm +++ b/test/unit/input/gc_target_feature.wasm diff --git a/test/unit/test_features.py b/test/unit/test_features.py index 4a82f8cc2..a44d58bbd 100644 --- a/test/unit/test_features.py +++ b/test/unit/test_features.py @@ -276,6 +276,24 @@ class FeatureValidationTest(utils.BinaryenTestCase): ''' self.check_gc(module, 'all used types should be allowed') + def test_eqref_global(self): + module = ''' + (module + (global $foo eqref (ref.null eq)) + ) + ''' + self.check_gc(module, 'all used types should be allowed') + + def test_eqref_local(self): + module = ''' + (module + (func $foo + (local $0 eqref) + ) + ) + ''' + self.check_gc(module, 'all used types should be allowed') + class TargetFeaturesSectionTest(utils.BinaryenTestCase): def test_atomics(self): @@ -337,7 +355,9 @@ class TargetFeaturesSectionTest(utils.BinaryenTestCase): filename = 'gc_target_feature.wasm' self.roundtrip(filename) self.check_features(filename, ['reference-types', 'gc']) - self.assertIn('anyref', self.disassemble(filename)) + disassembly = self.disassemble(filename) + self.assertIn('anyref', disassembly) + self.assertIn('eqref', disassembly) def test_incompatible_features(self): path = self.input_path('signext_target_feature.wasm') |