diff options
author | Daniel Wirtz <dcode@dcode.io> | 2020-09-11 03:04:17 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-10 18:04:17 -0700 |
commit | 192757772adce7568fc1f3f3e733a4263b6392c6 (patch) | |
tree | 922fec8709cf9008d239a1fcbce7280e6ab46deb /src | |
parent | cd6f0d908f0e4c68d72fd476a6e0e7cfb7ae8595 (diff) | |
download | binaryen-192757772adce7568fc1f3f3e733a4263b6392c6.tar.gz binaryen-192757772adce7568fc1f3f3e733a4263b6392c6.tar.bz2 binaryen-192757772adce7568fc1f3f3e733a4263b6392c6.zip |
Add anyref feature and type (#3109)
Adds `anyref` type, which is enabled by a new feature `--enable-anyref`. This type is primarily used for testing that passes correctly handle subtype relationships so that the codebase will continue to be prepared for future subtyping. Since `--enable-anyref` is meaningless without also using `--enable-reference-types`, this PR also makes it a validation error to pass only the former (and similarly makes it a validation error to enable exception handling without enabling reference types).
Diffstat (limited to 'src')
-rw-r--r-- | src/asmjs/asm_v_wasm.cpp | 3 | ||||
-rw-r--r-- | src/binaryen-c.cpp | 6 | ||||
-rw-r--r-- | src/binaryen-c.h | 2 | ||||
-rw-r--r-- | src/gen-s-parser.inc | 18 | ||||
-rw-r--r-- | src/ir/abstract.h | 2 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 8 | ||||
-rw-r--r-- | src/literal.h | 1 | ||||
-rw-r--r-- | src/parsing.h | 1 | ||||
-rw-r--r-- | src/passes/ConstHoisting.cpp | 3 | ||||
-rw-r--r-- | src/passes/FuncCastEmulation.cpp | 6 | ||||
-rw-r--r-- | src/passes/InstrumentLocals.cpp | 26 | ||||
-rw-r--r-- | src/shell-interface.h | 1 | ||||
-rw-r--r-- | src/tools/fuzzing.h | 33 | ||||
-rw-r--r-- | src/tools/spec-wrapper.h | 3 | ||||
-rw-r--r-- | src/tools/tool-options.h | 1 | ||||
-rw-r--r-- | src/tools/wasm-reduce.cpp | 5 | ||||
-rw-r--r-- | src/wasm-binary.h | 9 | ||||
-rw-r--r-- | src/wasm-builder.h | 2 | ||||
-rw-r--r-- | src/wasm-features.h | 7 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 2 | ||||
-rw-r--r-- | src/wasm-type.h | 15 | ||||
-rw-r--r-- | src/wasm/literal.cpp | 14 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 8 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 3 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 3 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 34 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 17 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 1 |
28 files changed, 203 insertions, 31 deletions
diff --git a/src/asmjs/asm_v_wasm.cpp b/src/asmjs/asm_v_wasm.cpp index ddcb27d3d..8d2894f13 100644 --- a/src/asmjs/asm_v_wasm.cpp +++ b/src/asmjs/asm_v_wasm.cpp @@ -57,6 +57,7 @@ AsmType wasmToAsmType(Type type) { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: assert(false && "reference types are not supported by asm2wasm"); case Type::none: return ASM_NONE; @@ -85,6 +86,8 @@ char getSig(Type type) { return 'X'; case Type::exnref: return 'E'; + case Type::anyref: + return 'A'; case Type::none: return 'v'; case Type::unreachable: diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 9b2da350d..e11b762dd 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -73,6 +73,7 @@ BinaryenLiteral toBinaryenLiteral(Literal x) { break; case Type::externref: case Type::exnref: + case Type::anyref: assert(x.isNull()); break; case Type::none: @@ -98,6 +99,7 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) { return Literal::makeFunc(x.func); case Type::externref: case Type::exnref: + case Type::anyref: return Literal::makeNull(Type(x.type)); case Type::none: case Type::unreachable: @@ -133,6 +135,7 @@ BinaryenType BinaryenTypeVec128(void) { return Type::v128; } 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 BinaryenTypeUnreachable(void) { return Type::unreachable; } BinaryenType BinaryenTypeAuto(void) { return uintptr_t(-1); } @@ -324,6 +327,9 @@ BinaryenFeatures BinaryenFeatureReferenceTypes(void) { BinaryenFeatures BinaryenFeatureMultivalue(void) { return static_cast<BinaryenFeatures>(FeatureSet::Multivalue); } +BinaryenFeatures BinaryenFeatureAnyref(void) { + return static_cast<BinaryenFeatures>(FeatureSet::Anyref); +} BinaryenFeatures BinaryenFeatureAll(void) { return static_cast<BinaryenFeatures>(FeatureSet::All); } diff --git a/src/binaryen-c.h b/src/binaryen-c.h index beaf72499..e622419ac 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -101,6 +101,7 @@ BINARYEN_API BinaryenType BinaryenTypeVec128(void); BINARYEN_API BinaryenType BinaryenTypeFuncref(void); BINARYEN_API BinaryenType BinaryenTypeExternref(void); BINARYEN_API BinaryenType BinaryenTypeExnref(void); +BINARYEN_API BinaryenType BinaryenTypeAnyref(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. @@ -196,6 +197,7 @@ BINARYEN_API BinaryenFeatures BinaryenFeatureExceptionHandling(void); BINARYEN_API BinaryenFeatures BinaryenFeatureTailCall(void); BINARYEN_API BinaryenFeatures BinaryenFeatureReferenceTypes(void); BINARYEN_API BinaryenFeatures BinaryenFeatureMultivalue(void); +BINARYEN_API BinaryenFeatures BinaryenFeatureAnyref(void); BINARYEN_API BinaryenFeatures BinaryenFeatureAll(void); // Modules diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 97ba15c32..4b02b09c2 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -8,13 +8,21 @@ char op[27] = {'\0'}; strncpy(op, s[0]->c_str(), 26); switch (op[0]) { case 'a': { - switch (op[7]) { - case 'f': - if (strcmp(op, "atomic.fence") == 0) { return makeAtomicFence(s); } - goto parse_error; + switch (op[1]) { case 'n': - if (strcmp(op, "atomic.notify") == 0) { return makeAtomicNotify(s); } + if (strcmp(op, "anyref.pop") == 0) { return makePop(Type::anyref); } goto parse_error; + case 't': { + switch (op[7]) { + case 'f': + if (strcmp(op, "atomic.fence") == 0) { return makeAtomicFence(s); } + goto parse_error; + case 'n': + if (strcmp(op, "atomic.notify") == 0) { return makeAtomicNotify(s); } + goto parse_error; + default: goto parse_error; + } + } default: goto parse_error; } } diff --git a/src/ir/abstract.h b/src/ir/abstract.h index b00537bf5..5f1fd393e 100644 --- a/src/ir/abstract.h +++ b/src/ir/abstract.h @@ -104,6 +104,7 @@ inline UnaryOp getUnary(Type type, Op op) { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: { return InvalidUnary; @@ -268,6 +269,7 @@ inline BinaryOp getBinary(Type type, Op op) { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: 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 66de10848..fd121b8af 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -36,6 +36,7 @@ function initializeConstants() { ['funcref', 'Funcref'], ['externref', 'Externref'], ['exnref', 'Exnref'], + ['anyref', 'Anyref'], ['unreachable', 'Unreachable'], ['auto', 'Auto'] ].forEach(entry => { @@ -120,6 +121,7 @@ function initializeConstants() { 'TailCall', 'ReferenceTypes', 'Multivalue', + 'Anyref', 'All' ].forEach(name => { Module['Features'][name] = Module['_BinaryenFeature' + name](); @@ -2063,6 +2065,12 @@ function wrapModule(module, self = {}) { } }; + self['anyref'] = { + 'pop'() { + return Module['_BinaryenPop'](module, Module['anyref']); + } + }; + self['ref'] = { 'null'(type) { return Module['_BinaryenRefNull'](module, type); diff --git a/src/literal.h b/src/literal.h index 1b3949d21..981f5b6d4 100644 --- a/src/literal.h +++ b/src/literal.h @@ -579,6 +579,7 @@ template<> struct less<wasm::Literal> { case wasm::Type::funcref: case wasm::Type::externref: case wasm::Type::exnref: + case wasm::Type::anyref: case wasm::Type::none: case wasm::Type::unreachable: return false; diff --git a/src/parsing.h b/src/parsing.h index 663b901fd..d809cbedd 100644 --- a/src/parsing.h +++ b/src/parsing.h @@ -266,6 +266,7 @@ parseConst(cashew::IString s, Type type, MixedArena& allocator) { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: WASM_UNREACHABLE("unexpected const type"); case Type::none: case Type::unreachable: { diff --git a/src/passes/ConstHoisting.cpp b/src/passes/ConstHoisting.cpp index e3583d3bb..3b34751ff 100644 --- a/src/passes/ConstHoisting.cpp +++ b/src/passes/ConstHoisting.cpp @@ -96,7 +96,8 @@ private: case Type::v128: case Type::funcref: case Type::externref: - case Type::exnref: { + case Type::exnref: + case Type::anyref: { return false; } case Type::none: diff --git a/src/passes/FuncCastEmulation.cpp b/src/passes/FuncCastEmulation.cpp index 160895f23..101834790 100644 --- a/src/passes/FuncCastEmulation.cpp +++ b/src/passes/FuncCastEmulation.cpp @@ -67,7 +67,8 @@ static Expression* toABI(Expression* value, Module* module) { } case Type::funcref: case Type::externref: - case Type::exnref: { + case Type::exnref: + case Type::anyref: { WASM_UNREACHABLE("reference types cannot be converted to i64"); } case Type::none: { @@ -110,7 +111,8 @@ static Expression* fromABI(Expression* value, Type type, Module* module) { } case Type::funcref: case Type::externref: - case Type::exnref: { + case Type::exnref: + case Type::anyref: { 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 ee288c103..b1ce5f05e 100644 --- a/src/passes/InstrumentLocals.cpp +++ b/src/passes/InstrumentLocals.cpp @@ -59,6 +59,7 @@ Name get_f64("get_f64"); Name get_funcref("get_funcref"); Name get_externref("get_externref"); Name get_exnref("get_exnref"); +Name get_anyref("get_anyref"); Name get_v128("get_v128"); Name set_i32("set_i32"); @@ -68,6 +69,7 @@ Name set_f64("set_f64"); Name set_funcref("set_funcref"); Name set_externref("set_externref"); Name set_exnref("set_exnref"); +Name set_anyref("set_anyref"); Name set_v128("set_v128"); struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> { @@ -99,6 +101,9 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> { case Type::exnref: import = get_exnref; break; + case Type::anyref: + import = get_anyref; + break; case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -145,6 +150,9 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> { case Type::exnref: import = set_exnref; break; + case Type::anyref: + import = set_anyref; + break; case Type::unreachable: return; // nothing to do here case Type::none: @@ -184,12 +192,18 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> { set_externref, {Type::i32, Type::i32, Type::externref}, Type::externref); - } - if (curr->features.hasExceptionHandling()) { - addImport( - curr, get_exnref, {Type::i32, Type::i32, Type::exnref}, Type::exnref); - addImport( - curr, set_exnref, {Type::i32, Type::i32, Type::exnref}, Type::exnref); + if (curr->features.hasExceptionHandling()) { + addImport( + curr, get_exnref, {Type::i32, Type::i32, Type::exnref}, Type::exnref); + addImport( + curr, set_exnref, {Type::i32, Type::i32, Type::exnref}, Type::exnref); + } + if (curr->features.hasAnyref()) { + addImport( + curr, get_anyref, {Type::i32, Type::i32, Type::anyref}, Type::anyref); + addImport( + curr, set_anyref, {Type::i32, Type::i32, Type::anyref}, Type::anyref); + } } if (curr->features.hasSIMD()) { addImport(curr, get_v128, {Type::i32, Type::i32, Type::v128}, Type::v128); diff --git a/src/shell-interface.h b/src/shell-interface.h index 92f562b48..ae86d13ec 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -118,6 +118,7 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: globals[import->name] = {Literal::makeNull(import->type)}; break; case Type::none: diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index ef7844c60..9768b63c4 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -315,7 +315,20 @@ private: } SmallVector<Type, 2> options; options.push_back(type); // includes itself - // TODO (GC): subtyping + TODO_SINGLE_COMPOUND(type); + switch (type.getBasic()) { + case Type::anyref: + if (wasm.features.hasReferenceTypes()) { + options.push_back(Type::funcref); + options.push_back(Type::externref); + if (wasm.features.hasExceptionHandling()) { + options.push_back(Type::exnref); + } + } + break; + default: + break; + } return pick(options); } @@ -1349,6 +1362,7 @@ private: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("invalid type"); @@ -1452,6 +1466,7 @@ private: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("invalid type"); @@ -1580,6 +1595,7 @@ private: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("invalid type"); @@ -1624,6 +1640,7 @@ private: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -1691,6 +1708,7 @@ private: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -1717,6 +1735,7 @@ private: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -1826,6 +1845,7 @@ private: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: return makeTrivial(type); case Type::none: case Type::unreachable: @@ -1970,6 +1990,7 @@ private: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -2206,6 +2227,7 @@ private: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -2412,6 +2434,7 @@ private: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -2592,6 +2615,9 @@ private: if (wasm.features.hasExceptionHandling()) { options.push_back(Type::exnref); } + if (wasm.features.hasAnyref()) { + options.push_back(Type::anyref); + } return builder.makeRefIsNull(make(pick(options))); } @@ -2657,7 +2683,8 @@ private: .add(FeatureSet::SIMD, Type::v128) .add(FeatureSet::ReferenceTypes, Type::funcref, Type::externref) .add(FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling, - Type::exnref)); + Type::exnref) + .add(FeatureSet::ReferenceTypes | FeatureSet::Anyref, Type::anyref)); } Type getSingleConcreteType() { return pick(getSingleConcreteTypes()); } @@ -2697,7 +2724,7 @@ private: // - funcref cannot be logged because referenced functions can be inlined or // removed during optimization - // - there's no point in logging externref because it is opaque + // - there's no point in logging externref or anyref because these are opaque // - don't bother logging tuples std::vector<Type> getLoggableTypes() { return items( diff --git a/src/tools/spec-wrapper.h b/src/tools/spec-wrapper.h index c073a994c..200571fd0 100644 --- a/src/tools/spec-wrapper.h +++ b/src/tools/spec-wrapper.h @@ -58,6 +58,9 @@ static std::string generateSpecWrapper(Module& wasm) { case Type::exnref: ret += "(ref.null exn)"; break; + case Type::anyref: + ret += "(ref.null any)"; + break; case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h index f04b95304..082e95549 100644 --- a/src/tools/tool-options.h +++ b/src/tools/tool-options.h @@ -87,6 +87,7 @@ struct ToolOptions : public Options { .addFeature(FeatureSet::TailCall, "tail call operations") .addFeature(FeatureSet::ReferenceTypes, "reference types") .addFeature(FeatureSet::Multivalue, "multivalue functions") + .addFeature(FeatureSet::Anyref, "anyref type (without GC)") .add("--no-validation", "-n", "Disables validation, assumes inputs are correct", diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp index 1a7c3544d..7410ff91e 100644 --- a/src/tools/wasm-reduce.cpp +++ b/src/tools/wasm-reduce.cpp @@ -598,6 +598,7 @@ struct Reducer case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: continue; // not implemented yet case Type::none: case Type::unreachable: @@ -623,6 +624,7 @@ struct Reducer case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: continue; // not implemented yet case Type::none: case Type::unreachable: @@ -648,6 +650,7 @@ struct Reducer case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: continue; // not implemented yet case Type::none: case Type::unreachable: @@ -673,6 +676,7 @@ struct Reducer case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: continue; // not implemented yet case Type::none: case Type::unreachable: @@ -684,6 +688,7 @@ struct Reducer case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: continue; // not implemented yet case Type::none: case Type::unreachable: diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 865a882df..33f78ce7f 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -347,6 +347,8 @@ enum EncodedType { funcref = -0x10, // 0x70 // opaque host reference type externref = -0x11, // 0x6f + // any reference type + anyref = -0x12, // 0x6e // exception reference type exnref = -0x18, // 0x68 // func_type form @@ -358,6 +360,7 @@ enum EncodedType { enum EncodedHeapType { func = -0x10, // 0x70 extern_ = -0x11, // 0x6f + any = -0x12, // 0x6e exn = -0x18, // 0x68 }; @@ -380,6 +383,7 @@ extern const char* ExceptionHandlingFeature; extern const char* TailCallFeature; extern const char* ReferenceTypesFeature; extern const char* MultivalueFeature; +extern const char* AnyrefFeature; enum Subsection { NameFunction = 1, @@ -975,6 +979,9 @@ inline S32LEB binaryType(Type type) { case Type::exnref: ret = BinaryConsts::EncodedType::exnref; break; + case Type::anyref: + ret = BinaryConsts::EncodedType::anyref; + break; case Type::unreachable: WASM_UNREACHABLE("unexpected type"); } @@ -994,6 +1001,8 @@ inline S32LEB binaryHeapType(HeapType type) { ret = BinaryConsts::EncodedHeapType::exn; break; case HeapType::AnyKind: + ret = BinaryConsts::EncodedHeapType::any; + break; case HeapType::EqKind: case HeapType::I31Kind: case HeapType::SignatureKind: diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 1ce3a507c..6c1923482 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -631,6 +631,7 @@ public: return makeRefNull(value.type); case Type::externref: case Type::exnref: // TODO: ExceptionPackage? + case Type::anyref: assert(value.isNull()); return makeRefNull(value.type); default: @@ -825,6 +826,7 @@ public: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: return ExpressionManipulator::refNull(curr, curr->type); case Type::none: return ExpressionManipulator::nop(curr); diff --git a/src/wasm-features.h b/src/wasm-features.h index c35ff0442..5d05b6284 100644 --- a/src/wasm-features.h +++ b/src/wasm-features.h @@ -36,7 +36,8 @@ struct FeatureSet { TailCall = 1 << 7, ReferenceTypes = 1 << 8, Multivalue = 1 << 9, - All = (1 << 10) - 1 + Anyref = 1 << 10, + All = (1 << 11) - 1 }; static std::string toString(Feature f) { @@ -61,6 +62,8 @@ struct FeatureSet { return "reference-types"; case Multivalue: return "multivalue"; + case Anyref: + return "anyref"; default: WASM_UNREACHABLE("unexpected feature"); } @@ -84,6 +87,7 @@ struct FeatureSet { bool hasTailCall() const { return (features & TailCall) != 0; } bool hasReferenceTypes() const { return (features & ReferenceTypes) != 0; } bool hasMultivalue() const { return (features & Multivalue) != 0; } + bool hasAnyref() const { return (features & Anyref) != 0; } bool hasAll() const { return (features & All) != 0; } void makeMVP() { features = MVP; } @@ -100,6 +104,7 @@ struct FeatureSet { void setTailCall(bool v = true) { set(TailCall, v); } void setReferenceTypes(bool v = true) { set(ReferenceTypes, v); } void setMultivalue(bool v = true) { set(Multivalue, v); } + void setAnyref(bool v = true) { set(Anyref, v); } void setAll(bool v = true) { features = v ? All : MVP; } void enable(const FeatureSet& other) { features |= other.features; } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 44cac9d49..361545a2c 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1647,6 +1647,7 @@ public: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -1703,6 +1704,7 @@ public: case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); diff --git a/src/wasm-type.h b/src/wasm-type.h index 384cc589f..f3973068f 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -50,7 +50,8 @@ public: funcref, externref, exnref, - _last_basic_id = exnref + anyref, + _last_basic_id = anyref }; Type() = default; @@ -88,11 +89,11 @@ public: // │ v128 ║ x │ │ x │ x │ V │ ┘ // ├─ Aliases ───╫───┼───┼───┼───┤───────┤ // │ funcref ║ x │ │ x │ x │ f n │ ┐ Ref - // │ externref ║ x │ │ x │ x │ f? n │ │ f_unc, n_ullable - // │ anyref ║ x │ │ x │ x │ f? n │ │ ┐ - // │ eqref ║ x │ │ x │ x │ n │ │ │ TODO (GC) + // │ externref ║ x │ │ x │ x │ f? n │ │ f_unc + // │ exnref ║ x │ │ x │ x │ n │ │ n_ullable + // │ anyref ║ x │ │ x │ x │ f? n │ │ + // │ eqref ║ x │ │ x │ x │ n │ │ ┐ TODO (GC) // │ i31ref ║ x │ │ x │ x │ │ │ ┘ - // │ exnref ║ x │ │ x │ x │ n │ │ // ├─ Compound ──╫───┼───┼───┼───┤───────┤ │ // │ Ref ║ │ x │ x │ x │ f? n? │◄┘ // │ Tuple ║ │ x │ │ x │ │ @@ -330,11 +331,11 @@ struct HeapType { enum Kind { FuncKind, ExternKind, + ExnKind, AnyKind, EqKind, I31Kind, - ExnKind, - _last_basic_kind = ExnKind, + _last_basic_kind = I31Kind, SignatureKind, StructKind, ArrayKind, diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index ffb98abe4..39a4cea3c 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -69,6 +69,7 @@ Literal::Literal(const Literal& other) : type(other.type) { case Type::none: break; case Type::externref: + case Type::anyref: break; // null case Type::funcref: case Type::exnref: @@ -221,6 +222,7 @@ void Literal::getBits(uint8_t (&buf)[16]) const { break; case Type::externref: case Type::exnref: + case Type::anyref: if (isNull()) { break; } @@ -384,6 +386,10 @@ std::ostream& operator<<(std::ostream& o, Literal literal) { o << "exnref(" << literal.getExceptionPackage() << ")"; } break; + case Type::anyref: + assert(literal.isNull() && "TODO: non-null anyref values"); + o << "anyref(null)"; + break; case Type::externref: assert(literal.isNull() && "TODO: non-null externref values"); o << "externref(null)"; @@ -612,6 +618,7 @@ Literal Literal::eqz() const { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -633,6 +640,7 @@ Literal Literal::neg() const { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -654,6 +662,7 @@ Literal Literal::abs() const { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -758,6 +767,7 @@ Literal Literal::add(const Literal& other) const { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -779,6 +789,7 @@ Literal Literal::sub(const Literal& other) const { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -896,6 +907,7 @@ Literal Literal::mul(const Literal& other) const { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -1141,6 +1153,7 @@ Literal Literal::eq(const Literal& other) const { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -1162,6 +1175,7 @@ Literal Literal::ne(const Literal& other) const { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: 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 b78d6b86b..de82f0656 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -691,6 +691,8 @@ void WasmBinaryWriter::writeFeaturesSection() { return BinaryConsts::UserSections::ReferenceTypesFeature; case FeatureSet::Multivalue: return BinaryConsts::UserSections::MultivalueFeature; + case FeatureSet::Anyref: + return BinaryConsts::UserSections::AnyrefFeature; default: WASM_UNREACHABLE("unexpected feature flag"); } @@ -1138,6 +1140,8 @@ Type WasmBinaryBuilder::getType() { return Type::externref; case BinaryConsts::EncodedType::exnref: return Type::exnref; + case BinaryConsts::EncodedType::anyref: + return Type::anyref; default: throwError("invalid wasm type: " + std::to_string(type)); } @@ -1160,6 +1164,8 @@ HeapType WasmBinaryBuilder::getHeapType() { return HeapType::ExternKind; case BinaryConsts::EncodedHeapType::exn: return HeapType::ExnKind; + case BinaryConsts::EncodedHeapType::any: + return HeapType::AnyKind; default: throwError("invalid wasm heap type: " + std::to_string(type)); } @@ -2203,6 +2209,8 @@ void WasmBinaryBuilder::readFeatures(size_t payloadLen) { wasm.features.setReferenceTypes(); } else if (name == BinaryConsts::UserSections::MultivalueFeature) { wasm.features.setMultivalue(); + } else if (name == BinaryConsts::UserSections::AnyrefFeature) { + wasm.features.setAnyref(); } } } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index bac5f958c..e4a33c034 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -874,6 +874,9 @@ Type SExpressionWasmBuilder::stringToType(const char* str, if (strncmp(str, "exnref", 6) == 0 && (prefix || str[6] == 0)) { return Type::exnref; } + if (strncmp(str, "anyref", 6) == 0 && (prefix || str[6] == 0)) { + return Type::anyref; + } if (allowError) { return Type::none; } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index aee5079c2..64622e814 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -191,6 +191,7 @@ void BinaryInstWriter::visitLoad(Load* curr) { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: WASM_UNREACHABLE("unexpected type"); } @@ -292,6 +293,7 @@ void BinaryInstWriter::visitStore(Store* curr) { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: WASM_UNREACHABLE("unexpected type"); @@ -694,6 +696,7 @@ void BinaryInstWriter::visitConst(Const* curr) { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: 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 729cc88f5..0c49e8dcc 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -256,12 +256,13 @@ std::unordered_map<TypeInfo, uintptr_t> indices = { {TypeInfo(HeapType(HeapType::FuncKind), true), Type::funcref}, {TypeInfo({Type::externref}), Type::externref}, {TypeInfo(HeapType(HeapType::ExternKind), true), Type::externref}, + {TypeInfo({Type::exnref}), Type::exnref}, + {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 any) == anyref` // * `(ref null eq) == eqref` // * `(ref i31) == i31ref` - {TypeInfo({Type::exnref}), Type::exnref}, - {TypeInfo(HeapType(HeapType::ExnKind), true), Type::exnref}, }; } // anonymous namespace @@ -340,7 +341,7 @@ bool Type::isTuple() const { bool Type::isRef() const { if (isBasic()) { - return id >= funcref && id <= exnref; + return id >= funcref && id <= anyref; } else { return getTypeInfo(*this)->isRef(); } @@ -366,7 +367,7 @@ bool Type::isException() const { bool Type::isNullable() const { if (isBasic()) { - return id >= funcref && id <= exnref; + return id >= funcref && id <= anyref; } else { return getTypeInfo(*this)->isNullable(); } @@ -407,6 +408,7 @@ unsigned Type::getByteSize() const { case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: case Type::unreachable: break; @@ -451,6 +453,8 @@ FeatureSet Type::getFeatures() const { return FeatureSet::ReferenceTypes; case Type::exnref: return FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling; + case Type::anyref: + return FeatureSet::ReferenceTypes | FeatureSet::Anyref; default: return FeatureSet::MVP; } @@ -478,6 +482,8 @@ HeapType Type::getHeapType() const { return HeapType::ExternKind; case exnref: return HeapType::ExnKind; + case anyref: + return HeapType::AnyKind; default: break; } @@ -502,10 +508,12 @@ Type Type::get(unsigned byteSize, bool float_) { } bool Type::isSubType(Type left, Type right) { - // TODO (GC): subtyping, currently checks for equality only if (left == right) { return true; } + if (left.isRef() && right.isRef()) { + return right == Type::anyref; + } if (left.isTuple() && right.isTuple()) { if (left.size() != right.size()) { return false; @@ -533,6 +541,17 @@ Type Type::getLeastUpperBound(Type a, Type b) { if (a.size() != b.size()) { return Type::none; // a poison value that must not be consumed } + if (a.isRef()) { + if (b.isRef()) { + // 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 + // code to introduce a use of anyref via this function, but that is not a + // problem because it will be caught and rejected by validation. + return Type::anyref; + } + return Type::none; + } if (a.isTuple()) { TypeList types; types.resize(a.size()); @@ -732,6 +751,9 @@ std::ostream& operator<<(std::ostream& os, Type type) { case Type::exnref: os << "exnref"; break; + case Type::anyref: + os << "anyref"; + break; } } else { os << *getTypeInfo(type); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index c6d679a24..80c54abed 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -1363,6 +1363,7 @@ void FunctionValidator::validateMemBytes(uint8_t bytes, case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: WASM_UNREACHABLE("unexpected type"); } @@ -2176,6 +2177,7 @@ void FunctionValidator::validateAlignment( case Type::funcref: case Type::externref: case Type::exnref: + case Type::anyref: case Type::none: WASM_UNREACHABLE("invalid type"); } @@ -2475,6 +2477,20 @@ static void validateModule(Module& module, ValidationInfo& info) { } } +static void validateFeatures(Module& module, ValidationInfo& info) { + if (module.features.hasAnyref()) { + info.shouldBeTrue(module.features.hasReferenceTypes(), + module.features, + "--enable-anyref requires --enable-reference-types"); + } + if (module.features.hasExceptionHandling()) { // implies exnref + info.shouldBeTrue( + module.features.hasReferenceTypes(), + module.features, + "--enable-exception-handling requires --enable-reference-types"); + } +} + // TODO: If we want the validator to be part of libwasm rather than libpasses, // then Using PassRunner::getPassDebug causes a circular dependence. We should // fix that, perhaps by moving some of the pass infrastructure into libsupport. @@ -2495,6 +2511,7 @@ bool WasmValidator::validate(Module& module, Flags flags) { validateTable(module, info); validateEvents(module, info); validateModule(module, info); + validateFeatures(module, info); } // validate additional internal IR details when in pass-debug mode if (PassRunner::getPassDebug()) { diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index fe7c1b229..31e05f42e 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -45,6 +45,7 @@ const char* SIMD128Feature = "simd128"; const char* TailCallFeature = "tail-call"; const char* ReferenceTypesFeature = "reference-types"; const char* MultivalueFeature = "multivalue"; +const char* AnyrefFeature = "anyref"; } // namespace UserSections } // namespace BinaryConsts |