diff options
41 files changed, 279 insertions, 48 deletions
diff --git a/build-js.sh b/build-js.sh index 35ec946e3..861aceefd 100755 --- a/build-js.sh +++ b/build-js.sh @@ -186,6 +186,7 @@ export_function "_BinaryenTypeInt64" export_function "_BinaryenTypeFloat32" export_function "_BinaryenTypeFloat64" export_function "_BinaryenTypeVec128" +export_function "_BinaryenTypeAnyref" export_function "_BinaryenTypeExnref" export_function "_BinaryenTypeUnreachable" export_function "_BinaryenTypeAuto" diff --git a/scripts/test/shared.py b/scripts/test/shared.py index 2440077a8..ad2f44c14 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -313,14 +313,14 @@ class Py2CalledProcessError(subprocess.CalledProcessError): self.stderr = stderr -def run_process(cmd, check=True, input=None, capture_output=False, *args, **kw): +def run_process(cmd, check=True, input=None, capture_output=False, decode_output=True, *args, **kw): if input and type(input) == str: input = bytes(input, 'utf-8') if capture_output: kw['stdout'] = subprocess.PIPE kw['stderr'] = subprocess.PIPE ret = subprocess.run(cmd, check=check, input=input, *args, **kw) - if ret.stdout is not None: + if decode_output and ret.stdout is not None: ret.stdout = ret.stdout.decode('utf-8') if ret.stderr is not None: ret.stderr = ret.stderr.decode('utf-8') diff --git a/src/asmjs/asm_v_wasm.cpp b/src/asmjs/asm_v_wasm.cpp index 32653fdba..143d6667e 100644 --- a/src/asmjs/asm_v_wasm.cpp +++ b/src/asmjs/asm_v_wasm.cpp @@ -53,8 +53,10 @@ AsmType wasmToAsmType(Type type) { return ASM_INT64; case v128: assert(false && "v128 not implemented yet"); + case anyref: + assert(false && "anyref is not supported by asm2wasm"); case exnref: - assert(false && "exnref is not in asm2wasm"); + assert(false && "exnref is not supported by asm2wasm"); case none: return ASM_NONE; case unreachable: @@ -75,6 +77,8 @@ char getSig(Type type) { return 'd'; case v128: return 'V'; + case anyref: + return 'a'; case exnref: return 'e'; case none: @@ -105,6 +109,8 @@ Type sigToType(char sig) { return f64; case 'V': return v128; + case 'a': + return anyref; case 'e': return exnref; case 'v': diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 5d7566e4a..41fb245d4 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -70,6 +70,7 @@ BinaryenLiteral toBinaryenLiteral(Literal x) { break; } + case Type::anyref: // there's no anyref literals case Type::exnref: // there's no exnref literals case Type::none: case Type::unreachable: @@ -90,6 +91,7 @@ Literal fromBinaryenLiteral(BinaryenLiteral x) { return Literal(x.i64).castToF64(); case Type::v128: return Literal(x.v128); + case Type::anyref: // there's no anyref literals case Type::exnref: // there's no exnref literals case Type::none: case Type::unreachable: @@ -210,6 +212,7 @@ void printArg(std::ostream& setup, std::ostream& out, BinaryenLiteral arg) { out << "BinaryenLiteralVec128(" << array << ")"; break; } + case Type::anyref: // there's no anyref literals case Type::exnref: // there's no exnref literals case Type::none: case Type::unreachable: @@ -265,6 +268,7 @@ BinaryenType BinaryenTypeInt64(void) { return i64; } BinaryenType BinaryenTypeFloat32(void) { return f32; } BinaryenType BinaryenTypeFloat64(void) { return f64; } BinaryenType BinaryenTypeVec128(void) { return v128; } +BinaryenType BinaryenTypeAnyref(void) { return anyref; } BinaryenType BinaryenTypeExnref(void) { return exnref; } BinaryenType BinaryenTypeUnreachable(void) { return unreachable; } BinaryenType BinaryenTypeAuto(void) { return uint32_t(-1); } diff --git a/src/binaryen-c.h b/src/binaryen-c.h index 37e8c3204..b7c99ed1a 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -74,6 +74,7 @@ BinaryenType BinaryenTypeInt64(void); BinaryenType BinaryenTypeFloat32(void); BinaryenType BinaryenTypeFloat64(void); BinaryenType BinaryenTypeVec128(void); +BinaryenType BinaryenTypeAnyref(void); BinaryenType BinaryenTypeExnref(void); BinaryenType BinaryenTypeUnreachable(void); // Not a real type. Used as the last parameter to BinaryenBlock to let diff --git a/src/ir/abstract.h b/src/ir/abstract.h index e1c3b979a..2653218b0 100644 --- a/src/ir/abstract.h +++ b/src/ir/abstract.h @@ -81,6 +81,7 @@ inline UnaryOp getUnary(Type type, Op op) { assert(false && "v128 not implemented yet"); WASM_UNREACHABLE(); } + case anyref: // there's no unary instructions for anyref case exnref: // there's no unary instructions for exnref case none: case unreachable: { @@ -212,6 +213,7 @@ inline BinaryOp getBinary(Type type, Op op) { assert(false && "v128 not implemented yet"); WASM_UNREACHABLE(); } + case anyref: // there's no binary instructions for anyref case exnref: // there's no binary instructions for exnref case none: case unreachable: { diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index a09ad76ab..635a10577 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -37,6 +37,7 @@ Module['i64'] = Module['_BinaryenTypeInt64'](); Module['f32'] = Module['_BinaryenTypeFloat32'](); Module['f64'] = Module['_BinaryenTypeFloat64'](); Module['v128'] = Module['_BinaryenTypeVec128'](); +Module['anyref'] = Module['_BinaryenTypeAnyref'](); Module['exnref'] = Module['_BinaryenTypeExnref'](); Module['unreachable'] = Module['_BinaryenTypeUnreachable'](); Module['auto'] = /* deprecated */ Module['undefined'] = Module['_BinaryenTypeAuto'](); diff --git a/src/literal.h b/src/literal.h index 4b9dfae7c..9865b8707 100644 --- a/src/literal.h +++ b/src/literal.h @@ -80,6 +80,7 @@ public: Literal(int32_t(0)), Literal(int32_t(0)), Literal(int32_t(0))}}); + case Type::anyref: // there's no anyref literals case Type::exnref: // there's no exnref literals case none: case unreachable: @@ -430,6 +431,7 @@ template<> struct less<wasm::Literal> { return a.reinterpreti64() < b.reinterpreti64(); case wasm::Type::v128: return memcmp(a.getv128Ptr(), b.getv128Ptr(), 16) < 0; + case wasm::Type::anyref: // anyref is an opaque value case wasm::Type::exnref: // exnref is an opaque value case wasm::Type::none: case wasm::Type::unreachable: diff --git a/src/parsing.h b/src/parsing.h index 0ee4e67ac..49051800f 100644 --- a/src/parsing.h +++ b/src/parsing.h @@ -263,6 +263,7 @@ parseConst(cashew::IString s, Type type, MixedArena& allocator) { break; } case v128: + case anyref: // there's no anyref.const case exnref: // there's no exnref.const WASM_UNREACHABLE(); case none: diff --git a/src/passes/ConstHoisting.cpp b/src/passes/ConstHoisting.cpp index 17761e765..08fede1df 100644 --- a/src/passes/ConstHoisting.cpp +++ b/src/passes/ConstHoisting.cpp @@ -91,12 +91,9 @@ private: size = getTypeSize(value.type); break; } - case v128: { - // v128 not implemented yet - return false; - } - case exnref: { - // exnref cannot have literals + case v128: // v128 not implemented yet + case anyref: // anyref cannot have literals + case exnref: { // exnref cannot have literals return false; } case none: diff --git a/src/passes/FuncCastEmulation.cpp b/src/passes/FuncCastEmulation.cpp index 9d6923703..f938da3b7 100644 --- a/src/passes/FuncCastEmulation.cpp +++ b/src/passes/FuncCastEmulation.cpp @@ -66,6 +66,10 @@ static Expression* toABI(Expression* value, Module* module) { assert(false && "v128 not implemented yet"); WASM_UNREACHABLE(); } + case anyref: { + assert(false && "anyref cannot be converted to i64"); + WASM_UNREACHABLE(); + } case exnref: { assert(false && "exnref cannot be converted to i64"); WASM_UNREACHABLE(); @@ -108,6 +112,10 @@ static Expression* fromABI(Expression* value, Type type, Module* module) { assert(false && "v128 not implemented yet"); WASM_UNREACHABLE(); } + case anyref: { + assert(false && "anyref cannot be converted from i64"); + WASM_UNREACHABLE(); + } case exnref: { assert(false && "exnref cannot be converted from i64"); WASM_UNREACHABLE(); diff --git a/src/passes/InstrumentLocals.cpp b/src/passes/InstrumentLocals.cpp index a6a361fd2..ae1c30836 100644 --- a/src/passes/InstrumentLocals.cpp +++ b/src/passes/InstrumentLocals.cpp @@ -81,8 +81,10 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> { break; case v128: assert(false && "v128 not implemented yet"); + case anyref: + assert(false && "anyref not implemented yet"); case exnref: - assert(false && "not implemented yet"); + assert(false && "exnref not implemented yet"); case none: WASM_UNREACHABLE(); case unreachable: @@ -113,6 +115,8 @@ struct InstrumentLocals : public WalkerPass<PostWalker<InstrumentLocals>> { break; case v128: assert(false && "v128 not implemented yet"); + case anyref: + assert(false && "anyref not implemented yet"); case exnref: assert(false && "exnref not implemented yet"); case unreachable: diff --git a/src/shell-interface.h b/src/shell-interface.h index 2d9f88846..72c7dc67b 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -114,6 +114,8 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { break; case v128: assert(false && "v128 not implemented yet"); + case anyref: + assert(false && "anyref not implemented yet"); case exnref: assert(false && "exnref not implemented yet"); case none: diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 68c4d992a..baf42336d 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -851,6 +851,7 @@ private: case f32: case f64: case v128: + case anyref: case exnref: ret = _makeConcrete(type); break; @@ -1370,6 +1371,7 @@ private: return builder.makeLoad( 16, false, offset, pick(1, 2, 4, 8, 16), ptr, type); } + case anyref: // anyref cannot be loaded from memory case exnref: // exnref cannot be loaded from memory case none: case unreachable: @@ -1471,6 +1473,7 @@ private: return builder.makeStore( 16, offset, pick(1, 2, 4, 8, 16), ptr, value, type); } + case anyref: // anyref cannot be stored in memory case exnref: // exnref cannot be stored in memory case none: case unreachable: @@ -1481,7 +1484,7 @@ private: Expression* makeStore(Type type) { // exnref type cannot be stored in memory - if (!allowMemory || type == exnref) { + if (!allowMemory || isReferenceType(type)) { return makeTrivial(type); } auto* ret = makeNonAtomicStore(type); @@ -1566,6 +1569,7 @@ private: case f64: return Literal(getDouble()); case v128: + case anyref: // anyref cannot have literals case exnref: // exnref cannot have literals case none: case unreachable: @@ -1608,6 +1612,7 @@ private: case f64: return Literal(double(small)); case v128: + case anyref: // anyref cannot have literals case exnref: // exnref cannot have literals case none: case unreachable: @@ -1673,6 +1678,7 @@ private: std::numeric_limits<uint64_t>::max())); break; case v128: + case anyref: // anyref cannot have literals case exnref: // exnref cannot have literals case none: case unreachable: @@ -1704,6 +1710,7 @@ private: value = Literal(double(int64_t(1) << upTo(64))); break; case v128: + case anyref: // anyref cannot have literals case exnref: // exnref cannot have literals case none: case unreachable: @@ -1728,12 +1735,21 @@ private: } Expression* makeConst(Type type) { - if (type == exnref) { - // There's no exnref.const. - // TODO We should return a nullref once we implement instructions for - // reference types proposal. - assert(false && "exnref const is not implemented yet"); + switch (type) { + case anyref: + // There's no anyref.const. + // TODO We should return a nullref once we implement instructions for + // reference types proposal. + assert(false && "anyref const is not implemented yet"); + case exnref: + // There's no exnref.const. + // TODO We should return a nullref once we implement instructions for + // reference types proposal. + assert(false && "exnref const is not implemented yet"); + default: + break; } + auto* ret = wasm.allocator.alloc<Const>(); ret->value = makeLiteral(type); ret->type = type; @@ -1802,6 +1818,7 @@ private: AllTrueVecI64x2), make(v128)}); } + case anyref: // there's no unary ops for anyref case exnref: // there's no unary ops for exnref case none: case unreachable: @@ -1933,6 +1950,7 @@ private: } WASM_UNREACHABLE(); } + case anyref: // there's no unary ops for anyref case exnref: // there's no unary ops for exnref case none: case unreachable: @@ -1955,7 +1973,7 @@ private: return makeTrivial(type); } // There's no binary ops for exnref - if (type == exnref) { + if (isReferenceType(type)) { makeTrivial(type); } @@ -2146,6 +2164,7 @@ private: make(v128), make(v128)}); } + case anyref: // there's no binary ops for anyref case exnref: // there's no binary ops for exnref case none: case unreachable: @@ -2340,6 +2359,7 @@ private: op = ExtractLaneVecF64x2; break; case v128: + case anyref: case exnref: case none: case unreachable: diff --git a/src/tools/spec-wrapper.h b/src/tools/spec-wrapper.h index fcd2e6335..8dcb5fde4 100644 --- a/src/tools/spec-wrapper.h +++ b/src/tools/spec-wrapper.h @@ -48,6 +48,7 @@ static std::string generateSpecWrapper(Module& wasm) { case v128: ret += "(v128.const i32x4 0 0 0 0)"; break; + case anyref: // there's no anyref.const case exnref: // there's no exnref.const case none: case unreachable: diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h index 7c1151c7f..0de42ad13 100644 --- a/src/tools/tool-options.h +++ b/src/tools/tool-options.h @@ -71,6 +71,7 @@ struct ToolOptions : public Options { .addFeature(FeatureSet::ExceptionHandling, "exception handling operations") .addFeature(FeatureSet::TailCall, "tail call operations") + .addFeature(FeatureSet::ReferenceTypes, "reference types") .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 f1f5a5b90..54c662211 100644 --- a/src/tools/wasm-reduce.cpp +++ b/src/tools/wasm-reduce.cpp @@ -592,6 +592,7 @@ struct Reducer fixed = builder->makeUnary(TruncSFloat64ToInt32, child); break; case v128: + case anyref: case exnref: continue; // not implemented yet case none: @@ -614,6 +615,7 @@ struct Reducer fixed = builder->makeUnary(TruncSFloat64ToInt64, child); break; case v128: + case anyref: case exnref: continue; // not implemented yet case none: @@ -636,6 +638,7 @@ struct Reducer fixed = builder->makeUnary(DemoteFloat64, child); break; case v128: + case anyref: case exnref: continue; // not implemented yet case none: @@ -658,6 +661,7 @@ struct Reducer case f64: WASM_UNREACHABLE(); case v128: + case anyref: case exnref: continue; // not implemented yet case none: @@ -667,6 +671,7 @@ struct Reducer break; } case v128: + case anyref: case exnref: continue; // not implemented yet case none: diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 1efa24b48..d01502e9b 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -381,7 +381,9 @@ enum EncodedType { v128 = -0x5, // 0x7b // elem_type AnyFunc = -0x10, // 0x70 - // reference type + // opaque reference type + anyref = -0x11, // 0x6f + // exception reference type exnref = -0x18, // 0x68 // func_type form Func = -0x20, // 0x60 @@ -406,6 +408,7 @@ extern const char* SignExtFeature; extern const char* SIMD128Feature; extern const char* ExceptionHandlingFeature; extern const char* TailCallFeature; +extern const char* ReferenceTypesFeature; enum Subsection { NameFunction = 1, @@ -903,6 +906,9 @@ inline S32LEB binaryType(Type type) { case v128: ret = BinaryConsts::EncodedType::v128; break; + case anyref: + ret = BinaryConsts::EncodedType::anyref; + break; case exnref: ret = BinaryConsts::EncodedType::exnref; break; diff --git a/src/wasm-builder.h b/src/wasm-builder.h index a0a43bc07..4258b9336 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -723,6 +723,9 @@ public: value = Literal(bytes.data()); break; } + case anyref: + // TODO Implement and return nullref + assert(false && "anyref not implemented yet"); case exnref: // TODO Implement and return nullref assert(false && "exnref not implemented yet"); diff --git a/src/wasm-features.h b/src/wasm-features.h index d1789a67a..a645c93a8 100644 --- a/src/wasm-features.h +++ b/src/wasm-features.h @@ -33,7 +33,8 @@ struct FeatureSet { SignExt = 1 << 5, ExceptionHandling = 1 << 6, TailCall = 1 << 7, - All = (1 << 8) - 1 + ReferenceTypes = 1 << 8, + All = (1 << 9) - 1 }; static std::string toString(Feature f) { @@ -54,6 +55,8 @@ struct FeatureSet { return "exception-handling"; case TailCall: return "tail-call"; + case ReferenceTypes: + return "reference-types"; default: WASM_UNREACHABLE(); } @@ -72,6 +75,7 @@ struct FeatureSet { bool hasSignExt() const { return features & SignExt; } bool hasExceptionHandling() const { return features & ExceptionHandling; } bool hasTailCall() const { return features & TailCall; } + bool hasReferenceTypes() const { return features & ReferenceTypes; } bool hasAll() const { return features & All; } void makeMVP() { features = MVP; } @@ -86,6 +90,7 @@ struct FeatureSet { void setSignExt(bool v = true) { set(SignExt, v); } void setExceptionHandling(bool v = true) { set(ExceptionHandling, v); } void setTailCall(bool v = true) { set(TailCall, v); } + void setReferenceTypes(bool v = true) { set(ReferenceTypes, v); } void setAll(bool v = true) { features = v ? All : MVP; } void enable(const FeatureSet& other) { features |= other.features; } @@ -118,6 +123,9 @@ struct FeatureSet { if (hasTailCall()) { f(TailCall); } + if (hasReferenceTypes()) { + f(ReferenceTypes); + } } bool operator<=(const FeatureSet& other) const { diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 53345f0ab..05d00ed10 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1142,6 +1142,7 @@ public: return Literal(load64u(addr)).castToF64(); case v128: return Literal(load128(addr).data()); + case anyref: // anyref cannot be loaded from memory case exnref: // exnref cannot be loaded from memory case none: case unreachable: @@ -1196,6 +1197,7 @@ public: case v128: store128(addr, value.getv128()); break; + case anyref: // anyref cannot be stored from memory case exnref: // exnref cannot be stored in memory case none: case unreachable: diff --git a/src/wasm-type.h b/src/wasm-type.h index 61179ec1a..42426c2c1 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -28,6 +28,7 @@ enum Type { f32, f64, v128, + anyref, exnref, // none means no type, e.g. a block can have no return type. but unreachable // is different, as it can be "ignored" when doing type checking across diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 68268d366..43adec6f6 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -137,6 +137,7 @@ void Literal::getBits(uint8_t (&buf)[16]) const { case Type::v128: memcpy(buf, &v128, sizeof(v128)); break; + case Type::anyref: // anyref type is opaque case Type::exnref: // exnref type is opaque case Type::none: case Type::unreachable: @@ -272,6 +273,7 @@ std::ostream& operator<<(std::ostream& o, Literal literal) { o << "i32x4 "; literal.printVec128(o, literal.getv128()); break; + case Type::anyref: // anyref type is opaque case Type::exnref: // exnref type is opaque case Type::unreachable: WASM_UNREACHABLE(); @@ -475,6 +477,7 @@ Literal Literal::eqz() const { case Type::f64: return eq(Literal(double(0))); case Type::v128: + case Type::anyref: case Type::exnref: case Type::none: case Type::unreachable: @@ -494,6 +497,7 @@ Literal Literal::neg() const { case Type::f64: return Literal(int64_t(i64 ^ 0x8000000000000000ULL)).castToF64(); case Type::v128: + case Type::anyref: case Type::exnref: case Type::none: case Type::unreachable: @@ -513,6 +517,7 @@ Literal Literal::abs() const { case Type::f64: return Literal(int64_t(i64 & 0x7fffffffffffffffULL)).castToF64(); case Type::v128: + case Type::anyref: case Type::exnref: case Type::none: case Type::unreachable: @@ -615,6 +620,7 @@ Literal Literal::add(const Literal& other) const { case Type::f64: return Literal(getf64() + other.getf64()); case Type::v128: + case Type::anyref: case Type::exnref: case Type::none: case Type::unreachable: @@ -634,6 +640,7 @@ Literal Literal::sub(const Literal& other) const { case Type::f64: return Literal(getf64() - other.getf64()); case Type::v128: + case Type::anyref: case Type::exnref: case Type::none: case Type::unreachable: @@ -724,6 +731,7 @@ Literal Literal::mul(const Literal& other) const { case Type::f64: return Literal(getf64() * other.getf64()); case Type::v128: + case Type::anyref: case Type::exnref: case Type::none: case Type::unreachable: @@ -942,6 +950,7 @@ Literal Literal::eq(const Literal& other) const { case Type::f64: return Literal(getf64() == other.getf64()); case Type::v128: + case Type::anyref: case Type::exnref: case Type::none: case Type::unreachable: @@ -961,6 +970,7 @@ Literal Literal::ne(const Literal& other) const { case Type::f64: return Literal(getf64() != other.getf64()); case Type::v128: + case Type::anyref: case Type::exnref: case Type::none: case Type::unreachable: diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 7047b674e..d75973ab0 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -681,6 +681,8 @@ void WasmBinaryWriter::writeFeaturesSection() { return BinaryConsts::UserSections::ExceptionHandlingFeature; case FeatureSet::TailCall: return BinaryConsts::UserSections::TailCallFeature; + case FeatureSet::ReferenceTypes: + return BinaryConsts::UserSections::ReferenceTypesFeature; default: WASM_UNREACHABLE(); } @@ -1085,6 +1087,8 @@ Type WasmBinaryBuilder::getType() { return f64; case BinaryConsts::EncodedType::v128: return v128; + case BinaryConsts::EncodedType::anyref: + return anyref; case BinaryConsts::EncodedType::exnref: return exnref; default: { throwError("invalid wasm type: " + std::to_string(type)); } @@ -2167,6 +2171,8 @@ void WasmBinaryBuilder::readFeatures(size_t payloadLen) { wasm.features.setSIMD(); } else if (name == BinaryConsts::UserSections::TailCallFeature) { wasm.features.setTailCall(); + } else if (name == BinaryConsts::UserSections::ReferenceTypesFeature) { + wasm.features.setReferenceTypes(); } } } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index e1413d5fd..39f6b0a9f 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -893,6 +893,9 @@ Type SExpressionWasmBuilder::stringToType(const char* str, return v128; } } + if (strncmp(str, "anyref", 6) == 0 && (prefix || str[6] == 0)) { + return anyref; + } if (strncmp(str, "exnref", 6) == 0 && (prefix || str[6] == 0)) { return exnref; } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index d3aba3b8c..cb60c50f9 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -147,6 +147,7 @@ void BinaryInstWriter::visitLoad(Load* curr) { // the pointer is unreachable, so we are never reached; just don't emit // a load return; + case anyref: // anyref cannot be loaded from memory case exnref: // exnref cannot be loaded from memory case none: WASM_UNREACHABLE(); @@ -246,6 +247,7 @@ void BinaryInstWriter::visitStore(Store* curr) { o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::V128Store); break; + case anyref: // anyref cannot be stored from memory case exnref: // exnref cannot be stored in memory case none: case unreachable: @@ -580,6 +582,7 @@ void BinaryInstWriter::visitConst(Const* curr) { } break; } + case anyref: // there's no anyref.const case exnref: // there's no exnref.const case none: case unreachable: @@ -1493,6 +1496,11 @@ void BinaryInstWriter::mapLocalsAndEmitHeader() { continue; } index += numLocalsByType[v128]; + if (type == anyref) { + mappedLocals[i] = index + currLocalsByType[anyref] - 1; + continue; + } + index += numLocalsByType[anyref]; if (type == exnref) { mappedLocals[i] = index + currLocalsByType[exnref] - 1; continue; @@ -1503,6 +1511,7 @@ void BinaryInstWriter::mapLocalsAndEmitHeader() { o << U32LEB((numLocalsByType[i32] ? 1 : 0) + (numLocalsByType[i64] ? 1 : 0) + (numLocalsByType[f32] ? 1 : 0) + (numLocalsByType[f64] ? 1 : 0) + (numLocalsByType[v128] ? 1 : 0) + + (numLocalsByType[anyref] ? 1 : 0) + (numLocalsByType[exnref] ? 1 : 0)); if (numLocalsByType[i32]) { o << U32LEB(numLocalsByType[i32]) << binaryType(i32); @@ -1519,6 +1528,9 @@ void BinaryInstWriter::mapLocalsAndEmitHeader() { if (numLocalsByType[v128]) { o << U32LEB(numLocalsByType[v128]) << binaryType(v128); } + if (numLocalsByType[anyref]) { + o << U32LEB(numLocalsByType[anyref]) << binaryType(anyref); + } if (numLocalsByType[exnref]) { o << U32LEB(numLocalsByType[exnref]) << binaryType(exnref); } diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 2a836ab42..39383a478 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -36,6 +36,8 @@ const char* printType(Type type) { return "f64"; case Type::v128: return "v128"; + case Type::anyref: + return "anyref"; case Type::exnref: return "exnref"; case Type::unreachable: @@ -56,6 +58,7 @@ unsigned getTypeSize(Type type) { return 8; case Type::v128: return 16; + case Type::anyref: // anyref type is opaque case Type::exnref: // exnref type is opaque case Type::none: case Type::unreachable: @@ -65,13 +68,16 @@ unsigned getTypeSize(Type type) { } FeatureSet getFeatures(Type type) { - if (type == v128) { - return FeatureSet::SIMD; - } - if (type == exnref) { - return FeatureSet::ExceptionHandling; + switch (type) { + case v128: + return FeatureSet::SIMD; + case anyref: + return FeatureSet::ReferenceTypes; + case exnref: + return FeatureSet::ExceptionHandling; + default: + return FeatureSet(); } - return FeatureSet(); } Type getType(unsigned size, bool float_) { @@ -117,8 +123,13 @@ bool isFloatType(Type type) { bool isVectorType(Type type) { return type == v128; } bool isReferenceType(Type type) { - // TODO Add other reference types later - return type == exnref; + switch (type) { + case anyref: + case exnref: + return true; + default: + return false; + } } Type reinterpretType(Type type) { @@ -132,6 +143,7 @@ Type reinterpretType(Type type) { case Type::f64: return i64; case Type::v128: + case Type::anyref: case Type::exnref: case Type::none: case Type::unreachable: diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 8eb3341de..339ad6f68 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -1134,6 +1134,7 @@ void FunctionValidator::validateMemBytes(uint8_t bytes, shouldBeEqual( bytes, uint8_t(16), curr, "expected v128 operation to touch 16 bytes"); break; + case anyref: // anyref cannot be stored in memory case exnref: // exnref cannot be stored in memory case none: WASM_UNREACHABLE(); @@ -1788,6 +1789,7 @@ void FunctionValidator::validateAlignment( case v128: case unreachable: break; + case anyref: // anyref cannot be stored in memory case exnref: // exnref cannot be stored in memory case none: WASM_UNREACHABLE(); diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 97b60bfb5..f8791286c 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -41,6 +41,7 @@ const char* TruncSatFeature = "nontrapping-fptoint"; const char* SignExtFeature = "sign-ext"; const char* SIMD128Feature = "simd128"; const char* TailCallFeature = "tail-call"; +const char* ReferenceTypesFeature = "reference-types"; } // namespace UserSections } // namespace BinaryConsts diff --git a/test/anyref.wast b/test/anyref.wast new file mode 100644 index 000000000..d617d3f42 --- /dev/null +++ b/test/anyref.wast @@ -0,0 +1,18 @@ +(module + (memory 1 1) + (import "env" "test1" (func $test1 (param anyref) (result anyref))) + (import "env" "test2" (global $test2 anyref)) + (export "test1" (func $test1 (param anyref) (result anyref))) + (export "test2" (global $test2)) + (func $anyref_test (param $0 anyref) (result anyref) + (local $1 anyref) + (local.set $1 + (call $test1 + (local.get $0) + ) + ) + (return + (local.get $1) + ) + ) +) diff --git a/test/anyref.wast.from-wast b/test/anyref.wast.from-wast new file mode 100644 index 000000000..117695077 --- /dev/null +++ b/test/anyref.wast.from-wast @@ -0,0 +1,19 @@ +(module + (type $FUNCSIG$aa (func (param anyref) (result anyref))) + (import "env" "test2" (global $test2 anyref)) + (import "env" "test1" (func $test1 (param anyref) (result anyref))) + (memory $0 1 1) + (export "test1" (func $test1)) + (export "test2" (global $test2)) + (func $anyref_test (; 1 ;) (type $FUNCSIG$aa) (param $0 anyref) (result anyref) + (local $1 anyref) + (local.set $1 + (call $test1 + (local.get $0) + ) + ) + (return + (local.get $1) + ) + ) +) diff --git a/test/anyref.wast.fromBinary b/test/anyref.wast.fromBinary new file mode 100644 index 000000000..3d9b223b6 --- /dev/null +++ b/test/anyref.wast.fromBinary @@ -0,0 +1,20 @@ +(module + (type $0 (func (param anyref) (result anyref))) + (import "env" "test2" (global $gimport$1 anyref)) + (import "env" "test1" (func $test1 (param anyref) (result anyref))) + (memory $0 1 1) + (export "test1" (func $test1)) + (export "test2" (global $gimport$1)) + (func $anyref_test (; 1 ;) (type $0) (param $0 anyref) (result anyref) + (local $1 anyref) + (local.set $1 + (call $test1 + (local.get $0) + ) + ) + (return + (local.get $1) + ) + ) +) + diff --git a/test/anyref.wast.fromBinary.noDebugInfo b/test/anyref.wast.fromBinary.noDebugInfo new file mode 100644 index 000000000..d397cd3f9 --- /dev/null +++ b/test/anyref.wast.fromBinary.noDebugInfo @@ -0,0 +1,20 @@ +(module + (type $0 (func (param anyref) (result anyref))) + (import "env" "test2" (global $gimport$1 anyref)) + (import "env" "test1" (func $fimport$0 (param anyref) (result anyref))) + (memory $0 1 1) + (export "test1" (func $fimport$0)) + (export "test2" (global $gimport$1)) + (func $0 (; 1 ;) (type $0) (param $0 anyref) (result anyref) + (local $1 anyref) + (local.set $1 + (call $fimport$0 + (local.get $0) + ) + ) + (return + (local.get $1) + ) + ) +) + diff --git a/test/binaryen.js/exception-handling.js.txt b/test/binaryen.js/exception-handling.js.txt index 902ac55e6..cdf45aeaa 100644 --- a/test/binaryen.js/exception-handling.js.txt +++ b/test/binaryen.js/exception-handling.js.txt @@ -26,7 +26,7 @@ ) ) -getExpressionInfo(throw) = {"id":39,"type":7,"event":"e"} -getExpressionInfo(br_on_exn) = {"id":41,"type":6,"name":"l","event":"e"} -getExpressionInfo(rethrow) = {"id":40,"type":7} +getExpressionInfo(throw) = {"id":39,"type":8,"event":"e"} +getExpressionInfo(br_on_exn) = {"id":41,"type":7,"name":"l","event":"e"} +getExpressionInfo(rethrow) = {"id":40,"type":8} getExpressionInfo(try) = {"id":38,"type":0} diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js index 163fe8839..f2a78ab34 100644 --- a/test/binaryen.js/kitchen-sink.js +++ b/test/binaryen.js/kitchen-sink.js @@ -57,6 +57,7 @@ function test_types() { console.log("BinaryenTypeFloat32: " + Binaryen.f32); console.log("BinaryenTypeFloat64: " + Binaryen.f64); console.log("BinaryenTypeVec128: " + Binaryen.v128); + console.log("BinaryenTypeAnyref: " + Binaryen.anyref); console.log("BinaryenTypeExnref: " + Binaryen.exnref); console.log("BinaryenTypeUnreachable: " + Binaryen.unreachable); console.log("BinaryenTypeAuto: " + Binaryen.auto); diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt index a1baa5951..07a06b98b 100644 --- a/test/binaryen.js/kitchen-sink.js.txt +++ b/test/binaryen.js/kitchen-sink.js.txt @@ -4,8 +4,9 @@ BinaryenTypeInt64: 2 BinaryenTypeFloat32: 3 BinaryenTypeFloat64: 4 BinaryenTypeVec128: 5 -BinaryenTypeExnref: 6 -BinaryenTypeUnreachable: 7 +BinaryenTypeAnyref: 6 +BinaryenTypeExnref: 7 +BinaryenTypeUnreachable: 8 BinaryenTypeAuto: -1 Binaryen.Features.MVP: 0 Binaryen.Features.Atomics: 1 @@ -15,7 +16,7 @@ Binaryen.Features.NontrappingFPToInt: 4 Binaryen.Features.SignExt: 32 Binaryen.Features.SIMD128: 8 Binaryen.Features.ExceptionHandling: 64 -Binaryen.Features.All: 255 +Binaryen.Features.All: 511 BinaryenInvalidId: 0 BinaryenBlockId: 1 BinaryenIfId: 2 @@ -4759,9 +4760,9 @@ int main() { BinaryenExpressionRef operands[] = { expressions[656] }; expressions[657] = BinaryenThrow(the_module, "a-event", operands, 1); } - expressions[658] = BinaryenPop(the_module, 6); + expressions[658] = BinaryenPop(the_module, 7); expressions[659] = BinaryenLocalSet(the_module, 5, expressions[658]); - expressions[660] = BinaryenLocalGet(the_module, 5, 6); + expressions[660] = BinaryenLocalGet(the_module, 5, 7); expressions[661] = BinaryenBrOnExn(the_module, "try-block", "a-event", expressions[660]); expressions[662] = BinaryenRethrow(the_module, expressions[661]); { @@ -4784,7 +4785,7 @@ int main() { expressions[674] = BinaryenPush(the_module, expressions[673]); expressions[675] = BinaryenPop(the_module, 5); expressions[676] = BinaryenPush(the_module, expressions[675]); - expressions[677] = BinaryenPop(the_module, 6); + expressions[677] = BinaryenPop(the_module, 7); expressions[678] = BinaryenPush(the_module, expressions[677]); expressions[679] = BinaryenNop(the_module); expressions[680] = BinaryenUnreachable(the_module); @@ -4876,7 +4877,7 @@ getExpressionInfo(f64.const)={"id":14,"type":4,"value":9.5} expressions[689] = BinaryenBlock(the_module, "the-body", children, 2, 0); } { - BinaryenType varTypes[] = { 1, 6 }; + BinaryenType varTypes[] = { 1, 7 }; functions[0] = BinaryenAddFunction(the_module, "kitchen()sinker", functionTypes[1], varTypes, 2, expressions[689]); } expressions[690] = BinaryenConst(the_module, BinaryenLiteralInt32(1)); @@ -4934,7 +4935,7 @@ getExpressionInfo(f64.const)={"id":14,"type":4,"value":9.5} functionTypes[4] = BinaryenAddFunctionType(the_module, NULL, 0, paramTypes, 0); } BinaryenModuleAutoDrop(the_module); - BinaryenModuleSetFeatures(the_module, 255); + BinaryenModuleSetFeatures(the_module, 511); BinaryenModuleGetFeatures(the_module); BinaryenModulePrint(the_module); (module diff --git a/test/binaryen.js/push-pop.js.txt b/test/binaryen.js/push-pop.js.txt index 0597780d9..c9689831f 100644 --- a/test/binaryen.js/push-pop.js.txt +++ b/test/binaryen.js/push-pop.js.txt @@ -27,5 +27,5 @@ getExpressionInfo(i64.pop) = {"id":37,"type":2} getExpressionInfo(f32.pop) = {"id":37,"type":3} getExpressionInfo(f64.pop) = {"id":37,"type":4} getExpressionInfo(v128.pop) = {"id":37,"type":5} -getExpressionInfo(exnref.pop) = {"id":37,"type":6} +getExpressionInfo(exnref.pop) = {"id":37,"type":7} getExpressionInfo(push) = {"id":36} diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c index 661d04ce2..3d9d42fa1 100644 --- a/test/example/c-api-kitchen-sink.c +++ b/test/example/c-api-kitchen-sink.c @@ -155,6 +155,7 @@ void test_types() { printf("BinaryenTypeFloat32: %d\n", BinaryenTypeFloat32()); printf("BinaryenTypeFloat64: %d\n", BinaryenTypeFloat64()); printf("BinaryenTypeVec128: %d\n", BinaryenTypeVec128()); + printf("BinaryenTypeAnyref: %d\n", BinaryenTypeAnyref()); printf("BinaryenTypeExnref: %d\n", BinaryenTypeExnref()); printf("BinaryenTypeUnreachable: %d\n", BinaryenTypeUnreachable()); printf("BinaryenTypeAuto: %d\n", BinaryenTypeAuto()); diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt index e135bd98d..d0582bd79 100644 --- a/test/example/c-api-kitchen-sink.txt +++ b/test/example/c-api-kitchen-sink.txt @@ -4,8 +4,9 @@ BinaryenTypeInt64: 2 BinaryenTypeFloat32: 3 BinaryenTypeFloat64: 4 BinaryenTypeVec128: 5 -BinaryenTypeExnref: 6 -BinaryenTypeUnreachable: 7 +BinaryenTypeAnyref: 6 +BinaryenTypeExnref: 7 +BinaryenTypeUnreachable: 8 BinaryenTypeAuto: -1 BinaryenFeatureMVP: 0 BinaryenFeatureAtomics: 1 @@ -15,7 +16,7 @@ BinaryenFeatureNontrappingFPToInt: 4 BinaryenFeatureSignExt: 32 BinaryenFeatureSIMD128: 8 BinaryenFeatureExceptionHandling: 64 -BinaryenFeatureAll: 255 +BinaryenFeatureAll: 511 (f32.neg (f32.const -33.61199951171875) ) @@ -2022,9 +2023,9 @@ int main() { BinaryenExpressionRef operands[] = { expressions[34] }; expressions[35] = BinaryenThrow(the_module, "a-event", operands, 1); } - expressions[36] = BinaryenPop(the_module, 6); + expressions[36] = BinaryenPop(the_module, 7); expressions[37] = BinaryenLocalSet(the_module, 5, expressions[36]); - expressions[38] = BinaryenLocalGet(the_module, 5, 6); + expressions[38] = BinaryenLocalGet(the_module, 5, 7); expressions[39] = BinaryenBrOnExn(the_module, "try-block", "a-event", expressions[38]); expressions[40] = BinaryenRethrow(the_module, expressions[39]); { @@ -3371,7 +3372,7 @@ int main() { expressions[666] = BinaryenBlock(the_module, "the-body", children, 2, BinaryenTypeAuto()); } { - BinaryenType varTypes[] = { 1, 6 }; + BinaryenType varTypes[] = { 1, 7 }; functions[0] = BinaryenAddFunction(the_module, "kitchen()sinker", functionTypes[0], varTypes, 2, expressions[666]); } expressions[667] = BinaryenConst(the_module, BinaryenLiteralInt32(7)); @@ -3414,7 +3415,7 @@ int main() { functionTypes[4] = BinaryenAddFunctionType(the_module, NULL, 0, paramTypes, 0); } BinaryenModuleAutoDrop(the_module); - BinaryenModuleSetFeatures(the_module, 255); + BinaryenModuleSetFeatures(the_module, 511); BinaryenModuleGetFeatures(the_module); BinaryenModuleValidate(the_module); BinaryenModulePrint(the_module); diff --git a/test/unit/input/reference_types_target_feature.wasm b/test/unit/input/reference_types_target_feature.wasm Binary files differnew file mode 100644 index 000000000..7ea8847e9 --- /dev/null +++ b/test/unit/input/reference_types_target_feature.wasm diff --git a/test/unit/test_features.py b/test/unit/test_features.py index 53037307d..c031c07fa 100644 --- a/test/unit/test_features.py +++ b/test/unit/test_features.py @@ -29,6 +29,9 @@ class FeatureValidationTest(BinaryenTestCase): def check_tail_call(self, module, error): self.check_feature(module, error, '--enable-tail-call') + def check_reference_types(self, module, error): + self.check_feature(module, error, '--enable-reference-types') + def test_v128_signature(self): module = ''' (module @@ -144,6 +147,24 @@ class FeatureValidationTest(BinaryenTestCase): ''' self.check_tail_call(module, 'return_call_indirect requires tail calls to be enabled') + def test_reference_types_anyref(self): + module = ''' + (module + (import "env" "test1" (func $test1 (param anyref) (result anyref))) + (import "env" "test2" (global $test2 anyref)) + (export "test1" (func $test1 (param anyref) (result anyref))) + (export "test2" (global $test2)) + (func $anyref_test (param $0 anyref) (result anyref) + (return + (call $test1 + (local.get $0) + ) + ) + ) + ) + ''' + self.check_reference_types(module, 'all used types should be allowed') + def test_exnref_local(self): module = ''' (module @@ -210,6 +231,12 @@ class TargetFeaturesSectionTest(BinaryenTestCase): self.check_features(filename, ['tail-call']) self.assertIn('return_call', self.disassemble(filename)) + def test_reference_types(self): + filename = 'reference_types_target_feature.wasm' + self.roundtrip(filename) + self.check_features(filename, ['reference-types']) + self.assertIn('anyref', self.disassemble(filename)) + def test_exception_handling(self): filename = 'exception_handling_target_feature.wasm' self.roundtrip(filename) @@ -243,7 +270,7 @@ class TargetFeaturesSectionTest(BinaryenTestCase): def test_emit_all_features(self): p = run_process(WASM_OPT + ['--emit-target-features', '-all', '-o', '-'], - input="(module)", check=False, capture_output=True) + input="(module)", check=False, capture_output=True, decode_output=False) self.assertEqual(p.returncode, 0) p2 = run_process(WASM_OPT + ['--print-features', '-o', os.devnull], input=p.stdout, check=False, capture_output=True) @@ -256,5 +283,6 @@ class TargetFeaturesSectionTest(BinaryenTestCase): '--enable-nontrapping-float-to-int', '--enable-sign-ext', '--enable-simd', - '--enable-tail-call' + '--enable-tail-call', + '--enable-reference-types' ], p2.stdout.split()) |