From 927bd6d068a47886531e45cc79565395af1da764 Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 1 Aug 2020 16:01:04 +0200 Subject: [PATCH 01/50] Refactor types to represent arbitrary complex types --- src/support/hash.h | 5 + src/wasm-type.h | 133 +++++++++++++++- src/wasm/wasm-type.cpp | 352 +++++++++++++++++++++++++++++------------ 3 files changed, 380 insertions(+), 110 deletions(-) diff --git a/src/support/hash.h b/src/support/hash.h index 647369ac817..aaa98d8937d 100644 --- a/src/support/hash.h +++ b/src/support/hash.h @@ -45,6 +45,11 @@ inline uint64_t rehash(uint64_t x, uint64_t y) { return rehash(ret, HashType(y >> 32)); } +template inline void hash_combine(std::size_t& s, const T& v) { + // see boost/container_hash/hash.hpp + s ^= std::hash{}(v) + 0x9e3779b9 + (s << 6) + (s >> 2); +} + } // namespace wasm #endif // wasm_support_hash_h diff --git a/src/wasm-type.h b/src/wasm-type.h index b0cfa40941a..38969b4f476 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -23,13 +23,18 @@ namespace wasm { +class Type; +typedef std::vector Tuple; +struct Signature; +struct Struct; +struct Array; + class Type { // The `id` uniquely represents each type, so type equality is just a // comparison of the ids. For basic types the `id` is just the `ValueType` // enum value below, and for constructed types the `id` is the address of the // canonical representation of the type, making lookups cheap for all types. uintptr_t id; - void init(const std::vector&); public: enum ValueType : uint32_t { @@ -56,24 +61,33 @@ class Type { explicit Type(uint64_t id) : id(id){}; // Construct from lists of elementary types - Type(std::initializer_list types); - explicit Type(const std::vector& types); + Type(std::initializer_list); + explicit Type(const Tuple&); + + // Construct from signature descriptions + explicit Type(const Signature&); + + // Construct from struct descriptions + explicit Type(const Struct&); + + // Construct from array descriptions + explicit Type(const Array&); // Accessors size_t size() const; - const std::vector& expand() const; + const Tuple& expand() const; // Predicates constexpr bool isSingle() const { return id >= i32 && id <= _last_value_type; } - constexpr bool isMulti() const { return id > _last_value_type; } constexpr bool isConcrete() const { return id >= i32; } constexpr bool isInteger() const { return id == i32 || id == i64; } constexpr bool isFloat() const { return id == f32 || id == f64; } constexpr bool isVector() const { return id == v128; }; constexpr bool isNumber() const { return id >= i32 && id <= v128; } - constexpr bool isRef() const { return id >= funcref && id <= exnref; } + bool isMulti() const; + bool isRef() const; private: template bool hasPredicate() { @@ -90,7 +104,7 @@ class Type { bool hasRef() { return hasPredicate<&Type::isRef>(); } constexpr uint64_t getID() const { return id; } - constexpr ValueType getSingle() const { + ValueType getSingle() const { assert(!isMulti() && "Unexpected multivalue type"); return static_cast(id); } @@ -166,10 +180,110 @@ struct Signature { bool operator<(const Signature& other) const; }; +struct Field { + Type type; + bool mutable_; + Field(Type type, bool mutable_ = false) : type(type), mutable_(mutable_) {} + bool operator==(const Field& other) const { + return type == other.type && mutable_ == other.mutable_; + } + bool operator!=(const Field& other) const { return !(*this == other); } +}; + +typedef std::vector FieldList; + +struct Struct { + FieldList fields; + bool nullable; + Struct(const Struct& other) + : fields(other.fields), nullable(other.nullable) {} + Struct(FieldList fields, bool nullable = false) + : fields(fields), nullable(nullable) {} + bool operator==(const Struct& other) const { + return fields == other.fields && nullable == other.nullable; + } + bool operator!=(const Struct& other) const { return !(*this == other); } +}; + +struct Array { + Field element; + bool nullable; + Array(const Array& other) + : element(other.element), nullable(other.nullable) {} + Array(Field element, bool nullable = false) + : element(element), nullable(nullable) {} + bool operator==(const Array& other) const { + return element == other.element && nullable == other.nullable; + } + bool operator!=(const Array& other) const { return !(*this == other); } +}; + +struct TypeDef { // TODO: make internal to wasm-type.cpp ? + enum Kind { TupleKind, SignatureKind, StructKind, ArrayKind }; + + Kind kind; + union Def { + Def(Tuple tuple) : tuple(tuple) {} + Def(Signature signature) : signature(signature) {} + Def(Struct struct_) : struct_(struct_) {} + Def(Array array) : array(array) {} + ~Def() {} + Tuple tuple; + Signature signature; + Struct struct_; + Array array; + } def; + + TypeDef(const TypeDef& other) : kind(other.kind), def(Tuple()) { // FIXME + switch (kind) { + case TupleKind: + def.tuple = other.def.tuple; + break; + case SignatureKind: { + def.signature = other.def.signature; + break; + } + case StructKind: { + def.struct_ = other.def.struct_; + break; + } + case ArrayKind: { + def.array = other.def.array; + break; + } + default: + WASM_UNREACHABLE("unexpected kind"); + } + } + TypeDef(Tuple tuple) : kind(TupleKind), def(tuple) {} + TypeDef(Signature signature) : kind(SignatureKind), def(signature) {} + TypeDef(Struct struct_) : kind(StructKind), def(struct_) {} + TypeDef(Array array) : kind(ArrayKind), def(array) {} + + bool operator==(const TypeDef& other) const { + if (kind != other.kind) + return false; + switch (kind) { + case TupleKind: + return def.tuple == other.def.tuple; + case SignatureKind: + return def.signature == other.def.signature; + case StructKind: + return def.struct_ == other.def.struct_; + case ArrayKind: + return def.array == other.def.array; + } + WASM_UNREACHABLE("unexpected kind"); + } + bool operator!=(const TypeDef& other) const { return !(*this == other); } +}; + std::ostream& operator<<(std::ostream& os, Type t); std::ostream& operator<<(std::ostream& os, ParamType t); std::ostream& operator<<(std::ostream& os, ResultType t); std::ostream& operator<<(std::ostream& os, Signature t); +std::ostream& operator<<(std::ostream& os, Struct t); +std::ostream& operator<<(std::ostream& os, Array t); } // namespace wasm @@ -185,6 +299,11 @@ template<> class hash { size_t operator()(const wasm::Signature& sig) const; }; +template<> class hash { +public: + size_t operator()(const wasm::TypeDef&) const; +}; + } // namespace std #endif // wasm_wasm_type_h diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index b49f0338f38..b1a20eb7206 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -30,9 +30,9 @@ namespace std { template<> class hash> { public: size_t operator()(const vector& types) const { - uint64_t res = wasm::rehash(0, uint32_t(types.size())); + auto res = hash{}(types.size()); for (auto t : types) { - res = wasm::rehash(res, t.getID()); + wasm::hash_combine(res, t.getID()); } return res; } @@ -43,8 +43,49 @@ size_t hash::operator()(const wasm::Type& type) const { } size_t hash::operator()(const wasm::Signature& sig) const { - return wasm::rehash(uint64_t(hash{}(sig.params.getID())), - uint64_t(hash{}(sig.results.getID()))); + auto res = hash{}(sig.params.getID()); + wasm::hash_combine(res, sig.results.getID()); + return res; +} + +size_t hash::operator()(const wasm::TypeDef& typeDef) const { + auto res = hash{}(uint32_t(typeDef.kind)); + switch (typeDef.kind) { + case wasm::TypeDef::TupleKind: { + auto& tuple = typeDef.def.tuple; + for (auto t : tuple) { + wasm::hash_combine(res, t.getID()); + } + break; + } + case wasm::TypeDef::SignatureKind: { + auto& sig = typeDef.def.signature; + wasm::hash_combine(res, sig.params.getID()); + wasm::hash_combine(res, sig.results.getID()); + break; + } + case wasm::TypeDef::StructKind: { + auto& struct_ = typeDef.def.struct_; + auto& fields = struct_.fields; + wasm::hash_combine(res, fields.size()); + for (auto f : fields) { + wasm::hash_combine(res, f.type.getID()); + wasm::hash_combine(res, f.mutable_); + } + wasm::hash_combine(res, struct_.nullable); + break; + } + case wasm::TypeDef::ArrayKind: { + auto& array = typeDef.def.array; + wasm::hash_combine(res, array.element.type.getID()); + wasm::hash_combine(res, array.element.mutable_); + wasm::hash_combine(res, array.nullable); + break; + } + default: + WASM_UNREACHABLE("unexpected type"); + } + return res; } } // namespace std @@ -55,86 +96,140 @@ namespace { std::mutex mutex; -std::array, Type::_last_value_type + 1> basicTypes = { - {{}, - {Type::unreachable}, - {Type::i32}, - {Type::i64}, - {Type::f32}, - {Type::f64}, - {Type::v128}, - {Type::funcref}, - {Type::externref}, - {Type::nullref}, - {Type::exnref}}}; - // Track unique_ptrs for constructed types to avoid leaks -std::vector>> constructedTypes; - -// Maps from type vectors to the canonical Type ID -std::unordered_map, uintptr_t> indices = { - {{}, Type::none}, - {{Type::unreachable}, Type::unreachable}, - {{Type::i32}, Type::i32}, - {{Type::i64}, Type::i64}, - {{Type::f32}, Type::f32}, - {{Type::f64}, Type::f64}, - {{Type::v128}, Type::v128}, - {{Type::funcref}, Type::funcref}, - {{Type::externref}, Type::externref}, - {{Type::nullref}, Type::nullref}, - {{Type::exnref}, Type::exnref}, +std::vector> complexTypes; + +// Maps from complex types to the canonical Type ID. +// Also maps tuples of a single basic type to the basic type. +std::unordered_map complexIndices = { + {TypeDef(Tuple()), Type::none}, + {TypeDef({Type::unreachable}), Type::unreachable}, + {TypeDef({Type::i32}), Type::i32}, + {TypeDef({Type::i64}), Type::i64}, + {TypeDef({Type::f32}), Type::f32}, + {TypeDef({Type::f64}), Type::f64}, + {TypeDef({Type::v128}), Type::v128}, + {TypeDef({Type::funcref}), Type::funcref}, + {TypeDef({Type::externref}), Type::externref}, + {TypeDef({Type::nullref}), Type::nullref}, + {TypeDef({Type::exnref}), Type::exnref}, +}; + +// Maps from the canonical Type ID to complex types. +// Also maps basic types to tuples of the single basic type. +std::unordered_map complexLookup = { + {Type::none, TypeDef(Tuple())}, + {Type::unreachable, TypeDef({Type::unreachable})}, + {Type::i32, TypeDef({Type::i32})}, + {Type::i64, TypeDef({Type::i64})}, + {Type::f32, TypeDef({Type::f32})}, + {Type::f64, TypeDef({Type::f64})}, + {Type::v128, TypeDef({Type::v128})}, + {Type::funcref, TypeDef({Type::funcref})}, + {Type::externref, TypeDef({Type::externref})}, + {Type::nullref, TypeDef({Type::nullref})}, + {Type::exnref, TypeDef({Type::exnref})}, }; } // anonymous namespace -void Type::init(const std::vector& types) { +static uintptr_t canonicalize(const TypeDef& typeDef) { + std::lock_guard lock(mutex); + auto indexIt = complexIndices.find(typeDef); + if (indexIt != complexIndices.end()) { + return indexIt->second; + } + auto ptr = std::make_unique(typeDef); + auto id = uintptr_t(ptr.get()); + complexTypes.push_back(std::move(ptr)); + assert(id > Type::_last_value_type); + complexIndices[typeDef] = id; + complexLookup.emplace(id, typeDef); + return id; +} + +Type::Type(std::initializer_list types) : Type(Tuple(types)) {} + +Type::Type(const Tuple& tuple) { #ifndef NDEBUG - for (Type t : types) { + for (Type t : tuple) { assert(t.isSingle() && t.isConcrete()); } #endif - - if (types.size() == 0) { + if (tuple.size() == 0) { id = none; return; } - if (types.size() == 1) { - *this = types[0]; + if (tuple.size() == 1) { + *this = tuple[0]; return; } + id = canonicalize(TypeDef(tuple)); +} - // Add a new type if it hasn't been added concurrently - std::lock_guard lock(mutex); - auto indexIt = indices.find(types); - if (indexIt != indices.end()) { - id = indexIt->second; - } else { - auto vec = std::make_unique>(types); - id = uintptr_t(vec.get()); - constructedTypes.push_back(std::move(vec)); - assert(id > _last_value_type); - indices[types] = id; +Type::Type(const Signature& signature) { + id = canonicalize(TypeDef(signature)); +} + +Type::Type(const Struct& struct_) { +#ifndef NDEBUG + for (Field f : struct_.fields) { + assert(f.type.isSingle() && f.type.isConcrete()); } +#endif + id = canonicalize(TypeDef(struct_)); } -Type::Type(std::initializer_list types) { init(types); } +Type::Type(const Array& array) { +#ifndef NDEBUG + assert(array.element.type.isSingle() && array.element.type.isConcrete()); +#endif + id = canonicalize(TypeDef(array)); +} -Type::Type(const std::vector& types) { init(types); } +bool Type::isMulti() const { + if (id > _last_value_type) { + auto it = complexLookup.find(id); + if (it != complexLookup.end()) { + return it->second.kind == TypeDef::TupleKind; + } + } + return false; +} + +bool Type::isRef() const { + if (id > _last_value_type) { + auto it = complexLookup.find(id); + if (it != complexLookup.end()) { + switch (it->second.kind) { + case TypeDef::SignatureKind: + case TypeDef::StructKind: + case TypeDef::ArrayKind: + return true; + default: + return false; + } + } + } + return id >= funcref && id <= exnref; +} size_t Type::size() const { return expand().size(); } -const std::vector& Type::expand() const { - if (id <= _last_value_type) { - return basicTypes[id]; - } else { - return *(std::vector*)id; +const Tuple& Type::expand() const { + auto it = complexLookup.find(id); + if (it != complexLookup.end()) { + auto& typeDef = it->second; + if (typeDef.kind == TypeDef::TupleKind) { + return typeDef.def.tuple; + } } + WASM_UNREACHABLE("invalid type"); } bool Type::operator<(const Type& other) const { - const std::vector& these = expand(); - const std::vector& others = other.expand(); + const Tuple& these = expand(); + const Tuple& others = other.expand(); return std::lexicographical_compare( these.begin(), these.end(), @@ -282,7 +377,7 @@ Type Type::getLeastUpperBound(Type a, Type b) { return Type::none; // a poison value that must not be consumed } if (a.isMulti()) { - std::vector types; + Tuple types; types.resize(a.size()); const auto& as = a.expand(); const auto& bs = b.expand(); @@ -343,52 +438,79 @@ bool Signature::operator<(const Signature& other) const { } std::ostream& operator<<(std::ostream& os, Type type) { - if (type.isMulti()) { - os << '('; - const std::vector& types = type.expand(); - for (size_t i = 0; i < types.size(); ++i) { - os << types[i]; - if (i < types.size() - 1) { - os << ", "; + auto id = type.getID(); + switch (id) { + case Type::none: + os << "none"; + break; + case Type::unreachable: + os << "unreachable"; + break; + case Type::i32: + os << "i32"; + break; + case Type::i64: + os << "i64"; + break; + case Type::f32: + os << "f32"; + break; + case Type::f64: + os << "f64"; + break; + case Type::v128: + os << "v128"; + break; + case Type::funcref: + os << "funcref"; + break; + case Type::externref: + os << "externref"; + break; + case Type::nullref: + os << "nullref"; + break; + case Type::exnref: + os << "exnref"; + break; + default: { + assert(id > Type::_last_value_type); + auto it = complexLookup.find(id); + if (it != complexLookup.end()) { + auto& typeDef = it->second; + switch (typeDef.kind) { + case TypeDef::TupleKind: { + auto& tuple = typeDef.def.tuple; + os << '('; + for (size_t i = 0; i < tuple.size(); ++i) { + os << tuple[i]; + if (i < tuple.size() - 1) { + os << ", "; + } + } + os << ')'; + break; + } + case TypeDef::SignatureKind: { + auto& signature = typeDef.def.signature; + os << signature; + break; + } + case TypeDef::StructKind: { + auto& struct_ = typeDef.def.struct_; + os << struct_; + break; + } + case TypeDef::ArrayKind: { + auto& array = typeDef.def.array; + os << array; + break; + } + default: + WASM_UNREACHABLE("invalid type kind"); + } } } - os << ')'; - } else { - switch (type.getSingle()) { - case Type::none: - os << "none"; - break; - case Type::unreachable: - os << "unreachable"; - break; - case Type::i32: - os << "i32"; - break; - case Type::i64: - os << "i64"; - break; - case Type::f32: - os << "f32"; - break; - case Type::f64: - os << "f64"; - break; - case Type::v128: - os << "v128"; - break; - case Type::funcref: - os << "funcref"; - break; - case Type::externref: - os << "externref"; - break; - case Type::nullref: - os << "nullref"; - break; - case Type::exnref: - os << "exnref"; - break; - } } return os; } @@ -405,4 +527,28 @@ std::ostream& operator<<(std::ostream& os, Signature sig) { return os << "Signature(" << sig.params << " => " << sig.results << ")"; } +std::ostream& operator<<(std::ostream& os, Struct struct_) { + os << "struct"; + auto& fields = struct_.fields; + for (auto f : fields) { + if (f.mutable_) { + os << " (mut " << f.type << ")"; + } else { + os << " " << f.type; + } + } + return os; +} + +std::ostream& operator<<(std::ostream& os, Array array) { + os << "array"; + auto& element = array.element; + if (element.mutable_) { + os << " (mut " << element.type << ")"; + } else { + os << element.type; + } + return os; +} + } // namespace wasm From e84664ff6832c365c69e5752dee28c7d18f44276 Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 1 Aug 2020 16:30:22 +0200 Subject: [PATCH 02/50] fix --- src/wasm-type.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 38969b4f476..9c486d18dbd 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -261,8 +261,9 @@ struct TypeDef { // TODO: make internal to wasm-type.cpp ? TypeDef(Array array) : kind(ArrayKind), def(array) {} bool operator==(const TypeDef& other) const { - if (kind != other.kind) + if (kind != other.kind) { return false; + } switch (kind) { case TupleKind: return def.tuple == other.def.tuple; From 185f8871ac985fe0b5968692756878d3fb72a9dd Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 1 Aug 2020 16:38:24 +0200 Subject: [PATCH 03/50] fix --- src/wasm/wasm-type.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index b1a20eb7206..ba91065cefb 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -189,6 +189,7 @@ Type::Type(const Array& array) { bool Type::isMulti() const { if (id > _last_value_type) { + std::lock_guard lock(mutex); auto it = complexLookup.find(id); if (it != complexLookup.end()) { return it->second.kind == TypeDef::TupleKind; @@ -199,6 +200,7 @@ bool Type::isMulti() const { bool Type::isRef() const { if (id > _last_value_type) { + std::lock_guard lock(mutex); auto it = complexLookup.find(id); if (it != complexLookup.end()) { switch (it->second.kind) { @@ -217,6 +219,7 @@ bool Type::isRef() const { size_t Type::size() const { return expand().size(); } const Tuple& Type::expand() const { + std::lock_guard lock(mutex); auto it = complexLookup.find(id); if (it != complexLookup.end()) { auto& typeDef = it->second; @@ -475,6 +478,7 @@ std::ostream& operator<<(std::ostream& os, Type type) { break; default: { assert(id > Type::_last_value_type); + std::lock_guard lock(mutex); auto it = complexLookup.find(id); if (it != complexLookup.end()) { auto& typeDef = it->second; From 415353f3d66e1c5ead4d973b1b199d2ad0c233ec Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 1 Aug 2020 19:16:56 +0200 Subject: [PATCH 04/50] I know nothing --- src/wasm-type.h | 96 +++++++++++++++++++++++++----------------- src/wasm/wasm-type.cpp | 31 +++++++------- 2 files changed, 73 insertions(+), 54 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 9c486d18dbd..ea96d915d22 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -221,58 +221,76 @@ struct Array { struct TypeDef { // TODO: make internal to wasm-type.cpp ? enum Kind { TupleKind, SignatureKind, StructKind, ArrayKind }; - Kind kind; union Def { - Def(Tuple tuple) : tuple(tuple) {} - Def(Signature signature) : signature(signature) {} - Def(Struct struct_) : struct_(struct_) {} - Def(Array array) : array(array) {} - ~Def() {} - Tuple tuple; - Signature signature; - Struct struct_; - Array array; - } def; - - TypeDef(const TypeDef& other) : kind(other.kind), def(Tuple()) { // FIXME - switch (kind) { - case TupleKind: - def.tuple = other.def.tuple; - break; - case SignatureKind: { - def.signature = other.def.signature; - break; - } - case StructKind: { - def.struct_ = other.def.struct_; - break; + struct TupleDef { + Kind kind; + Tuple tuple; + } tupleDef; + struct SignatureDef { + Kind kind; + Signature signature; + } signatureDef; + struct StructDef { + Kind kind; + Struct struct_; + } structDef; + struct ArrayDef { + Kind kind; + Array array; + } arrayDef; + + Def(Tuple tuple) : tupleDef{TupleKind, tuple} {} + Def(Signature signature) : signatureDef{SignatureKind, signature} {} + Def(Struct struct_) : structDef{StructKind, struct_} {} + Def(Array array) : arrayDef{ArrayKind, array} {} + + Def(const Def& other) { + switch (other.tupleDef.kind) { + case TupleKind: + ::new (&tupleDef) auto(other.tupleDef); + break; + case SignatureKind: + ::new (&signatureDef) auto(other.signatureDef); + break; + case StructKind: + ::new (&structDef) auto(other.structDef); + break; + case ArrayKind: + ::new (&arrayDef) auto(other.arrayDef); + break; + default: + WASM_UNREACHABLE("unexpected kind"); } - case ArrayKind: { - def.array = other.def.array; - break; + } + ~Def() { + if (tupleDef.kind == TupleKind) { + tupleDef.~TupleDef(); } - default: - WASM_UNREACHABLE("unexpected kind"); } - } - TypeDef(Tuple tuple) : kind(TupleKind), def(tuple) {} - TypeDef(Signature signature) : kind(SignatureKind), def(signature) {} - TypeDef(Struct struct_) : kind(StructKind), def(struct_) {} - TypeDef(Array array) : kind(ArrayKind), def(array) {} + } def; + + TypeDef(const TypeDef& other) : def(other.def) {} + TypeDef(Tuple tuple) : def(tuple) {} + TypeDef(Signature signature) : def(signature) {} + TypeDef(Struct struct_) : def(struct_) {} + TypeDef(Array array) : def(array) {} + + constexpr Kind getKind() const { return def.tupleDef.kind; } bool operator==(const TypeDef& other) const { - if (kind != other.kind) { + auto kind = getKind(); + if (kind != other.getKind()) { return false; } switch (kind) { case TupleKind: - return def.tuple == other.def.tuple; + return def.tupleDef.tuple == other.def.tupleDef.tuple; case SignatureKind: - return def.signature == other.def.signature; + return def.signatureDef.signature == other.def.signatureDef.signature; case StructKind: - return def.struct_ == other.def.struct_; + return def.structDef.struct_ == other.def.structDef.struct_; case ArrayKind: - return def.array == other.def.array; + return def.arrayDef.array == other.def.arrayDef.array; } WASM_UNREACHABLE("unexpected kind"); } diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index ba91065cefb..0e657ffcd93 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -49,23 +49,24 @@ size_t hash::operator()(const wasm::Signature& sig) const { } size_t hash::operator()(const wasm::TypeDef& typeDef) const { - auto res = hash{}(uint32_t(typeDef.kind)); - switch (typeDef.kind) { + auto kind = typeDef.getKind(); + auto res = hash{}(uint32_t(kind)); + switch (kind) { case wasm::TypeDef::TupleKind: { - auto& tuple = typeDef.def.tuple; + auto& tuple = typeDef.def.tupleDef.tuple; for (auto t : tuple) { wasm::hash_combine(res, t.getID()); } break; } case wasm::TypeDef::SignatureKind: { - auto& sig = typeDef.def.signature; + auto& sig = typeDef.def.signatureDef.signature; wasm::hash_combine(res, sig.params.getID()); wasm::hash_combine(res, sig.results.getID()); break; } case wasm::TypeDef::StructKind: { - auto& struct_ = typeDef.def.struct_; + auto& struct_ = typeDef.def.structDef.struct_; auto& fields = struct_.fields; wasm::hash_combine(res, fields.size()); for (auto f : fields) { @@ -76,7 +77,7 @@ size_t hash::operator()(const wasm::TypeDef& typeDef) const { break; } case wasm::TypeDef::ArrayKind: { - auto& array = typeDef.def.array; + auto& array = typeDef.def.arrayDef.array; wasm::hash_combine(res, array.element.type.getID()); wasm::hash_combine(res, array.element.mutable_); wasm::hash_combine(res, array.nullable); @@ -192,7 +193,7 @@ bool Type::isMulti() const { std::lock_guard lock(mutex); auto it = complexLookup.find(id); if (it != complexLookup.end()) { - return it->second.kind == TypeDef::TupleKind; + return it->second.def.tupleDef.kind == TypeDef::TupleKind; } } return false; @@ -203,7 +204,7 @@ bool Type::isRef() const { std::lock_guard lock(mutex); auto it = complexLookup.find(id); if (it != complexLookup.end()) { - switch (it->second.kind) { + switch (it->second.getKind()) { case TypeDef::SignatureKind: case TypeDef::StructKind: case TypeDef::ArrayKind: @@ -223,8 +224,8 @@ const Tuple& Type::expand() const { auto it = complexLookup.find(id); if (it != complexLookup.end()) { auto& typeDef = it->second; - if (typeDef.kind == TypeDef::TupleKind) { - return typeDef.def.tuple; + if (typeDef.getKind() == TypeDef::TupleKind) { + return typeDef.def.tupleDef.tuple; } } WASM_UNREACHABLE("invalid type"); @@ -482,9 +483,9 @@ std::ostream& operator<<(std::ostream& os, Type type) { auto it = complexLookup.find(id); if (it != complexLookup.end()) { auto& typeDef = it->second; - switch (typeDef.kind) { + switch (typeDef.getKind()) { case TypeDef::TupleKind: { - auto& tuple = typeDef.def.tuple; + auto& tuple = typeDef.def.tupleDef.tuple; os << '('; for (size_t i = 0; i < tuple.size(); ++i) { os << tuple[i]; @@ -496,17 +497,17 @@ std::ostream& operator<<(std::ostream& os, Type type) { break; } case TypeDef::SignatureKind: { - auto& signature = typeDef.def.signature; + auto& signature = typeDef.def.signatureDef.signature; os << signature; break; } case TypeDef::StructKind: { - auto& struct_ = typeDef.def.struct_; + auto& struct_ = typeDef.def.structDef.struct_; os << struct_; break; } case TypeDef::ArrayKind: { - auto& array = typeDef.def.array; + auto& array = typeDef.def.arrayDef.array; os << array; break; } From 941bde4c77b6811760612cef04bc20ac54529a1c Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 1 Aug 2020 19:51:20 +0200 Subject: [PATCH 05/50] layers --- src/wasm-type.h | 105 +++++++++++++++++++---------------------- src/wasm/wasm-type.cpp | 20 ++++---- 2 files changed, 58 insertions(+), 67 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index ea96d915d22..4c01d77424b 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -218,64 +218,55 @@ struct Array { bool operator!=(const Array& other) const { return !(*this == other); } }; -struct TypeDef { // TODO: make internal to wasm-type.cpp ? +union TypeDef { enum Kind { TupleKind, SignatureKind, StructKind, ArrayKind }; - union Def { - struct TupleDef { - Kind kind; - Tuple tuple; - } tupleDef; - struct SignatureDef { - Kind kind; - Signature signature; - } signatureDef; - struct StructDef { - Kind kind; - Struct struct_; - } structDef; - struct ArrayDef { - Kind kind; - Array array; - } arrayDef; - - Def(Tuple tuple) : tupleDef{TupleKind, tuple} {} - Def(Signature signature) : signatureDef{SignatureKind, signature} {} - Def(Struct struct_) : structDef{StructKind, struct_} {} - Def(Array array) : arrayDef{ArrayKind, array} {} - - Def(const Def& other) { - switch (other.tupleDef.kind) { - case TupleKind: - ::new (&tupleDef) auto(other.tupleDef); - break; - case SignatureKind: - ::new (&signatureDef) auto(other.signatureDef); - break; - case StructKind: - ::new (&structDef) auto(other.structDef); - break; - case ArrayKind: - ::new (&arrayDef) auto(other.arrayDef); - break; - default: - WASM_UNREACHABLE("unexpected kind"); - } + struct TupleDef { + Kind kind; + Tuple tuple; + } tupleDef; + struct SignatureDef { + Kind kind; + Signature signature; + } signatureDef; + struct StructDef { + Kind kind; + Struct struct_; + } structDef; + struct ArrayDef { + Kind kind; + Array array; + } arrayDef; + + TypeDef(Tuple tuple) : tupleDef{TupleKind, tuple} {} + TypeDef(Signature signature) : signatureDef{SignatureKind, signature} {} + TypeDef(Struct struct_) : structDef{StructKind, struct_} {} + TypeDef(Array array) : arrayDef{ArrayKind, array} {} + TypeDef(const TypeDef& other) { + switch (other.getKind()) { + case TupleKind: + ::new (&tupleDef) auto(other.tupleDef); + break; + case SignatureKind: + ::new (&signatureDef) auto(other.signatureDef); + break; + case StructKind: + ::new (&structDef) auto(other.structDef); + break; + case ArrayKind: + ::new (&arrayDef) auto(other.arrayDef); + break; + default: + WASM_UNREACHABLE("unexpected kind"); } - ~Def() { - if (tupleDef.kind == TupleKind) { - tupleDef.~TupleDef(); - } + } + ~TypeDef() { + if (tupleDef.kind == TupleKind) { + tupleDef.~TupleDef(); } - } def; - - TypeDef(const TypeDef& other) : def(other.def) {} - TypeDef(Tuple tuple) : def(tuple) {} - TypeDef(Signature signature) : def(signature) {} - TypeDef(Struct struct_) : def(struct_) {} - TypeDef(Array array) : def(array) {} + } - constexpr Kind getKind() const { return def.tupleDef.kind; } + constexpr Kind getKind() const { return tupleDef.kind; } bool operator==(const TypeDef& other) const { auto kind = getKind(); @@ -284,13 +275,13 @@ struct TypeDef { // TODO: make internal to wasm-type.cpp ? } switch (kind) { case TupleKind: - return def.tupleDef.tuple == other.def.tupleDef.tuple; + return tupleDef.tuple == other.tupleDef.tuple; case SignatureKind: - return def.signatureDef.signature == other.def.signatureDef.signature; + return signatureDef.signature == other.signatureDef.signature; case StructKind: - return def.structDef.struct_ == other.def.structDef.struct_; + return structDef.struct_ == other.structDef.struct_; case ArrayKind: - return def.arrayDef.array == other.def.arrayDef.array; + return arrayDef.array == other.arrayDef.array; } WASM_UNREACHABLE("unexpected kind"); } diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 0e657ffcd93..5c5658e8016 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -53,20 +53,20 @@ size_t hash::operator()(const wasm::TypeDef& typeDef) const { auto res = hash{}(uint32_t(kind)); switch (kind) { case wasm::TypeDef::TupleKind: { - auto& tuple = typeDef.def.tupleDef.tuple; + auto& tuple = typeDef.tupleDef.tuple; for (auto t : tuple) { wasm::hash_combine(res, t.getID()); } break; } case wasm::TypeDef::SignatureKind: { - auto& sig = typeDef.def.signatureDef.signature; + auto& sig = typeDef.signatureDef.signature; wasm::hash_combine(res, sig.params.getID()); wasm::hash_combine(res, sig.results.getID()); break; } case wasm::TypeDef::StructKind: { - auto& struct_ = typeDef.def.structDef.struct_; + auto& struct_ = typeDef.structDef.struct_; auto& fields = struct_.fields; wasm::hash_combine(res, fields.size()); for (auto f : fields) { @@ -77,7 +77,7 @@ size_t hash::operator()(const wasm::TypeDef& typeDef) const { break; } case wasm::TypeDef::ArrayKind: { - auto& array = typeDef.def.arrayDef.array; + auto& array = typeDef.arrayDef.array; wasm::hash_combine(res, array.element.type.getID()); wasm::hash_combine(res, array.element.mutable_); wasm::hash_combine(res, array.nullable); @@ -193,7 +193,7 @@ bool Type::isMulti() const { std::lock_guard lock(mutex); auto it = complexLookup.find(id); if (it != complexLookup.end()) { - return it->second.def.tupleDef.kind == TypeDef::TupleKind; + return it->second.getKind() == TypeDef::TupleKind; } } return false; @@ -225,7 +225,7 @@ const Tuple& Type::expand() const { if (it != complexLookup.end()) { auto& typeDef = it->second; if (typeDef.getKind() == TypeDef::TupleKind) { - return typeDef.def.tupleDef.tuple; + return typeDef.tupleDef.tuple; } } WASM_UNREACHABLE("invalid type"); @@ -485,7 +485,7 @@ std::ostream& operator<<(std::ostream& os, Type type) { auto& typeDef = it->second; switch (typeDef.getKind()) { case TypeDef::TupleKind: { - auto& tuple = typeDef.def.tupleDef.tuple; + auto& tuple = typeDef.tupleDef.tuple; os << '('; for (size_t i = 0; i < tuple.size(); ++i) { os << tuple[i]; @@ -497,17 +497,17 @@ std::ostream& operator<<(std::ostream& os, Type type) { break; } case TypeDef::SignatureKind: { - auto& signature = typeDef.def.signatureDef.signature; + auto& signature = typeDef.signatureDef.signature; os << signature; break; } case TypeDef::StructKind: { - auto& struct_ = typeDef.def.structDef.struct_; + auto& struct_ = typeDef.structDef.struct_; os << struct_; break; } case TypeDef::ArrayKind: { - auto& array = typeDef.def.arrayDef.array; + auto& array = typeDef.arrayDef.array; os << array; break; } From 37eb81f2fd214245bff0da49d2ca250bdf580197 Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 1 Aug 2020 23:27:10 +0200 Subject: [PATCH 06/50] unify printing --- src/wasm-type.h | 8 ++++ src/wasm/wasm-type.cpp | 104 ++++++++++++++++++++++++++++------------- 2 files changed, 79 insertions(+), 33 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 4c01d77424b..c104c37af99 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -178,6 +178,7 @@ struct Signature { } bool operator!=(const Signature& other) const { return !(*this == other); } bool operator<(const Signature& other) const; + std::string toString() const; }; struct Field { @@ -188,6 +189,7 @@ struct Field { return type == other.type && mutable_ == other.mutable_; } bool operator!=(const Field& other) const { return !(*this == other); } + std::string toString() const; }; typedef std::vector FieldList; @@ -203,6 +205,7 @@ struct Struct { return fields == other.fields && nullable == other.nullable; } bool operator!=(const Struct& other) const { return !(*this == other); } + std::string toString() const; }; struct Array { @@ -216,6 +219,7 @@ struct Array { return element == other.element && nullable == other.nullable; } bool operator!=(const Array& other) const { return !(*this == other); } + std::string toString() const; }; union TypeDef { @@ -286,14 +290,18 @@ union TypeDef { WASM_UNREACHABLE("unexpected kind"); } bool operator!=(const TypeDef& other) const { return !(*this == other); } + + std::string toString() const; }; std::ostream& operator<<(std::ostream& os, Type t); std::ostream& operator<<(std::ostream& os, ParamType t); std::ostream& operator<<(std::ostream& os, ResultType t); +std::ostream& operator<<(std::ostream& os, Tuple t); std::ostream& operator<<(std::ostream& os, Signature t); std::ostream& operator<<(std::ostream& os, Struct t); std::ostream& operator<<(std::ostream& os, Array t); +std::ostream& operator<<(std::ostream& os, TypeDef t); } // namespace wasm diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 5c5658e8016..dbcde9891e8 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -431,6 +431,14 @@ std::string ParamType::toString() const { return genericToString(*this); } std::string ResultType::toString() const { return genericToString(*this); } +std::string Signature::toString() const { return genericToString(*this); } + +std::string Struct::toString() const { return genericToString(*this); } + +std::string Array::toString() const { return genericToString(*this); } + +std::string TypeDef::toString() const { return genericToString(*this); } + bool Signature::operator<(const Signature& other) const { if (results < other.results) { return true; @@ -483,37 +491,13 @@ std::ostream& operator<<(std::ostream& os, Type type) { auto it = complexLookup.find(id); if (it != complexLookup.end()) { auto& typeDef = it->second; - switch (typeDef.getKind()) { - case TypeDef::TupleKind: { - auto& tuple = typeDef.tupleDef.tuple; - os << '('; - for (size_t i = 0; i < tuple.size(); ++i) { - os << tuple[i]; - if (i < tuple.size() - 1) { - os << ", "; - } - } - os << ')'; - break; - } - case TypeDef::SignatureKind: { - auto& signature = typeDef.signatureDef.signature; - os << signature; - break; - } - case TypeDef::StructKind: { - auto& struct_ = typeDef.structDef.struct_; - os << struct_; - break; - } - case TypeDef::ArrayKind: { - auto& array = typeDef.arrayDef.array; - os << array; - break; - } - default: - WASM_UNREACHABLE("invalid type kind"); + if (typeDef.getKind() == TypeDef::TupleKind) { + os << typeDef; + } else { + os << "ref " << typeDef; } + } else { + WASM_UNREACHABLE("invalid type kind"); } } } @@ -528,11 +512,38 @@ std::ostream& operator<<(std::ostream& os, ResultType param) { return printPrefixedTypes(os, "result", param.type); } +std::ostream& operator<<(std::ostream& os, Tuple tuple) { + os << "("; + auto size = tuple.size(); + if (size) { + os << tuple[0]; + for (size_t i = 1; i < size; ++i) { + os << " " << tuple[i]; + } + } + os << ")"; + return os; +} + std::ostream& operator<<(std::ostream& os, Signature sig) { - return os << "Signature(" << sig.params << " => " << sig.results << ")"; + os << "func"; + if (sig.params.getID() != Type::ValueType::none) { + os << " ("; + printPrefixedTypes(os, "param", sig.params); + os << ")"; + } + if (sig.results.getID() != Type::ValueType::none) { + os << " ("; + printPrefixedTypes(os, "result", sig.results); + os << ")"; + } + return os; } std::ostream& operator<<(std::ostream& os, Struct struct_) { + if (struct_.nullable) { + os << "null "; + } os << "struct"; auto& fields = struct_.fields; for (auto f : fields) { @@ -546,14 +557,41 @@ std::ostream& operator<<(std::ostream& os, Struct struct_) { } std::ostream& operator<<(std::ostream& os, Array array) { - os << "array"; + if (array.nullable) { + os << "null "; + } + os << "array "; auto& element = array.element; if (element.mutable_) { - os << " (mut " << element.type << ")"; + os << "(mut " << element.type << ")"; } else { os << element.type; } return os; } +std::ostream& operator<<(std::ostream& os, TypeDef typeDef) { + switch (typeDef.getKind()) { + case TypeDef::TupleKind: { + os << typeDef.tupleDef.tuple; + break; + } + case TypeDef::SignatureKind: { + os << typeDef.signatureDef.signature; + break; + } + case TypeDef::StructKind: { + os << typeDef.structDef.struct_; + break; + } + case TypeDef::ArrayKind: { + os << typeDef.arrayDef.array; + break; + } + default: + WASM_UNREACHABLE("invalid type kind"); + } + return os; +} + } // namespace wasm From f4067bdcf1ed920ef53ca61ae55c5fbb91966d88 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 2 Aug 2020 16:02:19 +0200 Subject: [PATCH 07/50] tuple terminology, Tuple::toString via wrapping --- src/asmjs/asm_v_wasm.cpp | 2 +- src/ir/module-utils.h | 2 +- src/passes/Print.cpp | 2 +- src/passes/RemoveUnusedBrs.cpp | 2 +- src/tools/fuzzing.h | 14 +++++----- src/tools/wasm-reduce.cpp | 2 +- src/wasm-builder.h | 2 +- src/wasm-type.h | 51 +++++++++++++++++++++++++++------- src/wasm/literal.cpp | 2 +- src/wasm/wasm-binary.cpp | 10 ++++--- src/wasm/wasm-stack.cpp | 2 +- src/wasm/wasm-type.cpp | 40 ++++++++++++++------------ src/wasm/wasm-validator.cpp | 8 +++--- 13 files changed, 88 insertions(+), 51 deletions(-) diff --git a/src/asmjs/asm_v_wasm.cpp b/src/asmjs/asm_v_wasm.cpp index 98a6be046f9..5b7a7fa30fc 100644 --- a/src/asmjs/asm_v_wasm.cpp +++ b/src/asmjs/asm_v_wasm.cpp @@ -99,7 +99,7 @@ std::string getSig(Function* func) { } std::string getSig(Type results, Type params) { - assert(!results.isMulti()); + assert(!results.isTuple()); std::string sig; sig += getSig(results); for (Type t : params.expand()) { diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h index ab23649f7c1..f99b842587c 100644 --- a/src/ir/module-utils.h +++ b/src/ir/module-utils.h @@ -404,7 +404,7 @@ collectSignatures(Module& wasm, counts[call->sig]++; } else if (Properties::isControlFlowStructure(curr)) { // TODO: Allow control flow to have input types as well - if (curr->type.isMulti()) { + if (curr->type.isTuple()) { counts[Signature(Type::none, curr->type)]++; } } diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 6246a5f5ae2..20ec7bc42cb 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -66,7 +66,7 @@ struct SExprType { static std::ostream& operator<<(std::ostream& o, const SExprType& localType) { Type type = localType.type; - if (type.isMulti()) { + if (type.isTuple()) { const std::vector& types = type.expand(); o << '(' << types[0]; for (size_t i = 1; i < types.size(); ++i) { diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 9d4575bb7ae..2238e9e9513 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -319,7 +319,7 @@ struct RemoveUnusedBrs : public WalkerPass> { // be further optimizable, and if select does not branch we also // avoid one branch. // Multivalue selects are not supported - if (br->value && br->value->type.isMulti()) { + if (br->value && br->value->type.isTuple()) { return; } // If running the br's condition unconditionally is too expensive, diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 52a524e29cb..50bb947a0f7 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -306,7 +306,7 @@ class TranslateToFuzzReader { double getDouble() { return Literal(get64()).reinterpretf64(); } Type getSubType(Type type) { - if (type.isMulti()) { + if (type.isTuple()) { std::vector types; for (auto t : type.expand()) { types.push_back(getSubType(t)); @@ -849,7 +849,7 @@ class TranslateToFuzzReader { Expression* _makeConcrete(Type type) { bool canMakeControlFlow = - !type.isMulti() || wasm.features.has(FeatureSet::Multivalue); + !type.isTuple() || wasm.features.has(FeatureSet::Multivalue); using Self = TranslateToFuzzReader; FeatureOptions options; using WeightedOption = decltype(options)::WeightedOption; @@ -885,7 +885,7 @@ class TranslateToFuzzReader { if (type == Type::i32) { options.add(FeatureSet::ReferenceTypes, &Self::makeRefIsNull); } - if (type.isMulti()) { + if (type.isTuple()) { options.add(FeatureSet::Multivalue, &Self::makeTupleMake); } return (this->*pick(options))(type); @@ -1264,7 +1264,7 @@ class TranslateToFuzzReader { Expression* makeTupleMake(Type type) { assert(wasm.features.hasMultivalue()); - assert(type.isMulti()); + assert(type.isTuple()); std::vector elements; for (auto t : type.expand()) { elements.push_back(make(t)); @@ -1742,7 +1742,7 @@ class TranslateToFuzzReader { } return builder.makeRefNull(); } - if (type.isMulti()) { + if (type.isTuple()) { std::vector operands; for (auto t : type.expand()) { operands.push_back(makeConst(t)); @@ -1760,7 +1760,7 @@ class TranslateToFuzzReader { } Expression* makeUnary(Type type) { - assert(!type.isMulti()); + assert(!type.isTuple()); if (type == Type::unreachable) { if (auto* unary = makeUnary(getSingleConcreteType())->dynCast()) { return builder.makeUnary(unary->op, make(Type::unreachable)); @@ -1979,7 +1979,7 @@ class TranslateToFuzzReader { } Expression* makeBinary(Type type) { - assert(!type.isMulti()); + assert(!type.isTuple()); if (type == Type::unreachable) { if (auto* binary = makeBinary(getSingleConcreteType())->dynCast()) { diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp index 029b9092d3d..b6631ddc665 100644 --- a/src/tools/wasm-reduce.cpp +++ b/src/tools/wasm-reduce.cpp @@ -1014,7 +1014,7 @@ struct Reducer RefNull* n = builder->makeRefNull(); return tryToReplaceCurrent(n); } - if (curr->type.isMulti()) { + if (curr->type.isTuple()) { Expression* n = builder->makeConstantExpression(Literal::makeZero(curr->type)); return tryToReplaceCurrent(n); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index e41bd769c16..e548934bdc9 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -794,7 +794,7 @@ class Builder { // minimal contents. as a replacement, this may reuse the // input node template Expression* replaceWithIdenticalType(T* curr) { - if (curr->type.isMulti()) { + if (curr->type.isTuple()) { return makeConstantExpression(Literal::makeZero(curr->type)); } Literal value; diff --git a/src/wasm-type.h b/src/wasm-type.h index c104c37af99..3e5d17b7231 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -24,11 +24,13 @@ namespace wasm { class Type; -typedef std::vector Tuple; +struct Tuple; struct Signature; struct Struct; struct Array; +typedef std::vector TypeList; + class Type { // The `id` uniquely represents each type, so type equality is just a // comparison of the ids. For basic types the `id` is just the `ValueType` @@ -60,22 +62,24 @@ class Type { // But converting raw uint32_t is more dangerous, so make it explicit explicit Type(uint64_t id) : id(id){}; - // Construct from lists of elementary types + // Construct tuple from lists of elementary types Type(std::initializer_list); + + // Construct from tuple description explicit Type(const Tuple&); - // Construct from signature descriptions + // Construct from signature description explicit Type(const Signature&); - // Construct from struct descriptions + // Construct from struct description explicit Type(const Struct&); - // Construct from array descriptions + // Construct from array description explicit Type(const Array&); // Accessors size_t size() const; - const Tuple& expand() const; + const TypeList& expand() const; // Predicates constexpr bool isSingle() const { @@ -86,7 +90,7 @@ class Type { constexpr bool isFloat() const { return id == f32 || id == f64; } constexpr bool isVector() const { return id == v128; }; constexpr bool isNumber() const { return id >= i32 && id <= v128; } - bool isMulti() const; + bool isTuple() const; bool isRef() const; private: @@ -105,7 +109,7 @@ class Type { constexpr uint64_t getID() const { return id; } ValueType getSingle() const { - assert(!isMulti() && "Unexpected multivalue type"); + assert(!isTuple() && "Unexpected tuple type"); return static_cast(id); } @@ -168,6 +172,16 @@ struct ResultType { std::string toString() const; }; +struct Tuple { + TypeList types; + Tuple() : types({}) {} + Tuple(std::initializer_list types) : types(types) {} + Tuple(TypeList types) : types(types) {} + bool operator==(const Tuple& other) const { return types == other.types; } + bool operator!=(const Tuple& other) const { return !(*this == other); } + std::string toString() const; +}; + struct Signature { Type params; Type results; @@ -265,8 +279,25 @@ union TypeDef { } } ~TypeDef() { - if (tupleDef.kind == TupleKind) { - tupleDef.~TupleDef(); + switch (getKind()) { + case TupleKind: { + tupleDef.~TupleDef(); + break; + } + case SignatureKind: { + signatureDef.~SignatureDef(); + break; + } + case StructKind: { + structDef.~StructDef(); + break; + } + case ArrayKind: { + arrayDef.~ArrayDef(); + break; + } + default: + WASM_UNREACHABLE("unexpected kind"); } } diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index f0a065c45cd..40494cec416 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -37,7 +37,7 @@ Literal::Literal(const Literal& other) { *this = other; } Literal& Literal::operator=(const Literal& other) { type = other.type; - assert(!type.isMulti()); + assert(!type.isTuple()); switch (type.getSingle()) { case Type::i32: case Type::f32: diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index bb5d420a952..60e0623e3d5 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -1385,7 +1385,9 @@ void WasmBinaryBuilder::readImports() { wasm.addEvent(curr); break; } - default: { throwError("bad import kind"); } + default: { + throwError("bad import kind"); + } } } } @@ -1790,7 +1792,7 @@ void WasmBinaryBuilder::skipUnreachableCode() { } void WasmBinaryBuilder::pushExpression(Expression* curr) { - if (curr->type.isMulti()) { + if (curr->type.isTuple()) { // Store tuple to local and push individual extracted values Builder builder(wasm); Index tuple = builder.addVar(currFunction, curr->type); @@ -1820,7 +1822,7 @@ Expression* WasmBinaryBuilder::popExpression() { } // the stack is not empty, and we would not be going out of the current block auto ret = expressionStack.back(); - assert(!ret->type.isMulti()); + assert(!ret->type.isTuple()); expressionStack.pop_back(); return ret; } @@ -1883,7 +1885,7 @@ Expression* WasmBinaryBuilder::popTuple(size_t numElems) { Expression* WasmBinaryBuilder::popTypedExpression(Type type) { if (type.isSingle()) { return popNonVoidExpression(); - } else if (type.isMulti()) { + } else if (type.isTuple()) { return popTuple(type.size()); } else { WASM_UNREACHABLE("Invalid popped type"); diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 9e3ce2afa1a..f6cd736a1b2 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -23,7 +23,7 @@ namespace wasm { void BinaryInstWriter::emitResultType(Type type) { if (type == Type::unreachable) { o << binaryType(Type::none); - } else if (type.isMulti()) { + } else if (type.isTuple()) { o << S32LEB(parent.getTypeIndex(Signature(Type::none, type))); } else { o << binaryType(type); diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index dbcde9891e8..4942d325bfd 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -32,7 +32,7 @@ template<> class hash> { size_t operator()(const vector& types) const { auto res = hash{}(types.size()); for (auto t : types) { - wasm::hash_combine(res, t.getID()); + wasm::hash_combine(res, t.getID()); } return res; } @@ -53,8 +53,8 @@ size_t hash::operator()(const wasm::TypeDef& typeDef) const { auto res = hash{}(uint32_t(kind)); switch (kind) { case wasm::TypeDef::TupleKind: { - auto& tuple = typeDef.tupleDef.tuple; - for (auto t : tuple) { + auto& types = typeDef.tupleDef.tuple.types; + for (auto t : types) { wasm::hash_combine(res, t.getID()); } break; @@ -152,17 +152,18 @@ static uintptr_t canonicalize(const TypeDef& typeDef) { Type::Type(std::initializer_list types) : Type(Tuple(types)) {} Type::Type(const Tuple& tuple) { + auto& types = tuple.types; #ifndef NDEBUG - for (Type t : tuple) { + for (Type t : types) { assert(t.isSingle() && t.isConcrete()); } #endif - if (tuple.size() == 0) { + if (types.size() == 0) { id = none; return; } - if (tuple.size() == 1) { - *this = tuple[0]; + if (types.size() == 1) { + *this = types[0]; return; } id = canonicalize(TypeDef(tuple)); @@ -188,7 +189,7 @@ Type::Type(const Array& array) { id = canonicalize(TypeDef(array)); } -bool Type::isMulti() const { +bool Type::isTuple() const { if (id > _last_value_type) { std::lock_guard lock(mutex); auto it = complexLookup.find(id); @@ -219,21 +220,21 @@ bool Type::isRef() const { size_t Type::size() const { return expand().size(); } -const Tuple& Type::expand() const { +const TypeList& Type::expand() const { std::lock_guard lock(mutex); auto it = complexLookup.find(id); if (it != complexLookup.end()) { auto& typeDef = it->second; if (typeDef.getKind() == TypeDef::TupleKind) { - return typeDef.tupleDef.tuple; + return typeDef.tupleDef.tuple.types; } } WASM_UNREACHABLE("invalid type"); } bool Type::operator<(const Type& other) const { - const Tuple& these = expand(); - const Tuple& others = other.expand(); + const TypeList& these = expand(); + const TypeList& others = other.expand(); return std::lexicographical_compare( these.begin(), these.end(), @@ -351,7 +352,7 @@ bool Type::isSubType(Type left, Type right) { (right == Type::externref || left == Type::nullref)) { return true; } - if (left.isMulti() && right.isMulti()) { + if (left.isTuple() && right.isTuple()) { const auto& leftElems = left.expand(); const auto& rightElems = right.expand(); if (leftElems.size() != rightElems.size()) { @@ -380,8 +381,8 @@ 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.isMulti()) { - Tuple types; + if (a.isTuple()) { + TypeList types; types.resize(a.size()); const auto& as = a.expand(); const auto& bs = b.expand(); @@ -431,6 +432,8 @@ std::string ParamType::toString() const { return genericToString(*this); } std::string ResultType::toString() const { return genericToString(*this); } +std::string Tuple::toString() const { return genericToString(*this); } + std::string Signature::toString() const { return genericToString(*this); } std::string Struct::toString() const { return genericToString(*this); } @@ -514,11 +517,12 @@ std::ostream& operator<<(std::ostream& os, ResultType param) { std::ostream& operator<<(std::ostream& os, Tuple tuple) { os << "("; - auto size = tuple.size(); + auto& types = tuple.types; + auto size = types.size(); if (size) { - os << tuple[0]; + os << types[0]; for (size_t i = 1; i < size; ++i) { - os << " " << tuple[i]; + os << " " << types[i]; } } os << ")"; diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 2c2aac1c862..d914b9c2e82 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -389,7 +389,7 @@ void FunctionValidator::noteLabelName(Name name) { void FunctionValidator::visitBlock(Block* curr) { if (!getModule()->features.hasMultivalue()) { - shouldBeTrue(!curr->type.isMulti(), + shouldBeTrue(!curr->type.isTuple(), curr, "Multivalue block type (multivalue is not enabled)"); } @@ -1964,7 +1964,7 @@ void FunctionValidator::visitTupleExtract(TupleExtract* curr) { } void FunctionValidator::visitFunction(Function* curr) { - if (curr->sig.results.isMulti()) { + if (curr->sig.results.isTuple()) { shouldBeTrue(getModule()->features.hasMultivalue(), curr->body, "Multivalue function results (multivalue is not enabled)"); @@ -2131,7 +2131,7 @@ static void validateBinaryenIR(Module& wasm, ValidationInfo& info) { static void validateImports(Module& module, ValidationInfo& info) { ModuleUtils::iterImportedFunctions(module, [&](Function* curr) { - if (curr->sig.results.isMulti()) { + if (curr->sig.results.isTuple()) { info.shouldBeTrue(module.features.hasMultivalue(), curr->name, "Imported multivalue function " @@ -2341,7 +2341,7 @@ static void validateEvents(Module& module, ValidationInfo& info) { Type(Type::none), curr->name, "Event type's result type should be none"); - if (curr->sig.params.isMulti()) { + if (curr->sig.params.isTuple()) { info.shouldBeTrue(module.features.hasMultivalue(), curr->name, "Multivalue event type (multivalue is not enabled)"); From 5146da29da88dfc8a7fe8bb2077a7b1128a897c8 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 2 Aug 2020 18:11:09 +0200 Subject: [PATCH 08/50] make nullable a conditional property of specific TypeDefs --- src/wasm-type.h | 96 ++++++++++++++++++++++++------------------ src/wasm/wasm-type.cpp | 40 ++++++++---------- 2 files changed, 73 insertions(+), 63 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 3e5d17b7231..6ab8efe4446 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -69,13 +69,13 @@ class Type { explicit Type(const Tuple&); // Construct from signature description - explicit Type(const Signature&); + explicit Type(const Signature&, bool nullable); // Construct from struct description - explicit Type(const Struct&); + explicit Type(const Struct&, bool nullable); // Construct from array description - explicit Type(const Array&); + explicit Type(const Array&, bool nullable); // Accessors size_t size() const; @@ -210,28 +210,18 @@ typedef std::vector FieldList; struct Struct { FieldList fields; - bool nullable; - Struct(const Struct& other) - : fields(other.fields), nullable(other.nullable) {} - Struct(FieldList fields, bool nullable = false) - : fields(fields), nullable(nullable) {} - bool operator==(const Struct& other) const { - return fields == other.fields && nullable == other.nullable; - } + Struct(const Struct& other) : fields(other.fields) {} + Struct(FieldList fields, bool nullable = false) : fields(fields) {} + bool operator==(const Struct& other) const { return fields == other.fields; } bool operator!=(const Struct& other) const { return !(*this == other); } std::string toString() const; }; struct Array { Field element; - bool nullable; - Array(const Array& other) - : element(other.element), nullable(other.nullable) {} - Array(Field element, bool nullable = false) - : element(element), nullable(nullable) {} - bool operator==(const Array& other) const { - return element == other.element && nullable == other.nullable; - } + Array(const Array& other) : element(other.element) {} + Array(Field element, bool nullable = false) : element(element) {} + bool operator==(const Array& other) const { return element == other.element; } bool operator!=(const Array& other) const { return !(*this == other); } std::string toString() const; }; @@ -246,62 +236,83 @@ union TypeDef { struct SignatureDef { Kind kind; Signature signature; + bool nullable; } signatureDef; struct StructDef { Kind kind; Struct struct_; + bool nullable; } structDef; struct ArrayDef { Kind kind; Array array; + bool nullable; } arrayDef; TypeDef(Tuple tuple) : tupleDef{TupleKind, tuple} {} - TypeDef(Signature signature) : signatureDef{SignatureKind, signature} {} - TypeDef(Struct struct_) : structDef{StructKind, struct_} {} - TypeDef(Array array) : arrayDef{ArrayKind, array} {} + TypeDef(Signature signature, bool nullable) + : signatureDef{SignatureKind, signature, nullable} {} + TypeDef(Struct struct_, bool nullable) + : structDef{StructKind, struct_, nullable} {} + TypeDef(Array array, bool nullable) : arrayDef{ArrayKind, array, nullable} {} TypeDef(const TypeDef& other) { switch (other.getKind()) { case TupleKind: - ::new (&tupleDef) auto(other.tupleDef); - break; + new (&tupleDef) auto(other.tupleDef); + return; case SignatureKind: - ::new (&signatureDef) auto(other.signatureDef); - break; + new (&signatureDef) auto(other.signatureDef); + return; case StructKind: - ::new (&structDef) auto(other.structDef); - break; + new (&structDef) auto(other.structDef); + return; case ArrayKind: - ::new (&arrayDef) auto(other.arrayDef); - break; - default: - WASM_UNREACHABLE("unexpected kind"); + new (&arrayDef) auto(other.arrayDef); + return; } + WASM_UNREACHABLE("unexpected kind"); } ~TypeDef() { switch (getKind()) { case TupleKind: { tupleDef.~TupleDef(); - break; + return; } case SignatureKind: { signatureDef.~SignatureDef(); - break; + return; } case StructKind: { structDef.~StructDef(); - break; + return; } case ArrayKind: { arrayDef.~ArrayDef(); - break; + return; } - default: - WASM_UNREACHABLE("unexpected kind"); } + WASM_UNREACHABLE("unexpected kind"); } constexpr Kind getKind() const { return tupleDef.kind; } + constexpr bool isTuple() const { return getKind() == TupleKind; } + constexpr bool isSignature() const { return getKind() == SignatureKind; } + constexpr bool isStruct() const { return getKind() == StructKind; } + constexpr bool isArray() const { return getKind() == ArrayKind; } + + bool isNullable() const { + switch (getKind()) { + case TupleKind: + return false; + case SignatureKind: + return signatureDef.nullable; + case StructKind: + return structDef.nullable; + case ArrayKind: + return arrayDef.nullable; + } + WASM_UNREACHABLE("unexpected kind"); + } bool operator==(const TypeDef& other) const { auto kind = getKind(); @@ -312,11 +323,14 @@ union TypeDef { case TupleKind: return tupleDef.tuple == other.tupleDef.tuple; case SignatureKind: - return signatureDef.signature == other.signatureDef.signature; + return signatureDef.nullable == other.signatureDef.nullable && + signatureDef.signature == other.signatureDef.signature; case StructKind: - return structDef.struct_ == other.structDef.struct_; + return structDef.nullable == other.structDef.nullable && + structDef.struct_ == other.structDef.struct_; case ArrayKind: - return arrayDef.array == other.arrayDef.array; + return arrayDef.nullable == other.arrayDef.nullable && + arrayDef.array == other.arrayDef.array; } WASM_UNREACHABLE("unexpected kind"); } diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 4942d325bfd..e3813b9b792 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -63,24 +63,24 @@ size_t hash::operator()(const wasm::TypeDef& typeDef) const { auto& sig = typeDef.signatureDef.signature; wasm::hash_combine(res, sig.params.getID()); wasm::hash_combine(res, sig.results.getID()); + wasm::hash_combine(res, typeDef.isNullable()); break; } case wasm::TypeDef::StructKind: { - auto& struct_ = typeDef.structDef.struct_; - auto& fields = struct_.fields; + auto& fields = typeDef.structDef.struct_.fields; wasm::hash_combine(res, fields.size()); for (auto f : fields) { wasm::hash_combine(res, f.type.getID()); wasm::hash_combine(res, f.mutable_); } - wasm::hash_combine(res, struct_.nullable); + wasm::hash_combine(res, typeDef.isNullable()); break; } case wasm::TypeDef::ArrayKind: { auto& array = typeDef.arrayDef.array; wasm::hash_combine(res, array.element.type.getID()); wasm::hash_combine(res, array.element.mutable_); - wasm::hash_combine(res, array.nullable); + wasm::hash_combine(res, typeDef.isNullable()); break; } default: @@ -169,24 +169,24 @@ Type::Type(const Tuple& tuple) { id = canonicalize(TypeDef(tuple)); } -Type::Type(const Signature& signature) { - id = canonicalize(TypeDef(signature)); +Type::Type(const Signature& signature, bool nullable) { + id = canonicalize(TypeDef(signature, nullable)); } -Type::Type(const Struct& struct_) { +Type::Type(const Struct& struct_, bool nullable) { #ifndef NDEBUG for (Field f : struct_.fields) { assert(f.type.isSingle() && f.type.isConcrete()); } #endif - id = canonicalize(TypeDef(struct_)); + id = canonicalize(TypeDef(struct_, nullable)); } -Type::Type(const Array& array) { +Type::Type(const Array& array, bool nullable) { #ifndef NDEBUG assert(array.element.type.isSingle() && array.element.type.isConcrete()); #endif - id = canonicalize(TypeDef(array)); + id = canonicalize(TypeDef(array, nullable)); } bool Type::isTuple() const { @@ -194,7 +194,7 @@ bool Type::isTuple() const { std::lock_guard lock(mutex); auto it = complexLookup.find(id); if (it != complexLookup.end()) { - return it->second.getKind() == TypeDef::TupleKind; + return it->second.isTuple(); } } return false; @@ -225,7 +225,7 @@ const TypeList& Type::expand() const { auto it = complexLookup.find(id); if (it != complexLookup.end()) { auto& typeDef = it->second; - if (typeDef.getKind() == TypeDef::TupleKind) { + if (typeDef.isTuple()) { return typeDef.tupleDef.tuple.types; } } @@ -494,11 +494,13 @@ std::ostream& operator<<(std::ostream& os, Type type) { auto it = complexLookup.find(id); if (it != complexLookup.end()) { auto& typeDef = it->second; - if (typeDef.getKind() == TypeDef::TupleKind) { - os << typeDef; - } else { - os << "ref " << typeDef; + if (!typeDef.isTuple()) { + os << "ref "; + if (typeDef.isNullable()) { + os << "null "; + } } + os << typeDef; } else { WASM_UNREACHABLE("invalid type kind"); } @@ -545,9 +547,6 @@ std::ostream& operator<<(std::ostream& os, Signature sig) { } std::ostream& operator<<(std::ostream& os, Struct struct_) { - if (struct_.nullable) { - os << "null "; - } os << "struct"; auto& fields = struct_.fields; for (auto f : fields) { @@ -561,9 +560,6 @@ std::ostream& operator<<(std::ostream& os, Struct struct_) { } std::ostream& operator<<(std::ostream& os, Array array) { - if (array.nullable) { - os << "null "; - } os << "array "; auto& element = array.element; if (element.mutable_) { From 72990283e78aaa47a09a1a9e4752212a9bed3c4b Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 2 Aug 2020 18:26:51 +0200 Subject: [PATCH 09/50] remove now unused function parameters --- src/wasm-type.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 6ab8efe4446..e530a29fb46 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -211,7 +211,7 @@ typedef std::vector FieldList; struct Struct { FieldList fields; Struct(const Struct& other) : fields(other.fields) {} - Struct(FieldList fields, bool nullable = false) : fields(fields) {} + Struct(FieldList fields) : fields(fields) {} bool operator==(const Struct& other) const { return fields == other.fields; } bool operator!=(const Struct& other) const { return !(*this == other); } std::string toString() const; @@ -220,7 +220,7 @@ struct Struct { struct Array { Field element; Array(const Array& other) : element(other.element) {} - Array(Field element, bool nullable = false) : element(element) {} + Array(Field element) : element(element) {} bool operator==(const Array& other) const { return element == other.element; } bool operator!=(const Array& other) const { return !(*this == other); } std::string toString() const; From a8dce05bb12482f21b4284bbac4e731af13c2ff1 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 2 Aug 2020 18:35:07 +0200 Subject: [PATCH 10/50] move 'null' to TypeDef when printing --- src/wasm/wasm-type.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index e3813b9b792..6e54ac84f7b 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -496,9 +496,6 @@ std::ostream& operator<<(std::ostream& os, Type type) { auto& typeDef = it->second; if (!typeDef.isTuple()) { os << "ref "; - if (typeDef.isNullable()) { - os << "null "; - } } os << typeDef; } else { @@ -577,14 +574,23 @@ std::ostream& operator<<(std::ostream& os, TypeDef typeDef) { break; } case TypeDef::SignatureKind: { + if (typeDef.signatureDef.nullable) { + os << "null "; + } os << typeDef.signatureDef.signature; break; } case TypeDef::StructKind: { + if (typeDef.structDef.nullable) { + os << "null "; + } os << typeDef.structDef.struct_; break; } case TypeDef::ArrayKind: { + if (typeDef.arrayDef.nullable) { + os << "null "; + } os << typeDef.arrayDef.array; break; } From e006f215cf62ee0ac68b33ae28596e485e996a71 Mon Sep 17 00:00:00 2001 From: dcode Date: Mon, 3 Aug 2020 00:03:35 +0200 Subject: [PATCH 11/50] ValueType -> ID, efficient lookups --- src/wasm-type.h | 24 ++++----- src/wasm/literal.cpp | 3 +- src/wasm/wasm-type.cpp | 120 ++++++++++++++++++----------------------- 3 files changed, 65 insertions(+), 82 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index e530a29fb46..b0607fa75f0 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -33,13 +33,13 @@ typedef std::vector TypeList; class Type { // The `id` uniquely represents each type, so type equality is just a - // comparison of the ids. For basic types the `id` is just the `ValueType` + // comparison of the ids. For basic types the `id` is just the `ID` // enum value below, and for constructed types the `id` is the address of the // canonical representation of the type, making lookups cheap for all types. uintptr_t id; public: - enum ValueType : uint32_t { + enum ID : uint32_t { none, unreachable, i32, @@ -51,13 +51,13 @@ class Type { externref, nullref, exnref, - _last_value_type = exnref + _last_basic_id = exnref }; Type() = default; - // ValueType can be implicitly upgraded to Type - constexpr Type(ValueType id) : id(id){}; + // ID can be implicitly upgraded to Type + constexpr Type(ID id) : id(id){}; // But converting raw uint32_t is more dangerous, so make it explicit explicit Type(uint64_t id) : id(id){}; @@ -82,9 +82,7 @@ class Type { const TypeList& expand() const; // Predicates - constexpr bool isSingle() const { - return id >= i32 && id <= _last_value_type; - } + constexpr bool isSingle() const { return id >= i32 && id <= _last_basic_id; } constexpr bool isConcrete() const { return id >= i32; } constexpr bool isInteger() const { return id == i32 || id == i64; } constexpr bool isFloat() const { return id == f32 || id == f64; } @@ -108,18 +106,18 @@ class Type { bool hasRef() { return hasPredicate<&Type::isRef>(); } constexpr uint64_t getID() const { return id; } - ValueType getSingle() const { + ID getSingle() const { assert(!isTuple() && "Unexpected tuple type"); - return static_cast(id); + return static_cast(id); } - // (In)equality must be defined for both Type and ValueType because it is + // (In)equality must be defined for both Type and ID because it is // otherwise ambiguous whether to convert both this and other to int or // convert other to Type. bool operator==(const Type& other) const { return id == other.id; } - bool operator==(const ValueType& other) const { return id == other; } + bool operator==(const ID& other) const { return id == other; } bool operator!=(const Type& other) const { return id != other.id; } - bool operator!=(const ValueType& other) const { return id != other; } + bool operator!=(const ID& other) const { return id != other; } // Order types by some notion of simplicity bool operator<(const Type& other) const; diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 40494cec416..0092c83cccd 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -1433,8 +1433,7 @@ Literal Literal::shuffleV8x16(const Literal& other, return Literal(bytes); } -template -static Literal splat(const Literal& val) { +template static Literal splat(const Literal& val) { assert(val.type == Ty); LaneArray lanes; lanes.fill(val); diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 6e54ac84f7b..21c415775d9 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -97,12 +97,26 @@ namespace { std::mutex mutex; +// Maps basic types to tuples of the single basic type. +std::array basicTuples = {{ + {}, + {Type::unreachable}, + {Type::i32}, + {Type::i64}, + {Type::f32}, + {Type::f64}, + {Type::v128}, + {Type::funcref}, + {Type::externref}, + {Type::nullref}, + {Type::exnref}, +}}; + // Track unique_ptrs for constructed types to avoid leaks -std::vector> complexTypes; +std::vector> constructedTypes; -// Maps from complex types to the canonical Type ID. -// Also maps tuples of a single basic type to the basic type. -std::unordered_map complexIndices = { +// Maps from constructed types to the canonical Type ID. +std::unordered_map indices = { {TypeDef(Tuple()), Type::none}, {TypeDef({Type::unreachable}), Type::unreachable}, {TypeDef({Type::i32}), Type::i32}, @@ -116,36 +130,19 @@ std::unordered_map complexIndices = { {TypeDef({Type::exnref}), Type::exnref}, }; -// Maps from the canonical Type ID to complex types. -// Also maps basic types to tuples of the single basic type. -std::unordered_map complexLookup = { - {Type::none, TypeDef(Tuple())}, - {Type::unreachable, TypeDef({Type::unreachable})}, - {Type::i32, TypeDef({Type::i32})}, - {Type::i64, TypeDef({Type::i64})}, - {Type::f32, TypeDef({Type::f32})}, - {Type::f64, TypeDef({Type::f64})}, - {Type::v128, TypeDef({Type::v128})}, - {Type::funcref, TypeDef({Type::funcref})}, - {Type::externref, TypeDef({Type::externref})}, - {Type::nullref, TypeDef({Type::nullref})}, - {Type::exnref, TypeDef({Type::exnref})}, -}; - } // anonymous namespace static uintptr_t canonicalize(const TypeDef& typeDef) { std::lock_guard lock(mutex); - auto indexIt = complexIndices.find(typeDef); - if (indexIt != complexIndices.end()) { + auto indexIt = indices.find(typeDef); + if (indexIt != indices.end()) { return indexIt->second; } auto ptr = std::make_unique(typeDef); auto id = uintptr_t(ptr.get()); - complexTypes.push_back(std::move(ptr)); - assert(id > Type::_last_value_type); - complexIndices[typeDef] = id; - complexLookup.emplace(id, typeDef); + constructedTypes.push_back(std::move(ptr)); + assert(id > Type::_last_basic_id); + indices[typeDef] = id; return id; } @@ -190,46 +187,40 @@ Type::Type(const Array& array, bool nullable) { } bool Type::isTuple() const { - if (id > _last_value_type) { - std::lock_guard lock(mutex); - auto it = complexLookup.find(id); - if (it != complexLookup.end()) { - return it->second.isTuple(); - } + if (id <= _last_basic_id) { + return false; + } else { + auto* typeDef = (TypeDef*)id; + return typeDef->isTuple(); } - return false; } bool Type::isRef() const { - if (id > _last_value_type) { - std::lock_guard lock(mutex); - auto it = complexLookup.find(id); - if (it != complexLookup.end()) { - switch (it->second.getKind()) { - case TypeDef::SignatureKind: - case TypeDef::StructKind: - case TypeDef::ArrayKind: - return true; - default: - return false; - } + if (id <= _last_basic_id) { + return id >= funcref && id <= exnref; + } else { + auto* typeDef = (TypeDef*)id; + switch (typeDef->getKind()) { + case TypeDef::SignatureKind: + case TypeDef::StructKind: + case TypeDef::ArrayKind: + return true; + default: + return false; } } - return id >= funcref && id <= exnref; } size_t Type::size() const { return expand().size(); } const TypeList& Type::expand() const { - std::lock_guard lock(mutex); - auto it = complexLookup.find(id); - if (it != complexLookup.end()) { - auto& typeDef = it->second; - if (typeDef.isTuple()) { - return typeDef.tupleDef.tuple.types; - } + if (id <= Type::_last_basic_id) { + return basicTuples[id]; + } else { + auto* typeDef = (TypeDef*)id; + assert(typeDef->isTuple() && "can only expand tuple types"); + return typeDef->tupleDef.tuple.types; } - WASM_UNREACHABLE("invalid type"); } bool Type::operator<(const Type& other) const { @@ -489,18 +480,13 @@ std::ostream& operator<<(std::ostream& os, Type type) { os << "exnref"; break; default: { - assert(id > Type::_last_value_type); - std::lock_guard lock(mutex); - auto it = complexLookup.find(id); - if (it != complexLookup.end()) { - auto& typeDef = it->second; - if (!typeDef.isTuple()) { - os << "ref "; - } - os << typeDef; - } else { - WASM_UNREACHABLE("invalid type kind"); + assert(id > Type::_last_basic_id); + auto* typeDef = (TypeDef*)id; + if (!typeDef->isTuple()) { + os << "ref "; } + os << *typeDef; + break; } } return os; @@ -530,12 +516,12 @@ std::ostream& operator<<(std::ostream& os, Tuple tuple) { std::ostream& operator<<(std::ostream& os, Signature sig) { os << "func"; - if (sig.params.getID() != Type::ValueType::none) { + if (sig.params.getID() != Type::none) { os << " ("; printPrefixedTypes(os, "param", sig.params); os << ")"; } - if (sig.results.getID() != Type::ValueType::none) { + if (sig.results.getID() != Type::none) { os << " ("; printPrefixedTypes(os, "result", sig.results); os << ")"; From a41c3d5a272dcd1609f8d637d2b8d00dc1cd9b64 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Mon, 3 Aug 2020 14:38:40 -0700 Subject: [PATCH 12/50] Extract kind --- src/wasm-type.h | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index b0607fa75f0..1d6c79aa323 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -224,35 +224,37 @@ struct Array { std::string toString() const; }; -union TypeDef { - enum Kind { TupleKind, SignatureKind, StructKind, ArrayKind }; - +struct TypeDef { + enum Kind { TupleKind, SignatureKind, StructKind, ArrayKind } kind; struct TupleDef { - Kind kind; Tuple tuple; - } tupleDef; + }; struct SignatureDef { - Kind kind; Signature signature; bool nullable; - } signatureDef; + }; struct StructDef { - Kind kind; Struct struct_; bool nullable; - } structDef; + }; struct ArrayDef { - Kind kind; Array array; bool nullable; - } arrayDef; + }; + union { + TupleDef tupleDef; + SignatureDef signatureDef; + StructDef structDef; + ArrayDef arrayDef; + }; - TypeDef(Tuple tuple) : tupleDef{TupleKind, tuple} {} + TypeDef(Tuple tuple) : kind(TupleKind), tupleDef{tuple} {} TypeDef(Signature signature, bool nullable) - : signatureDef{SignatureKind, signature, nullable} {} + : kind(SignatureKind), signatureDef{signature, nullable} {} TypeDef(Struct struct_, bool nullable) - : structDef{StructKind, struct_, nullable} {} - TypeDef(Array array, bool nullable) : arrayDef{ArrayKind, array, nullable} {} + : kind(StructKind), structDef{struct_, nullable} {} + TypeDef(Array array, bool nullable) + : kind(ArrayKind), arrayDef{array, nullable} {} TypeDef(const TypeDef& other) { switch (other.getKind()) { case TupleKind: @@ -292,7 +294,7 @@ union TypeDef { WASM_UNREACHABLE("unexpected kind"); } - constexpr Kind getKind() const { return tupleDef.kind; } + constexpr Kind getKind() const { return kind; } constexpr bool isTuple() const { return getKind() == TupleKind; } constexpr bool isSignature() const { return getKind() == SignatureKind; } constexpr bool isStruct() const { return getKind() == StructKind; } From 2764af7acdcfa37b504896b6b5246531a221c37b Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 4 Aug 2020 00:09:14 +0200 Subject: [PATCH 13/50] rename Type::ID to Type::BasicID --- src/wasm-type.h | 14 +++++++------- src/wasm/literal.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index b0607fa75f0..b81c69aaca3 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -33,13 +33,13 @@ typedef std::vector TypeList; class Type { // The `id` uniquely represents each type, so type equality is just a - // comparison of the ids. For basic types the `id` is just the `ID` + // comparison of the ids. For basic types the `id` is just the `BasicID` // enum value below, and for constructed types the `id` is the address of the // canonical representation of the type, making lookups cheap for all types. uintptr_t id; public: - enum ID : uint32_t { + enum BasicID : uint32_t { none, unreachable, i32, @@ -57,7 +57,7 @@ class Type { Type() = default; // ID can be implicitly upgraded to Type - constexpr Type(ID id) : id(id){}; + constexpr Type(BasicID id) : id(id){}; // But converting raw uint32_t is more dangerous, so make it explicit explicit Type(uint64_t id) : id(id){}; @@ -106,18 +106,18 @@ class Type { bool hasRef() { return hasPredicate<&Type::isRef>(); } constexpr uint64_t getID() const { return id; } - ID getSingle() const { + BasicID getSingle() const { assert(!isTuple() && "Unexpected tuple type"); - return static_cast(id); + return static_cast(id); } // (In)equality must be defined for both Type and ID because it is // otherwise ambiguous whether to convert both this and other to int or // convert other to Type. bool operator==(const Type& other) const { return id == other.id; } - bool operator==(const ID& other) const { return id == other; } + bool operator==(const BasicID& other) const { return id == other; } bool operator!=(const Type& other) const { return id != other.id; } - bool operator!=(const ID& other) const { return id != other; } + bool operator!=(const BasicID& other) const { return id != other; } // Order types by some notion of simplicity bool operator<(const Type& other) const; diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 0092c83cccd..99096a58018 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -1433,7 +1433,7 @@ Literal Literal::shuffleV8x16(const Literal& other, return Literal(bytes); } -template static Literal splat(const Literal& val) { +template static Literal splat(const Literal& val) { assert(val.type == Ty); LaneArray lanes; lanes.fill(val); From 8e159d1522155286799c65f290516f4116d7a2bb Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 4 Aug 2020 00:23:19 +0200 Subject: [PATCH 14/50] rename ID -> BasicID in other comments --- src/wasm-type.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index b81c69aaca3..9e03e08b12c 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -56,7 +56,7 @@ class Type { Type() = default; - // ID can be implicitly upgraded to Type + // BasicID can be implicitly upgraded to Type constexpr Type(BasicID id) : id(id){}; // But converting raw uint32_t is more dangerous, so make it explicit @@ -111,7 +111,7 @@ class Type { return static_cast(id); } - // (In)equality must be defined for both Type and ID because it is + // (In)equality must be defined for both Type and BasicID because it is // otherwise ambiguous whether to convert both this and other to int or // convert other to Type. bool operator==(const Type& other) const { return id == other.id; } From f1a25a422f2a21e399af1b8b32d81b2db5f81fff Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 4 Aug 2020 00:23:56 +0200 Subject: [PATCH 15/50] avoid using default cases --- src/wasm/wasm-type.cpp | 83 +++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 50 deletions(-) diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 21c415775d9..9f919314b96 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -57,14 +57,14 @@ size_t hash::operator()(const wasm::TypeDef& typeDef) const { for (auto t : types) { wasm::hash_combine(res, t.getID()); } - break; + return res; } case wasm::TypeDef::SignatureKind: { auto& sig = typeDef.signatureDef.signature; wasm::hash_combine(res, sig.params.getID()); wasm::hash_combine(res, sig.results.getID()); wasm::hash_combine(res, typeDef.isNullable()); - break; + return res; } case wasm::TypeDef::StructKind: { auto& fields = typeDef.structDef.struct_.fields; @@ -74,19 +74,17 @@ size_t hash::operator()(const wasm::TypeDef& typeDef) const { wasm::hash_combine(res, f.mutable_); } wasm::hash_combine(res, typeDef.isNullable()); - break; + return res; } case wasm::TypeDef::ArrayKind: { auto& array = typeDef.arrayDef.array; wasm::hash_combine(res, array.element.type.getID()); wasm::hash_combine(res, array.element.mutable_); wasm::hash_combine(res, typeDef.isNullable()); - break; + return res; } - default: - WASM_UNREACHABLE("unexpected type"); } - return res; + WASM_UNREACHABLE("unexpected kind"); } } // namespace std @@ -201,13 +199,14 @@ bool Type::isRef() const { } else { auto* typeDef = (TypeDef*)id; switch (typeDef->getKind()) { + case TypeDef::TupleKind: + return false; case TypeDef::SignatureKind: case TypeDef::StructKind: case TypeDef::ArrayKind: return true; - default: - return false; } + WASM_UNREACHABLE("unexpected kind"); } } @@ -447,49 +446,39 @@ std::ostream& operator<<(std::ostream& os, Type type) { auto id = type.getID(); switch (id) { case Type::none: - os << "none"; - break; + return os << "none"; case Type::unreachable: - os << "unreachable"; - break; + return os << "unreachable"; case Type::i32: - os << "i32"; - break; + return os << "i32"; case Type::i64: - os << "i64"; - break; + return os << "i64"; case Type::f32: - os << "f32"; - break; + return os << "f32"; case Type::f64: - os << "f64"; - break; + return os << "f64"; case Type::v128: - os << "v128"; - break; + return os << "v128"; case Type::funcref: - os << "funcref"; - break; + return os << "funcref"; case Type::externref: - os << "externref"; - break; + return os << "externref"; case Type::nullref: - os << "nullref"; - break; + return os << "nullref"; case Type::exnref: - os << "exnref"; + return os << "exnref"; + } + auto* typeDef = (TypeDef*)id; + switch (typeDef->getKind()) { + case TypeDef::TupleKind: break; - default: { - assert(id > Type::_last_basic_id); - auto* typeDef = (TypeDef*)id; - if (!typeDef->isTuple()) { - os << "ref "; - } - os << *typeDef; + case TypeDef::SignatureKind: + case TypeDef::StructKind: + case TypeDef::ArrayKind: + os << "ref "; break; - } } - return os; + return os << *typeDef; } std::ostream& operator<<(std::ostream& os, ParamType param) { @@ -556,34 +545,28 @@ std::ostream& operator<<(std::ostream& os, Array array) { std::ostream& operator<<(std::ostream& os, TypeDef typeDef) { switch (typeDef.getKind()) { case TypeDef::TupleKind: { - os << typeDef.tupleDef.tuple; - break; + return os << typeDef.tupleDef.tuple; } case TypeDef::SignatureKind: { if (typeDef.signatureDef.nullable) { os << "null "; } - os << typeDef.signatureDef.signature; - break; + return os << typeDef.signatureDef.signature; } case TypeDef::StructKind: { if (typeDef.structDef.nullable) { os << "null "; } - os << typeDef.structDef.struct_; - break; + return os << typeDef.structDef.struct_; } case TypeDef::ArrayKind: { if (typeDef.arrayDef.nullable) { os << "null "; } - os << typeDef.arrayDef.array; - break; + return os << typeDef.arrayDef.array; } - default: - WASM_UNREACHABLE("invalid type kind"); } - return os; + WASM_UNREACHABLE("unexpected kind"); } } // namespace wasm From 34c2b55ee826424c6da464a2170c10dcbce348ab Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 4 Aug 2020 00:48:16 +0200 Subject: [PATCH 16/50] fix, remove getKind --- src/wasm-type.h | 19 +++++++++---------- src/wasm/wasm-type.cpp | 8 ++++---- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index a4439858d1a..b9fb89f9b20 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -256,7 +256,8 @@ struct TypeDef { TypeDef(Array array, bool nullable) : kind(ArrayKind), arrayDef{array, nullable} {} TypeDef(const TypeDef& other) { - switch (other.getKind()) { + kind = other.kind; + switch (kind) { case TupleKind: new (&tupleDef) auto(other.tupleDef); return; @@ -273,7 +274,7 @@ struct TypeDef { WASM_UNREACHABLE("unexpected kind"); } ~TypeDef() { - switch (getKind()) { + switch (kind) { case TupleKind: { tupleDef.~TupleDef(); return; @@ -294,14 +295,13 @@ struct TypeDef { WASM_UNREACHABLE("unexpected kind"); } - constexpr Kind getKind() const { return kind; } - constexpr bool isTuple() const { return getKind() == TupleKind; } - constexpr bool isSignature() const { return getKind() == SignatureKind; } - constexpr bool isStruct() const { return getKind() == StructKind; } - constexpr bool isArray() const { return getKind() == ArrayKind; } + constexpr bool isTuple() const { return kind == TupleKind; } + constexpr bool isSignature() const { return kind == SignatureKind; } + constexpr bool isStruct() const { return kind == StructKind; } + constexpr bool isArray() const { return kind == ArrayKind; } bool isNullable() const { - switch (getKind()) { + switch (kind) { case TupleKind: return false; case SignatureKind: @@ -315,8 +315,7 @@ struct TypeDef { } bool operator==(const TypeDef& other) const { - auto kind = getKind(); - if (kind != other.getKind()) { + if (kind != other.kind) { return false; } switch (kind) { diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 9f919314b96..c654152246f 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -49,7 +49,7 @@ size_t hash::operator()(const wasm::Signature& sig) const { } size_t hash::operator()(const wasm::TypeDef& typeDef) const { - auto kind = typeDef.getKind(); + auto kind = typeDef.kind; auto res = hash{}(uint32_t(kind)); switch (kind) { case wasm::TypeDef::TupleKind: { @@ -198,7 +198,7 @@ bool Type::isRef() const { return id >= funcref && id <= exnref; } else { auto* typeDef = (TypeDef*)id; - switch (typeDef->getKind()) { + switch (typeDef->kind) { case TypeDef::TupleKind: return false; case TypeDef::SignatureKind: @@ -469,7 +469,7 @@ std::ostream& operator<<(std::ostream& os, Type type) { return os << "exnref"; } auto* typeDef = (TypeDef*)id; - switch (typeDef->getKind()) { + switch (typeDef->kind) { case TypeDef::TupleKind: break; case TypeDef::SignatureKind: @@ -543,7 +543,7 @@ std::ostream& operator<<(std::ostream& os, Array array) { } std::ostream& operator<<(std::ostream& os, TypeDef typeDef) { - switch (typeDef.getKind()) { + switch (typeDef.kind) { case TypeDef::TupleKind: { return os << typeDef.tupleDef.tuple; } From b4ffb988d75a5ff38e2488ad1b3f34d58f91ae0d Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 4 Aug 2020 01:31:22 +0200 Subject: [PATCH 17/50] pass Signature by value --- src/wasm-type.h | 2 +- src/wasm/wasm-type.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index b9fb89f9b20..8de5a01ef50 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -69,7 +69,7 @@ class Type { explicit Type(const Tuple&); // Construct from signature description - explicit Type(const Signature&, bool nullable); + explicit Type(const Signature, bool nullable); // Construct from struct description explicit Type(const Struct&, bool nullable); diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index c654152246f..e64f810d557 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -164,7 +164,7 @@ Type::Type(const Tuple& tuple) { id = canonicalize(TypeDef(tuple)); } -Type::Type(const Signature& signature, bool nullable) { +Type::Type(const Signature signature, bool nullable) { id = canonicalize(TypeDef(signature, nullable)); } From 12183ecd3c5441675ea190e14ce47669e9240d91 Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 4 Aug 2020 03:09:34 +0200 Subject: [PATCH 18/50] packed field types --- src/wasm-type.h | 52 ++++++++++++++++++++++++++++--------- src/wasm/wasm-type.cpp | 58 ++++++++++++++++++++++++++++-------------- 2 files changed, 79 insertions(+), 31 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 8de5a01ef50..783f0a1dba7 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -195,10 +195,31 @@ struct Signature { struct Field { Type type; + enum PackedType : uint32_t { + not_packed, + i8, + i16, + } packedType; // applicable iff type=i32 bool mutable_; - Field(Type type, bool mutable_ = false) : type(type), mutable_(mutable_) {} + + Field(Type type, bool mutable_ = false) + : type(type), packedType(not_packed), mutable_(mutable_) {} + Field(Type::BasicID type, bool mutable_ = false) + : type(type), packedType(not_packed), mutable_(mutable_) {} + Field(PackedType packedType, bool mutable_ = false) + : type(Type::i32), packedType(packedType), mutable_(mutable_) {} + + constexpr bool isPacked() const { + if (packedType != not_packed) { + assert(type.getID() == Type::BasicID::i32 && "unexpected type"); + return true; + } + return false; + } + bool operator==(const Field& other) const { - return type == other.type && mutable_ == other.mutable_; + return type == other.type && packedType == other.packedType && + mutable_ == other.mutable_; } bool operator!=(const Field& other) const { return !(*this == other); } std::string toString() const; @@ -338,14 +359,16 @@ struct TypeDef { std::string toString() const; }; -std::ostream& operator<<(std::ostream& os, Type t); -std::ostream& operator<<(std::ostream& os, ParamType t); -std::ostream& operator<<(std::ostream& os, ResultType t); -std::ostream& operator<<(std::ostream& os, Tuple t); -std::ostream& operator<<(std::ostream& os, Signature t); -std::ostream& operator<<(std::ostream& os, Struct t); -std::ostream& operator<<(std::ostream& os, Array t); -std::ostream& operator<<(std::ostream& os, TypeDef t); +std::ostream& operator<<(std::ostream&, Type); +std::ostream& operator<<(std::ostream&, ParamType); +std::ostream& operator<<(std::ostream&, ResultType); +std::ostream& operator<<(std::ostream&, Tuple); +std::ostream& operator<<(std::ostream&, Signature); +std::ostream& operator<<(std::ostream&, Field::PackedType); +std::ostream& operator<<(std::ostream&, Field); +std::ostream& operator<<(std::ostream&, Struct); +std::ostream& operator<<(std::ostream&, Array); +std::ostream& operator<<(std::ostream&, TypeDef); } // namespace wasm @@ -353,12 +376,17 @@ namespace std { template<> class hash { public: - size_t operator()(const wasm::Type& type) const; + size_t operator()(const wasm::Type&) const; }; template<> class hash { public: - size_t operator()(const wasm::Signature& sig) const; + size_t operator()(const wasm::Signature&) const; +}; + +template<> class hash { +public: + size_t operator()(const wasm::Field&) const; }; template<> class hash { diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index e64f810d557..59eb89e35af 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -48,6 +48,13 @@ size_t hash::operator()(const wasm::Signature& sig) const { return res; } +size_t hash::operator()(const wasm::Field& field) const { + auto res = hash{}(field.type.getID()); + wasm::hash_combine(res, uint32_t(field.packedType)); + wasm::hash_combine(res, field.mutable_); + return res; +} + size_t hash::operator()(const wasm::TypeDef& typeDef) const { auto kind = typeDef.kind; auto res = hash{}(uint32_t(kind)); @@ -70,16 +77,14 @@ size_t hash::operator()(const wasm::TypeDef& typeDef) const { auto& fields = typeDef.structDef.struct_.fields; wasm::hash_combine(res, fields.size()); for (auto f : fields) { - wasm::hash_combine(res, f.type.getID()); - wasm::hash_combine(res, f.mutable_); + wasm::hash_combine(res, f); } wasm::hash_combine(res, typeDef.isNullable()); return res; } case wasm::TypeDef::ArrayKind: { auto& array = typeDef.arrayDef.array; - wasm::hash_combine(res, array.element.type.getID()); - wasm::hash_combine(res, array.element.mutable_); + wasm::hash_combine(res, array.element); wasm::hash_combine(res, typeDef.isNullable()); return res; } @@ -518,28 +523,43 @@ std::ostream& operator<<(std::ostream& os, Signature sig) { return os; } +std::ostream& operator<<(std::ostream& os, Field::PackedType packedType) { + switch (packedType) { + case Field::PackedType::not_packed: + return os << "not_packed"; + case Field::PackedType::i8: + return os << "i8"; + case Field::PackedType::i16: + return os << "i16"; + } + WASM_UNREACHABLE("unexpected type"); +} + +std::ostream& operator<<(std::ostream& os, Field field) { + if (field.mutable_) { + os << "(mut "; + } + if (field.isPacked()) { + os << field.packedType; + } else { + os << field.type; + } + if (field.mutable_) { + os << ")"; + } + return os; +}; + std::ostream& operator<<(std::ostream& os, Struct struct_) { os << "struct"; - auto& fields = struct_.fields; - for (auto f : fields) { - if (f.mutable_) { - os << " (mut " << f.type << ")"; - } else { - os << " " << f.type; - } + for (auto f : struct_.fields) { + os << " " << f; } return os; } std::ostream& operator<<(std::ostream& os, Array array) { - os << "array "; - auto& element = array.element; - if (element.mutable_) { - os << "(mut " << element.type << ")"; - } else { - os << element.type; - } - return os; + return os << "array " << array.element; } std::ostream& operator<<(std::ostream& os, TypeDef typeDef) { From e2f328174b48cba86b864d5d5778f5c2c85d8b7c Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 4 Aug 2020 03:27:12 +0200 Subject: [PATCH 19/50] copy assignment for TupleDef --- src/wasm-type.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/wasm-type.h b/src/wasm-type.h index 783f0a1dba7..c3282f62fbe 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -355,6 +355,35 @@ struct TypeDef { WASM_UNREACHABLE("unexpected kind"); } bool operator!=(const TypeDef& other) const { return !(*this == other); } + TypeDef& operator=(const TypeDef& other) { + if (&other == this) { + return *this; + } + kind = other.kind; + switch (kind) { + case TupleKind: { + tupleDef.~TupleDef(); + new (&tupleDef) auto(other.tupleDef); + return *this; + } + case SignatureKind: { + signatureDef.~SignatureDef(); + new (&signatureDef) auto(other.signatureDef); + return *this; + } + case StructKind: { + structDef.~StructDef(); + new (&structDef) auto(other.structDef); + return *this; + } + case ArrayKind: { + arrayDef.~ArrayDef(); + new (&arrayDef) auto(other.arrayDef); + return *this; + } + } + WASM_UNREACHABLE("unexpected kind"); + } std::string toString() const; }; From fbb0897468279b034a7782da2fa5c920c5934cca Mon Sep 17 00:00:00 2001 From: dcode Date: Wed, 5 Aug 2020 00:15:41 +0200 Subject: [PATCH 20/50] remove unnecessary Field constructor --- src/wasm-type.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index c3282f62fbe..43e989753c9 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -204,8 +204,6 @@ struct Field { Field(Type type, bool mutable_ = false) : type(type), packedType(not_packed), mutable_(mutable_) {} - Field(Type::BasicID type, bool mutable_ = false) - : type(type), packedType(not_packed), mutable_(mutable_) {} Field(PackedType packedType, bool mutable_ = false) : type(Type::i32), packedType(packedType), mutable_(mutable_) {} From cda1056f53c3224e62652625da805516c93d3d6a Mon Sep 17 00:00:00 2001 From: dcode Date: Wed, 5 Aug 2020 00:25:33 +0200 Subject: [PATCH 21/50] add isNullable predicate --- src/wasm-type.h | 1 + src/wasm/wasm-type.cpp | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/src/wasm-type.h b/src/wasm-type.h index 43e989753c9..9261a6a84c2 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -90,6 +90,7 @@ class Type { constexpr bool isNumber() const { return id >= i32 && id <= v128; } bool isTuple() const; bool isRef() const; + bool isNullable() const; private: template bool hasPredicate() { diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 59eb89e35af..0c73741cc71 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -215,6 +215,15 @@ bool Type::isRef() const { } } +bool Type::isNullable() const { + if (id <= _last_basic_id) { + return id >= funcref && id <= exnref; + } else { + auto* typeDef = (TypeDef*)id; + return typeDef->isNullable(); + } +} + size_t Type::size() const { return expand().size(); } const TypeList& Type::expand() const { From 5ba1afc0e0dfb14068a88b5f1e68b31838778283 Mon Sep 17 00:00:00 2001 From: dcode Date: Wed, 5 Aug 2020 00:28:29 +0200 Subject: [PATCH 22/50] use Type instead of BasicID in isPacked check --- src/wasm-type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 9261a6a84c2..a72190bf4e6 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -210,7 +210,7 @@ struct Field { constexpr bool isPacked() const { if (packedType != not_packed) { - assert(type.getID() == Type::BasicID::i32 && "unexpected type"); + assert(type == Type::i32 && "unexpected type"); return true; } return false; From 8bf19066ea31b91eda6401e94abec79dab143d8b Mon Sep 17 00:00:00 2001 From: dcode Date: Wed, 5 Aug 2020 01:04:09 +0200 Subject: [PATCH 23/50] document TypeDefs of lists of a single type --- src/wasm/wasm-type.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 0c73741cc71..3d1907c4e34 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -120,6 +120,12 @@ std::vector> constructedTypes; // Maps from constructed types to the canonical Type ID. std::unordered_map indices = { + // If a Type is constructed from a list of types, the list of types becomes + // implicitly converted to a TypeDef before canonicalizing its id. This is + // also the case if a list of just one type is provided, even though such a + // list of types will be canonicalized to the BasicID of the single type. As + // such, the following entries are solely placeholders to enable the lookup + // of lists of just one type to the BasicID of the single type. {TypeDef(Tuple()), Type::none}, {TypeDef({Type::unreachable}), Type::unreachable}, {TypeDef({Type::i32}), Type::i32}, From eb11e414bbcefb4333cbf693d2c206d4058dcc5a Mon Sep 17 00:00:00 2001 From: dcode Date: Wed, 5 Aug 2020 01:21:29 +0200 Subject: [PATCH 24/50] fix copy assignment as suggested --- src/wasm-type.h | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index a72190bf4e6..d0adea27d59 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -358,28 +358,34 @@ struct TypeDef { if (&other == this) { return *this; } - kind = other.kind; switch (kind) { - case TupleKind: { + case TupleKind: tupleDef.~TupleDef(); + break; + case SignatureKind: + signatureDef.~SignatureDef(); + break; + case StructKind: + structDef.~StructDef(); + break; + case ArrayKind: + arrayDef.~ArrayDef(); + break; + } + kind = other.kind; + switch (kind) { + case TupleKind: new (&tupleDef) auto(other.tupleDef); return *this; - } - case SignatureKind: { - signatureDef.~SignatureDef(); + case SignatureKind: new (&signatureDef) auto(other.signatureDef); return *this; - } - case StructKind: { - structDef.~StructDef(); + case StructKind: new (&structDef) auto(other.structDef); return *this; - } - case ArrayKind: { - arrayDef.~ArrayDef(); + case ArrayKind: new (&arrayDef) auto(other.arrayDef); return *this; - } } WASM_UNREACHABLE("unexpected kind"); } From 3761ed5b1ced99ce6662dea94e33dbca134d36c1 Mon Sep 17 00:00:00 2001 From: dcode Date: Wed, 5 Aug 2020 01:29:27 +0200 Subject: [PATCH 25/50] revert separate printing of Field::PackedType --- src/wasm-type.h | 1 - src/wasm/wasm-type.cpp | 21 ++++++++------------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index d0adea27d59..8ba782b6077 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -398,7 +398,6 @@ std::ostream& operator<<(std::ostream&, ParamType); std::ostream& operator<<(std::ostream&, ResultType); std::ostream& operator<<(std::ostream&, Tuple); std::ostream& operator<<(std::ostream&, Signature); -std::ostream& operator<<(std::ostream&, Field::PackedType); std::ostream& operator<<(std::ostream&, Field); std::ostream& operator<<(std::ostream&, Struct); std::ostream& operator<<(std::ostream&, Array); diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 3d1907c4e34..ab15ddd4fde 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -538,24 +538,19 @@ std::ostream& operator<<(std::ostream& os, Signature sig) { return os; } -std::ostream& operator<<(std::ostream& os, Field::PackedType packedType) { - switch (packedType) { - case Field::PackedType::not_packed: - return os << "not_packed"; - case Field::PackedType::i8: - return os << "i8"; - case Field::PackedType::i16: - return os << "i16"; - } - WASM_UNREACHABLE("unexpected type"); -} - std::ostream& operator<<(std::ostream& os, Field field) { if (field.mutable_) { os << "(mut "; } if (field.isPacked()) { - os << field.packedType; + auto packedType = field.packedType; + if (packedType == Field::PackedType::i8) { + os << "i8"; + } else if (packedType == Field::PackedType::i16) { + os << "i16"; + } else { + WASM_UNREACHABLE("unexpected packed type"); + } } else { os << field.type; } From 7da70129ac7b373011ecaf94c53c603c7e76978c Mon Sep 17 00:00:00 2001 From: dcode Date: Wed, 5 Aug 2020 02:05:20 +0200 Subject: [PATCH 26/50] simplify TypeDef copy assignment --- src/wasm-type.h | 36 ++++-------------------------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 8ba782b6077..b77c0aa4ac5 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -355,39 +355,11 @@ struct TypeDef { } bool operator!=(const TypeDef& other) const { return !(*this == other); } TypeDef& operator=(const TypeDef& other) { - if (&other == this) { - return *this; + if (&other != this) { + (*this).~TypeDef(); + new (this) auto(other); } - switch (kind) { - case TupleKind: - tupleDef.~TupleDef(); - break; - case SignatureKind: - signatureDef.~SignatureDef(); - break; - case StructKind: - structDef.~StructDef(); - break; - case ArrayKind: - arrayDef.~ArrayDef(); - break; - } - kind = other.kind; - switch (kind) { - case TupleKind: - new (&tupleDef) auto(other.tupleDef); - return *this; - case SignatureKind: - new (&signatureDef) auto(other.signatureDef); - return *this; - case StructKind: - new (&structDef) auto(other.structDef); - return *this; - case ArrayKind: - new (&arrayDef) auto(other.arrayDef); - return *this; - } - WASM_UNREACHABLE("unexpected kind"); + return *this; } std::string toString() const; From 06cb1a32428b15d891212b76c13de2bd67999448 Mon Sep 17 00:00:00 2001 From: dcode Date: Sat, 15 Aug 2020 16:33:52 +0200 Subject: [PATCH 27/50] use wasm::hash --- src/wasm/wasm-type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 668b4d9e57d..d7643a96a01 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -49,7 +49,7 @@ size_t hash::operator()(const wasm::Signature& sig) const { } size_t hash::operator()(const wasm::Field& field) const { - auto digest = hash{}(field.type.getID()); + auto digest = wasm::hash(field.type.getID()); wasm::rehash(digest, uint32_t(field.packedType)); wasm::rehash(digest, field.mutable_); return digest; From adb43323f96f8e3f22ab1671ef2babfa38ed6746 Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 18 Aug 2020 03:31:17 +0200 Subject: [PATCH 28/50] drop extra Tuple wrapper, clarify nested Ref concept --- src/wasm-type.h | 93 ++++++++++++++++++++---------------------- src/wasm/wasm-type.cpp | 48 +++++++++++----------- 2 files changed, 69 insertions(+), 72 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 6f8f274578d..5afc64f3485 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -279,50 +279,47 @@ struct Array { }; struct TypeDef { - enum Kind { TupleKind, SignatureKind, StructKind, ArrayKind } kind; - struct TupleDef { - Tuple tuple; - }; - struct SignatureDef { + enum Kind { TupleKind, SignatureRefKind, StructRefKind, ArrayRefKind } kind; + struct SignatureRef { Signature signature; bool nullable; }; - struct StructDef { + struct StructRef { Struct struct_; bool nullable; }; - struct ArrayDef { + struct ArrayRef { Array array; bool nullable; }; union { - TupleDef tupleDef; - SignatureDef signatureDef; - StructDef structDef; - ArrayDef arrayDef; + Tuple tuple; + SignatureRef signatureRef; + StructRef structRef; + ArrayRef arrayRef; }; - TypeDef(Tuple tuple) : kind(TupleKind), tupleDef{tuple} {} + TypeDef(Tuple tuple) : kind(TupleKind), tuple(tuple) {} TypeDef(Signature signature, bool nullable) - : kind(SignatureKind), signatureDef{signature, nullable} {} + : kind(SignatureRefKind), signatureRef{signature, nullable} {} TypeDef(Struct struct_, bool nullable) - : kind(StructKind), structDef{struct_, nullable} {} + : kind(StructRefKind), structRef{struct_, nullable} {} TypeDef(Array array, bool nullable) - : kind(ArrayKind), arrayDef{array, nullable} {} + : kind(ArrayRefKind), arrayRef{array, nullable} {} TypeDef(const TypeDef& other) { kind = other.kind; switch (kind) { case TupleKind: - new (&tupleDef) auto(other.tupleDef); + new (&tuple) auto(other.tuple); return; - case SignatureKind: - new (&signatureDef) auto(other.signatureDef); + case SignatureRefKind: + new (&signatureRef) auto(other.signatureRef); return; - case StructKind: - new (&structDef) auto(other.structDef); + case StructRefKind: + new (&structRef) auto(other.structRef); return; - case ArrayKind: - new (&arrayDef) auto(other.arrayDef); + case ArrayRefKind: + new (&arrayRef) auto(other.arrayRef); return; } WASM_UNREACHABLE("unexpected kind"); @@ -330,19 +327,19 @@ struct TypeDef { ~TypeDef() { switch (kind) { case TupleKind: { - tupleDef.~TupleDef(); + tuple.~Tuple(); return; } - case SignatureKind: { - signatureDef.~SignatureDef(); + case SignatureRefKind: { + signatureRef.~SignatureRef(); return; } - case StructKind: { - structDef.~StructDef(); + case StructRefKind: { + structRef.~StructRef(); return; } - case ArrayKind: { - arrayDef.~ArrayDef(); + case ArrayRefKind: { + arrayRef.~ArrayRef(); return; } } @@ -350,20 +347,20 @@ struct TypeDef { } constexpr bool isTuple() const { return kind == TupleKind; } - constexpr bool isSignature() const { return kind == SignatureKind; } - constexpr bool isStruct() const { return kind == StructKind; } - constexpr bool isArray() const { return kind == ArrayKind; } + constexpr bool isSignatureRef() const { return kind == SignatureRefKind; } + constexpr bool isStructRef() const { return kind == StructRefKind; } + constexpr bool isArrayRef() const { return kind == ArrayRefKind; } bool isNullable() const { switch (kind) { case TupleKind: return false; - case SignatureKind: - return signatureDef.nullable; - case StructKind: - return structDef.nullable; - case ArrayKind: - return arrayDef.nullable; + case SignatureRefKind: + return signatureRef.nullable; + case StructRefKind: + return structRef.nullable; + case ArrayRefKind: + return arrayRef.nullable; } WASM_UNREACHABLE("unexpected kind"); } @@ -374,16 +371,16 @@ struct TypeDef { } switch (kind) { case TupleKind: - return tupleDef.tuple == other.tupleDef.tuple; - case SignatureKind: - return signatureDef.nullable == other.signatureDef.nullable && - signatureDef.signature == other.signatureDef.signature; - case StructKind: - return structDef.nullable == other.structDef.nullable && - structDef.struct_ == other.structDef.struct_; - case ArrayKind: - return arrayDef.nullable == other.arrayDef.nullable && - arrayDef.array == other.arrayDef.array; + return tuple == other.tuple; + case SignatureRefKind: + return signatureRef.nullable == other.signatureRef.nullable && + signatureRef.signature == other.signatureRef.signature; + case StructRefKind: + return structRef.nullable == other.structRef.nullable && + structRef.struct_ == other.structRef.struct_; + case ArrayRefKind: + return arrayRef.nullable == other.arrayRef.nullable && + arrayRef.array == other.arrayRef.array; } WASM_UNREACHABLE("unexpected kind"); } diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index c72d4e5ff43..0cf5035d35c 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -60,21 +60,21 @@ size_t hash::operator()(const wasm::TypeDef& typeDef) const { auto digest = wasm::hash(uint32_t(kind)); switch (kind) { case wasm::TypeDef::TupleKind: { - auto& types = typeDef.tupleDef.tuple.types; + auto& types = typeDef.tuple.types; for (auto t : types) { wasm::rehash(digest, t.getID()); } return digest; } - case wasm::TypeDef::SignatureKind: { - auto& sig = typeDef.signatureDef.signature; + case wasm::TypeDef::SignatureRefKind: { + auto& sig = typeDef.signatureRef.signature; wasm::rehash(digest, sig.params.getID()); wasm::rehash(digest, sig.results.getID()); wasm::rehash(digest, typeDef.isNullable()); return digest; } - case wasm::TypeDef::StructKind: { - auto& fields = typeDef.structDef.struct_.fields; + case wasm::TypeDef::StructRefKind: { + auto& fields = typeDef.structRef.struct_.fields; wasm::rehash(digest, fields.size()); for (auto f : fields) { wasm::rehash(digest, f); @@ -82,8 +82,8 @@ size_t hash::operator()(const wasm::TypeDef& typeDef) const { wasm::rehash(digest, typeDef.isNullable()); return digest; } - case wasm::TypeDef::ArrayKind: { - auto& array = typeDef.arrayDef.array; + case wasm::TypeDef::ArrayRefKind: { + auto& array = typeDef.arrayRef.array; wasm::rehash(digest, array.element); wasm::rehash(digest, typeDef.isNullable()); return digest; @@ -212,9 +212,9 @@ bool Type::isRef() const { switch (typeDef->kind) { case TypeDef::TupleKind: return false; - case TypeDef::SignatureKind: - case TypeDef::StructKind: - case TypeDef::ArrayKind: + case TypeDef::SignatureRefKind: + case TypeDef::StructRefKind: + case TypeDef::ArrayRefKind: return true; } WASM_UNREACHABLE("unexpected kind"); @@ -238,7 +238,7 @@ const TypeList& Type::expand() const { } else { auto* typeDef = (TypeDef*)id; assert(typeDef->isTuple() && "can only expand tuple types"); - return typeDef->tupleDef.tuple.types; + return typeDef->tuple.types; } } @@ -505,9 +505,9 @@ std::ostream& operator<<(std::ostream& os, Type type) { switch (typeDef->kind) { case TypeDef::TupleKind: break; - case TypeDef::SignatureKind: - case TypeDef::StructKind: - case TypeDef::ArrayKind: + case TypeDef::SignatureRefKind: + case TypeDef::StructRefKind: + case TypeDef::ArrayRefKind: os << "ref "; break; } @@ -590,25 +590,25 @@ std::ostream& operator<<(std::ostream& os, Array array) { std::ostream& operator<<(std::ostream& os, TypeDef typeDef) { switch (typeDef.kind) { case TypeDef::TupleKind: { - return os << typeDef.tupleDef.tuple; + return os << typeDef.tuple; } - case TypeDef::SignatureKind: { - if (typeDef.signatureDef.nullable) { + case TypeDef::SignatureRefKind: { + if (typeDef.signatureRef.nullable) { os << "null "; } - return os << typeDef.signatureDef.signature; + return os << typeDef.signatureRef.signature; } - case TypeDef::StructKind: { - if (typeDef.structDef.nullable) { + case TypeDef::StructRefKind: { + if (typeDef.structRef.nullable) { os << "null "; } - return os << typeDef.structDef.struct_; + return os << typeDef.structRef.struct_; } - case TypeDef::ArrayKind: { - if (typeDef.arrayDef.nullable) { + case TypeDef::ArrayRefKind: { + if (typeDef.arrayRef.nullable) { os << "null "; } - return os << typeDef.arrayDef.array; + return os << typeDef.arrayRef.array; } } WASM_UNREACHABLE("unexpected kind"); From 7e46013e4a9e2cc7408cf1db672475f00da307ff Mon Sep 17 00:00:00 2001 From: Daniel Wirtz Date: Tue, 18 Aug 2020 09:26:02 +0200 Subject: [PATCH 29/50] Update src/wasm-type.h Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com> --- src/wasm-type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 5afc64f3485..43020764d48 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -70,7 +70,7 @@ class Type { // But converting raw uint32_t is more dangerous, so make it explicit explicit Type(uint64_t id) : id(id){}; - // Construct tuple from lists of elementary types + // Construct tuple from a list of single types Type(std::initializer_list); // Construct from tuple description From 8aa4b5de903c92a3696fa3c7d8adc5ad36780dc2 Mon Sep 17 00:00:00 2001 From: Daniel Wirtz Date: Tue, 18 Aug 2020 09:27:13 +0200 Subject: [PATCH 30/50] Update src/wasm-type.h Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com> --- src/wasm-type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 43020764d48..06d0337189e 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -121,7 +121,7 @@ class Type { constexpr bool isNumber() const { return id >= i32 && id <= v128; } bool isTuple() const; bool isSingle() const { - return id >= i32 && (id <= _last_basic_id || !isTuple()); + return isConcrete() && !isTuple(); } bool isRef() const; bool isNullable() const; From 4ed19aa052b399f85180239f00dcc130d097d16b Mon Sep 17 00:00:00 2001 From: Daniel Wirtz Date: Tue, 18 Aug 2020 09:27:42 +0200 Subject: [PATCH 31/50] Update src/wasm-type.h Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com> --- src/wasm-type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 06d0337189e..764598645ab 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -207,7 +207,7 @@ struct ResultType { struct Tuple { TypeList types; - Tuple() : types({}) {} + Tuple() : types() {} Tuple(std::initializer_list types) : types(types) {} Tuple(TypeList types) : types(types) {} bool operator==(const Tuple& other) const { return types == other.types; } From fc05734f2fcc2e3bf99f1334f352404ad5503a0c Mon Sep 17 00:00:00 2001 From: Daniel Wirtz Date: Tue, 18 Aug 2020 09:28:48 +0200 Subject: [PATCH 32/50] Update src/wasm/wasm-type.cpp Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com> --- src/wasm/wasm-type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 0cf5035d35c..b72a6c532f5 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -161,7 +161,7 @@ Type::Type(const Tuple& tuple) { auto& types = tuple.types; #ifndef NDEBUG for (Type t : types) { - assert(!t.isTuple() && t.isConcrete()); + assert(t.isSingle()); } #endif if (types.size() == 0) { From 94e2f615e704048d302b7e14a23df830296f5a30 Mon Sep 17 00:00:00 2001 From: Daniel Wirtz Date: Tue, 18 Aug 2020 09:29:28 +0200 Subject: [PATCH 33/50] Update src/wasm/wasm-type.cpp Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com> --- src/wasm/wasm-type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index b72a6c532f5..7524c6dcf35 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -182,7 +182,7 @@ Type::Type(const Signature signature, bool nullable) { Type::Type(const Struct& struct_, bool nullable) { #ifndef NDEBUG for (Field f : struct_.fields) { - assert(f.type.isSingle() && f.type.isConcrete()); + assert(f.type.isSingle()); } #endif id = canonicalize(TypeDef(struct_, nullable)); From 959aba12e1519eff3e7df34f093ba3ea48b5a321 Mon Sep 17 00:00:00 2001 From: Daniel Wirtz Date: Tue, 18 Aug 2020 09:30:04 +0200 Subject: [PATCH 34/50] Update src/wasm/wasm-type.cpp Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com> --- src/wasm/wasm-type.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 7524c6dcf35..56dae719ab1 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -189,9 +189,7 @@ Type::Type(const Struct& struct_, bool nullable) { } Type::Type(const Array& array, bool nullable) { -#ifndef NDEBUG - assert(array.element.type.isSingle() && array.element.type.isConcrete()); -#endif + assert(array.element.type.isSingle()); id = canonicalize(TypeDef(array, nullable)); } From e7eeb50e0b18e38e163430715efbe75f6eb194a2 Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 18 Aug 2020 09:45:55 +0200 Subject: [PATCH 35/50] add getDef for readability, remove PackedType storage type --- src/wasm-type.h | 11 +++++++---- src/wasm/wasm-type.cpp | 23 ++++++++++------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 764598645ab..7c1f4dcc30e 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -32,6 +32,7 @@ namespace wasm { class Type; +struct TypeDef; struct Tuple; struct Signature; struct Struct; @@ -120,9 +121,7 @@ class Type { constexpr bool isVector() const { return id == v128; }; constexpr bool isNumber() const { return id >= i32 && id <= v128; } bool isTuple() const; - bool isSingle() const { - return isConcrete() && !isTuple(); - } + bool isSingle() const { return isConcrete() && !isTuple(); } bool isRef() const; bool isNullable() const; @@ -145,6 +144,10 @@ class Type { assert(isBasic() && "Basic type expected"); return static_cast(id); } + constexpr TypeDef* getDef() const { + assert(isCompound() && "Compound type expected"); + return (TypeDef*)id; + } // (In)equality must be defined for both Type and BasicID because it is // otherwise ambiguous whether to convert both this and other to int or @@ -230,7 +233,7 @@ struct Signature { struct Field { Type type; - enum PackedType : uint32_t { + enum PackedType { not_packed, i8, i16, diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 56dae719ab1..c7076dd3d38 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -194,20 +194,18 @@ Type::Type(const Array& array, bool nullable) { } bool Type::isTuple() const { - if (id <= _last_basic_id) { + if (isBasic()) { return false; } else { - auto* typeDef = (TypeDef*)id; - return typeDef->isTuple(); + return getDef()->isTuple(); } } bool Type::isRef() const { - if (id <= _last_basic_id) { + if (isBasic()) { return id >= funcref && id <= exnref; } else { - auto* typeDef = (TypeDef*)id; - switch (typeDef->kind) { + switch (getDef()->kind) { case TypeDef::TupleKind: return false; case TypeDef::SignatureRefKind: @@ -220,21 +218,20 @@ bool Type::isRef() const { } bool Type::isNullable() const { - if (id <= _last_basic_id) { + if (isBasic()) { return id >= funcref && id <= exnref; } else { - auto* typeDef = (TypeDef*)id; - return typeDef->isNullable(); + return getDef()->isNullable(); } } size_t Type::size() const { return expand().size(); } const TypeList& Type::expand() const { - if (id <= Type::_last_basic_id) { + if (isBasic()) { return basicTuples[id]; } else { - auto* typeDef = (TypeDef*)id; + auto* typeDef = getDef(); assert(typeDef->isTuple() && "can only expand tuple types"); return typeDef->tuple.types; } @@ -463,7 +460,7 @@ bool Signature::operator<(const Signature& other) const { std::ostream& operator<<(std::ostream& os, Type type) { if (type.isBasic()) { - switch (static_cast(type.getID())) { + switch (type.getBasic()) { case Type::none: os << "none"; break; @@ -499,7 +496,7 @@ std::ostream& operator<<(std::ostream& os, Type type) { break; } } else { - auto* typeDef = (TypeDef*)type.getID(); + auto* typeDef = type.getDef(); switch (typeDef->kind) { case TypeDef::TupleKind: break; From b72890c8c39eb6ea1bb62cc0ff088a5315e7831e Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 18 Aug 2020 09:48:29 +0200 Subject: [PATCH 36/50] fix --- src/wasm-type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 7c1f4dcc30e..8147af5177f 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -144,7 +144,7 @@ class Type { assert(isBasic() && "Basic type expected"); return static_cast(id); } - constexpr TypeDef* getDef() const { + TypeDef* getDef() const { assert(isCompound() && "Compound type expected"); return (TypeDef*)id; } From a9affcf477f75504226baf941a084fea53632df8 Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 18 Aug 2020 09:53:21 +0200 Subject: [PATCH 37/50] keep getDef internal as suggested --- src/wasm-type.h | 4 ---- src/wasm/wasm-type.cpp | 12 +++++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 8147af5177f..9b4f857c9e0 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -144,10 +144,6 @@ class Type { assert(isBasic() && "Basic type expected"); return static_cast(id); } - TypeDef* getDef() const { - assert(isCompound() && "Compound type expected"); - return (TypeDef*)id; - } // (In)equality must be defined for both Type and BasicID because it is // otherwise ambiguous whether to convert both this and other to int or diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index c7076dd3d38..cb427353312 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -155,6 +155,8 @@ static uintptr_t canonicalize(const TypeDef& typeDef) { return id; } +static TypeDef* getDef(Type type) { return (TypeDef*)type.getID(); } + Type::Type(std::initializer_list types) : Type(Tuple(types)) {} Type::Type(const Tuple& tuple) { @@ -197,7 +199,7 @@ bool Type::isTuple() const { if (isBasic()) { return false; } else { - return getDef()->isTuple(); + return getDef(*this)->isTuple(); } } @@ -205,7 +207,7 @@ bool Type::isRef() const { if (isBasic()) { return id >= funcref && id <= exnref; } else { - switch (getDef()->kind) { + switch (getDef(*this)->kind) { case TypeDef::TupleKind: return false; case TypeDef::SignatureRefKind: @@ -221,7 +223,7 @@ bool Type::isNullable() const { if (isBasic()) { return id >= funcref && id <= exnref; } else { - return getDef()->isNullable(); + return getDef(*this)->isNullable(); } } @@ -231,7 +233,7 @@ const TypeList& Type::expand() const { if (isBasic()) { return basicTuples[id]; } else { - auto* typeDef = getDef(); + auto* typeDef = getDef(*this); assert(typeDef->isTuple() && "can only expand tuple types"); return typeDef->tuple.types; } @@ -496,7 +498,7 @@ std::ostream& operator<<(std::ostream& os, Type type) { break; } } else { - auto* typeDef = type.getDef(); + auto* typeDef = getDef(type); switch (typeDef->kind) { case TypeDef::TupleKind: break; From 40f3a1a91532eddff5ef9c637523cf999a83f016 Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 18 Aug 2020 10:10:40 +0200 Subject: [PATCH 38/50] move TypeDef definition to wasm-type.cpp --- src/wasm-type.h | 118 --------------------------------------- src/wasm/wasm-type.cpp | 122 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 118 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 9b4f857c9e0..56f5bc8f5c2 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -277,124 +277,6 @@ struct Array { std::string toString() const; }; -struct TypeDef { - enum Kind { TupleKind, SignatureRefKind, StructRefKind, ArrayRefKind } kind; - struct SignatureRef { - Signature signature; - bool nullable; - }; - struct StructRef { - Struct struct_; - bool nullable; - }; - struct ArrayRef { - Array array; - bool nullable; - }; - union { - Tuple tuple; - SignatureRef signatureRef; - StructRef structRef; - ArrayRef arrayRef; - }; - - TypeDef(Tuple tuple) : kind(TupleKind), tuple(tuple) {} - TypeDef(Signature signature, bool nullable) - : kind(SignatureRefKind), signatureRef{signature, nullable} {} - TypeDef(Struct struct_, bool nullable) - : kind(StructRefKind), structRef{struct_, nullable} {} - TypeDef(Array array, bool nullable) - : kind(ArrayRefKind), arrayRef{array, nullable} {} - TypeDef(const TypeDef& other) { - kind = other.kind; - switch (kind) { - case TupleKind: - new (&tuple) auto(other.tuple); - return; - case SignatureRefKind: - new (&signatureRef) auto(other.signatureRef); - return; - case StructRefKind: - new (&structRef) auto(other.structRef); - return; - case ArrayRefKind: - new (&arrayRef) auto(other.arrayRef); - return; - } - WASM_UNREACHABLE("unexpected kind"); - } - ~TypeDef() { - switch (kind) { - case TupleKind: { - tuple.~Tuple(); - return; - } - case SignatureRefKind: { - signatureRef.~SignatureRef(); - return; - } - case StructRefKind: { - structRef.~StructRef(); - return; - } - case ArrayRefKind: { - arrayRef.~ArrayRef(); - return; - } - } - WASM_UNREACHABLE("unexpected kind"); - } - - constexpr bool isTuple() const { return kind == TupleKind; } - constexpr bool isSignatureRef() const { return kind == SignatureRefKind; } - constexpr bool isStructRef() const { return kind == StructRefKind; } - constexpr bool isArrayRef() const { return kind == ArrayRefKind; } - - bool isNullable() const { - switch (kind) { - case TupleKind: - return false; - case SignatureRefKind: - return signatureRef.nullable; - case StructRefKind: - return structRef.nullable; - case ArrayRefKind: - return arrayRef.nullable; - } - WASM_UNREACHABLE("unexpected kind"); - } - - bool operator==(const TypeDef& other) const { - if (kind != other.kind) { - return false; - } - switch (kind) { - case TupleKind: - return tuple == other.tuple; - case SignatureRefKind: - return signatureRef.nullable == other.signatureRef.nullable && - signatureRef.signature == other.signatureRef.signature; - case StructRefKind: - return structRef.nullable == other.structRef.nullable && - structRef.struct_ == other.structRef.struct_; - case ArrayRefKind: - return arrayRef.nullable == other.arrayRef.nullable && - arrayRef.array == other.arrayRef.array; - } - WASM_UNREACHABLE("unexpected kind"); - } - bool operator!=(const TypeDef& other) const { return !(*this == other); } - TypeDef& operator=(const TypeDef& other) { - if (&other != this) { - (*this).~TypeDef(); - new (this) auto(other); - } - return *this; - } - - std::string toString() const; -}; - std::ostream& operator<<(std::ostream&, Type); std::ostream& operator<<(std::ostream&, ParamType); std::ostream& operator<<(std::ostream&, ResultType); diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index cb427353312..363cb42bb55 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -25,6 +25,128 @@ #include "wasm-features.h" #include "wasm-type.h" +namespace wasm { + +struct TypeDef { + enum Kind { TupleKind, SignatureRefKind, StructRefKind, ArrayRefKind } kind; + struct SignatureRef { + Signature signature; + bool nullable; + }; + struct StructRef { + Struct struct_; + bool nullable; + }; + struct ArrayRef { + Array array; + bool nullable; + }; + union { + Tuple tuple; + SignatureRef signatureRef; + StructRef structRef; + ArrayRef arrayRef; + }; + + TypeDef(Tuple tuple) : kind(TupleKind), tuple(tuple) {} + TypeDef(Signature signature, bool nullable) + : kind(SignatureRefKind), signatureRef{signature, nullable} {} + TypeDef(Struct struct_, bool nullable) + : kind(StructRefKind), structRef{struct_, nullable} {} + TypeDef(Array array, bool nullable) + : kind(ArrayRefKind), arrayRef{array, nullable} {} + TypeDef(const TypeDef& other) { + kind = other.kind; + switch (kind) { + case TupleKind: + new (&tuple) auto(other.tuple); + return; + case SignatureRefKind: + new (&signatureRef) auto(other.signatureRef); + return; + case StructRefKind: + new (&structRef) auto(other.structRef); + return; + case ArrayRefKind: + new (&arrayRef) auto(other.arrayRef); + return; + } + WASM_UNREACHABLE("unexpected kind"); + } + ~TypeDef() { + switch (kind) { + case TupleKind: { + tuple.~Tuple(); + return; + } + case SignatureRefKind: { + signatureRef.~SignatureRef(); + return; + } + case StructRefKind: { + structRef.~StructRef(); + return; + } + case ArrayRefKind: { + arrayRef.~ArrayRef(); + return; + } + } + WASM_UNREACHABLE("unexpected kind"); + } + + constexpr bool isTuple() const { return kind == TupleKind; } + constexpr bool isSignatureRef() const { return kind == SignatureRefKind; } + constexpr bool isStructRef() const { return kind == StructRefKind; } + constexpr bool isArrayRef() const { return kind == ArrayRefKind; } + + bool isNullable() const { + switch (kind) { + case TupleKind: + return false; + case SignatureRefKind: + return signatureRef.nullable; + case StructRefKind: + return structRef.nullable; + case ArrayRefKind: + return arrayRef.nullable; + } + WASM_UNREACHABLE("unexpected kind"); + } + + bool operator==(const TypeDef& other) const { + if (kind != other.kind) { + return false; + } + switch (kind) { + case TupleKind: + return tuple == other.tuple; + case SignatureRefKind: + return signatureRef.nullable == other.signatureRef.nullable && + signatureRef.signature == other.signatureRef.signature; + case StructRefKind: + return structRef.nullable == other.structRef.nullable && + structRef.struct_ == other.structRef.struct_; + case ArrayRefKind: + return arrayRef.nullable == other.arrayRef.nullable && + arrayRef.array == other.arrayRef.array; + } + WASM_UNREACHABLE("unexpected kind"); + } + bool operator!=(const TypeDef& other) const { return !(*this == other); } + TypeDef& operator=(const TypeDef& other) { + if (&other != this) { + (*this).~TypeDef(); + new (this) auto(other); + } + return *this; + } + + std::string toString() const; +}; + +} // namespace wasm + namespace std { template<> class hash> { From accd33d2473b32594141f36d2dd04bcf032ffe38 Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 18 Aug 2020 14:50:48 +0200 Subject: [PATCH 39/50] initial test --- src/wasm/wasm-type.cpp | 23 +++----- test/example/typedef.cpp | 112 +++++++++++++++++++++++++++++++++++++++ test/example/typedef.txt | 18 +++++++ 3 files changed, 136 insertions(+), 17 deletions(-) create mode 100644 test/example/typedef.cpp create mode 100644 test/example/typedef.txt diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 363cb42bb55..37d6d8e113e 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -620,17 +620,7 @@ std::ostream& operator<<(std::ostream& os, Type type) { break; } } else { - auto* typeDef = getDef(type); - switch (typeDef->kind) { - case TypeDef::TupleKind: - break; - case TypeDef::SignatureRefKind: - case TypeDef::StructRefKind: - case TypeDef::ArrayRefKind: - os << "ref "; - break; - } - os << *typeDef; + os << "(" << *getDef(type) << ")"; } return os; } @@ -644,7 +634,6 @@ std::ostream& operator<<(std::ostream& os, ResultType param) { } std::ostream& operator<<(std::ostream& os, Tuple tuple) { - os << "("; auto& types = tuple.types; auto size = types.size(); if (size) { @@ -653,21 +642,18 @@ std::ostream& operator<<(std::ostream& os, Tuple tuple) { os << " " << types[i]; } } - os << ")"; return os; } std::ostream& operator<<(std::ostream& os, Signature sig) { os << "func"; if (sig.params.getID() != Type::none) { - os << " ("; + os << " "; printPrefixedTypes(os, "param", sig.params); - os << ")"; } if (sig.results.getID() != Type::none) { - os << " ("; + os << " "; printPrefixedTypes(os, "result", sig.results); - os << ")"; } return os; } @@ -712,18 +698,21 @@ std::ostream& operator<<(std::ostream& os, TypeDef typeDef) { return os << typeDef.tuple; } case TypeDef::SignatureRefKind: { + os << "ref "; if (typeDef.signatureRef.nullable) { os << "null "; } return os << typeDef.signatureRef.signature; } case TypeDef::StructRefKind: { + os << "ref "; if (typeDef.structRef.nullable) { os << "null "; } return os << typeDef.structRef.struct_; } case TypeDef::ArrayRefKind: { + os << "ref "; if (typeDef.arrayRef.nullable) { os << "null "; } diff --git a/test/example/typedef.cpp b/test/example/typedef.cpp new file mode 100644 index 00000000000..a43b513ea8a --- /dev/null +++ b/test/example/typedef.cpp @@ -0,0 +1,112 @@ +#include +#include + +#include "wasm-type.h" + +using namespace wasm; + +void test_compound() { + { + Signature signature(Type::i32, Type::none); + assert(Type(signature, false).getID() == Type(signature, false).getID()); + assert(Type(signature, false).getID() != Type(signature, true).getID()); + + Signature sameSignature(Type::i32, Type::none); + assert(Type(signature, false).getID() == + Type(sameSignature, false).getID()); + + Signature otherSignature(Type::f64, Type::none); + assert(Type(signature, false).getID() != + Type(otherSignature, false).getID()); + } + { + Struct struct_({}); + assert(Type(struct_, false).getID() == Type(struct_, false).getID()); + assert(Type(struct_, false).getID() != Type(struct_, true).getID()); + + Struct sameStruct({}); + assert(Type(struct_, false).getID() == Type(sameStruct, false).getID()); + + Struct otherStruct({{Type::i32, false}}); + assert(Type(struct_, false).getID() != Type(otherStruct, false).getID()); + } + { + Array array({Type::i32, false}); + assert(Type(array, false).getID() == Type(array, false).getID()); + assert(Type(array, false).getID() != Type(array, true).getID()); + + Array sameArray({Type::i32, false}); + assert(Type(array, false).getID() == Type(sameArray, false).getID()); + + Array otherArray({Type::f64, true}); + assert(Type(array, false).getID() != Type(otherArray, false).getID()); + } + { + Tuple singleTuple({Type::i32}); + assert(Type(singleTuple).getID() == Type::i32); + + Tuple tuple({Type::i32, Type::f64}); + assert(Type(tuple).getID() == Type(tuple).getID()); + + Tuple sameTuple({Type::i32, Type::f64}); + assert(Type(tuple).getID() == Type(sameTuple).getID()); + + Tuple otherTuple({Type::f64, Type::externref}); + assert(Type(tuple).getID() != Type(otherTuple).getID()); + } +} + +void test_printing() { + { + std::cout << "# Signature\n"; + Signature signature(Type::i32, Type::none); + std::cout << signature << "\n"; + std::cout << Type(signature, false) << "\n"; + std::cout << Type(signature, true) << "\n"; + } + { + std::cout << "# Struct\n"; + Struct struct_({ + {Type::i32, false}, + {Type::i64, false}, + {Type::f32, true}, + {Type::f64, true}, + {Type::externref, false}, + }); + std::cout << struct_ << "\n"; + std::cout << Type(struct_, false) << "\n"; + std::cout << Type(struct_, true) << "\n"; + } + { + std::cout << "# Array\n"; + Array array({Type::i32, false}); + std::cout << array << "\n"; + std::cout << Type(array, false) << "\n"; + std::cout << Type(array, true) << "\n"; + Array arrayMut({Type::externref, true}); + std::cout << arrayMut << "\n"; + std::cout << Type(arrayMut, false) << "\n"; + std::cout << Type(arrayMut, true) << "\n"; + } + { + std::cout << "# Tuple\n"; + Tuple tuple({ + Type::i32, + Type::f64, + Type::externref, + }); + std::cout << tuple << "\n"; + std::cout << Type(tuple) << "\n"; + } + // FIXME: Can't expand a single compound `params` type, see + // https://github.com/WebAssembly/binaryen/pull/3012#discussion_r471842763 + // { + // Signature signature(Type(Array({Type::i32, false}), false), Type::none); + // std::cout << signature << "\n"; + // } +} + +int main() { + test_compound(); + test_printing(); +} diff --git a/test/example/typedef.txt b/test/example/typedef.txt new file mode 100644 index 00000000000..9cb5f6e08dd --- /dev/null +++ b/test/example/typedef.txt @@ -0,0 +1,18 @@ +# Signature +func (param i32) +(ref func (param i32)) +(ref null func (param i32)) +# Struct +struct i32 i64 (mut f32) (mut f64) externref +(ref struct i32 i64 (mut f32) (mut f64) externref) +(ref null struct i32 i64 (mut f32) (mut f64) externref) +# Array +array i32 +(ref array i32) +(ref null array i32) +array (mut externref) +(ref array (mut externref)) +(ref null array (mut externref)) +# Tuple +i32 f64 externref +(i32 f64 externref) From d92e41661177534dfe3a50c4c120a939396439ab Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 18 Aug 2020 15:39:44 +0200 Subject: [PATCH 40/50] parens it is --- src/wasm/wasm-type.cpp | 35 ++++++++++++++++++++--------------- test/example/typedef.txt | 26 +++++++++++++------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 37d6d8e113e..dfeaca9f729 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -620,7 +620,7 @@ std::ostream& operator<<(std::ostream& os, Type type) { break; } } else { - os << "(" << *getDef(type) << ")"; + os << *getDef(type); } return os; } @@ -636,17 +636,18 @@ std::ostream& operator<<(std::ostream& os, ResultType param) { std::ostream& operator<<(std::ostream& os, Tuple tuple) { auto& types = tuple.types; auto size = types.size(); + os << "("; if (size) { os << types[0]; for (size_t i = 1; i < size; ++i) { os << " " << types[i]; } } - return os; + return os << ")"; } std::ostream& operator<<(std::ostream& os, Signature sig) { - os << "func"; + os << "(func"; if (sig.params.getID() != Type::none) { os << " "; printPrefixedTypes(os, "param", sig.params); @@ -655,7 +656,7 @@ std::ostream& operator<<(std::ostream& os, Signature sig) { os << " "; printPrefixedTypes(os, "result", sig.results); } - return os; + return os << ")"; } std::ostream& operator<<(std::ostream& os, Field field) { @@ -681,15 +682,19 @@ std::ostream& operator<<(std::ostream& os, Field field) { }; std::ostream& operator<<(std::ostream& os, Struct struct_) { - os << "struct"; - for (auto f : struct_.fields) { - os << " " << f; + os << "(struct"; + if (struct_.fields.size()) { + os << " (field"; + for (auto f : struct_.fields) { + os << " " << f; + } + os << ")"; } - return os; + return os << ")"; } std::ostream& operator<<(std::ostream& os, Array array) { - return os << "array " << array.element; + return os << "(array " << array.element << ")"; } std::ostream& operator<<(std::ostream& os, TypeDef typeDef) { @@ -698,25 +703,25 @@ std::ostream& operator<<(std::ostream& os, TypeDef typeDef) { return os << typeDef.tuple; } case TypeDef::SignatureRefKind: { - os << "ref "; + os << "(ref "; if (typeDef.signatureRef.nullable) { os << "null "; } - return os << typeDef.signatureRef.signature; + return os << typeDef.signatureRef.signature << ")"; } case TypeDef::StructRefKind: { - os << "ref "; + os << "(ref "; if (typeDef.structRef.nullable) { os << "null "; } - return os << typeDef.structRef.struct_; + return os << typeDef.structRef.struct_ << ")"; } case TypeDef::ArrayRefKind: { - os << "ref "; + os << "(ref "; if (typeDef.arrayRef.nullable) { os << "null "; } - return os << typeDef.arrayRef.array; + return os << typeDef.arrayRef.array << ")"; } } WASM_UNREACHABLE("unexpected kind"); diff --git a/test/example/typedef.txt b/test/example/typedef.txt index 9cb5f6e08dd..cc3c3caa53d 100644 --- a/test/example/typedef.txt +++ b/test/example/typedef.txt @@ -1,18 +1,18 @@ # Signature -func (param i32) -(ref func (param i32)) -(ref null func (param i32)) +(func (param i32)) +(ref (func (param i32))) +(ref null (func (param i32))) # Struct -struct i32 i64 (mut f32) (mut f64) externref -(ref struct i32 i64 (mut f32) (mut f64) externref) -(ref null struct i32 i64 (mut f32) (mut f64) externref) +(struct (field i32 i64 (mut f32) (mut f64) externref)) +(ref (struct (field i32 i64 (mut f32) (mut f64) externref))) +(ref null (struct (field i32 i64 (mut f32) (mut f64) externref))) # Array -array i32 -(ref array i32) -(ref null array i32) -array (mut externref) -(ref array (mut externref)) -(ref null array (mut externref)) +(array i32) +(ref (array i32)) +(ref null (array i32)) +(array (mut externref)) +(ref (array (mut externref))) +(ref null (array (mut externref))) # Tuple -i32 f64 externref +(i32 f64 externref) (i32 f64 externref) From 9517da1ce7f9f5dc4bac419b3b1e63be6b1b49b4 Mon Sep 17 00:00:00 2001 From: Daniel Wirtz Date: Thu, 20 Aug 2020 09:43:35 +0200 Subject: [PATCH 41/50] Update src/wasm-type.h Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com> --- src/wasm-type.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wasm-type.h b/src/wasm-type.h index 45438e27dcb..ad65cd372aa 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -234,6 +234,7 @@ struct Tuple { Tuple() : types() {} Tuple(std::initializer_list types) : types(types) {} Tuple(TypeList types) : types(types) {} + Tuple(TypeList&& types) : types(types) {} bool operator==(const Tuple& other) const { return types == other.types; } bool operator!=(const Tuple& other) const { return !(*this == other); } std::string toString() const; From c20b61fa48f23ac85c28b722b89e86ad7a62c11d Mon Sep 17 00:00:00 2001 From: dcode Date: Thu, 20 Aug 2020 10:04:11 +0200 Subject: [PATCH 42/50] add an assert --- src/wasm/wasm-type.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 62115b431cb..66e4b7417f9 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -380,7 +380,8 @@ unsigned Type::getByteSize() const { } Type Type::reinterpret() const { - auto singleType = *(*this).begin(); + assert(!isTuple() && "Unexpected tuple type"); + auto& singleType = *(*this).begin(); switch (singleType.getBasic()) { case Type::i32: return f32; @@ -390,16 +391,9 @@ Type Type::reinterpret() const { return i32; case Type::f64: return i64; - case Type::v128: - case Type::funcref: - case Type::externref: - case Type::nullref: - case Type::exnref: - case Type::none: - case Type::unreachable: + default: WASM_UNREACHABLE("invalid type"); } - WASM_UNREACHABLE("invalid type"); } FeatureSet Type::getFeatures() const { From f6b9f8399c7b4439dd2e000f7d548847edb20400 Mon Sep 17 00:00:00 2001 From: dcode Date: Thu, 20 Aug 2020 10:04:44 +0200 Subject: [PATCH 43/50] revert Tuple move constructor until expert feedback --- src/wasm-type.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index ad65cd372aa..45438e27dcb 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -234,7 +234,6 @@ struct Tuple { Tuple() : types() {} Tuple(std::initializer_list types) : types(types) {} Tuple(TypeList types) : types(types) {} - Tuple(TypeList&& types) : types(types) {} bool operator==(const Tuple& other) const { return types == other.types; } bool operator!=(const Tuple& other) const { return !(*this == other); } std::string toString() const; From 0de9d01ada70846472710477ad67ef2880fbffb4 Mon Sep 17 00:00:00 2001 From: dcode Date: Thu, 20 Aug 2020 10:34:25 +0200 Subject: [PATCH 44/50] remove unnecessary this reference --- src/wasm/wasm-type.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 66e4b7417f9..eab18dc698b 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -335,8 +335,8 @@ bool Type::isNullable() const { } bool Type::operator<(const Type& other) const { - return std::lexicographical_compare((*this).begin(), - (*this).end(), + return std::lexicographical_compare(begin(), + end(), other.begin(), other.end(), [](const Type& a, const Type& b) { From 85fb78f9984268aa8a6c7023d94fc53110390295 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 21 Aug 2020 10:18:06 +0200 Subject: [PATCH 45/50] move remains of TypeDef to wasm-type.cpp, rename to TypeInfo and implement hashing of all the public things --- src/wasm-type.h | 20 ++-- src/wasm/wasm-type.cpp | 223 ++++++++++++++++++++++------------------- 2 files changed, 132 insertions(+), 111 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index e6194aaa2cf..3f6de50513d 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -31,14 +31,12 @@ namespace wasm { -class Type; -struct TypeDef; struct Tuple; struct Signature; struct Struct; struct Array; -typedef std::vector TypeList; +typedef std::vector TypeList; class Type { // The `id` uniquely represents each type, so type equality is just a @@ -310,7 +308,6 @@ std::ostream& operator<<(std::ostream&, Signature); std::ostream& operator<<(std::ostream&, Field); std::ostream& operator<<(std::ostream&, Struct); std::ostream& operator<<(std::ostream&, Array); -std::ostream& operator<<(std::ostream&, TypeDef); } // namespace wasm @@ -320,20 +317,25 @@ template<> class hash { public: size_t operator()(const wasm::Type&) const; }; - +template<> class hash { +public: + size_t operator()(const wasm::Tuple&) const; +}; template<> class hash { public: size_t operator()(const wasm::Signature&) const; }; - template<> class hash { public: size_t operator()(const wasm::Field&) const; }; - -template<> class hash { +template<> class hash { +public: + size_t operator()(const wasm::Struct&) const; +}; +template<> class hash { public: - size_t operator()(const wasm::TypeDef&) const; + size_t operator()(const wasm::Array&) const; }; } // namespace std diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 6af741cbda9..87ca429719f 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -27,7 +27,7 @@ namespace wasm { -struct TypeDef { +struct TypeInfo { enum Kind { TupleKind, SignatureRefKind, StructRefKind, ArrayRefKind } kind; struct SignatureRef { Signature signature; @@ -48,14 +48,14 @@ struct TypeDef { ArrayRef arrayRef; }; - TypeDef(Tuple tuple) : kind(TupleKind), tuple(tuple) {} - TypeDef(Signature signature, bool nullable) + TypeInfo(Tuple tuple) : kind(TupleKind), tuple(tuple) {} + TypeInfo(Signature signature, bool nullable) : kind(SignatureRefKind), signatureRef{signature, nullable} {} - TypeDef(Struct struct_, bool nullable) + TypeInfo(Struct struct_, bool nullable) : kind(StructRefKind), structRef{struct_, nullable} {} - TypeDef(Array array, bool nullable) + TypeInfo(Array array, bool nullable) : kind(ArrayRefKind), arrayRef{array, nullable} {} - TypeDef(const TypeDef& other) { + TypeInfo(const TypeInfo& other) { kind = other.kind; switch (kind) { case TupleKind: @@ -73,7 +73,7 @@ struct TypeDef { } WASM_UNREACHABLE("unexpected kind"); } - ~TypeDef() { + ~TypeInfo() { switch (kind) { case TupleKind: { tuple.~Tuple(); @@ -114,7 +114,7 @@ struct TypeDef { WASM_UNREACHABLE("unexpected kind"); } - bool operator==(const TypeDef& other) const { + bool operator==(const TypeInfo& other) const { if (kind != other.kind) { return false; } @@ -133,10 +133,10 @@ struct TypeDef { } WASM_UNREACHABLE("unexpected kind"); } - bool operator!=(const TypeDef& other) const { return !(*this == other); } - TypeDef& operator=(const TypeDef& other) { + bool operator!=(const TypeInfo& other) const { return !(*this == other); } + TypeInfo& operator=(const TypeInfo& other) { if (&other != this) { - (*this).~TypeDef(); + this->~TypeInfo(); new (this) auto(other); } return *this; @@ -145,73 +145,92 @@ struct TypeDef { std::string toString() const; }; +std::ostream& operator<<(std::ostream&, TypeInfo); + } // namespace wasm namespace std { -template<> class hash> { +template<> class hash { public: - size_t operator()(const vector& types) const { + size_t operator()(const wasm::TypeList& types) const { auto digest = wasm::hash(types.size()); - for (auto t : types) { - wasm::rehash(digest, t.getID()); + for (auto type : types) { + wasm::rehash(digest, type); + } + return digest; + } +}; + +template<> class hash { +public: + size_t operator()(const wasm::FieldList& fields) const { + auto digest = wasm::hash(fields.size()); + for (auto field : fields) { + wasm::rehash(digest, field); } return digest; } }; +template<> class hash { +public: + size_t operator()(const wasm::TypeInfo& info) const { + auto digest = wasm::hash(info.kind); + switch (info.kind) { + case wasm::TypeInfo::TupleKind: { + wasm::rehash(digest, info.tuple.types); + return digest; + } + case wasm::TypeInfo::SignatureRefKind: { + wasm::rehash(digest, info.signatureRef.signature); + wasm::rehash(digest, info.signatureRef.nullable); + return digest; + } + case wasm::TypeInfo::StructRefKind: { + wasm::rehash(digest, info.structRef.struct_); + wasm::rehash(digest, info.structRef.nullable); + return digest; + } + case wasm::TypeInfo::ArrayRefKind: { + wasm::rehash(digest, info.arrayRef.array); + wasm::rehash(digest, info.arrayRef.nullable); + return digest; + } + } + WASM_UNREACHABLE("unexpected kind"); + } +}; + size_t hash::operator()(const wasm::Type& type) const { return wasm::hash(type.getID()); } +size_t hash::operator()(const wasm::Tuple& tuple) const { + return wasm::hash(tuple.types); +} + size_t hash::operator()(const wasm::Signature& sig) const { - auto digest = wasm::hash(sig.params.getID()); - wasm::rehash(digest, sig.results.getID()); + auto digest = wasm::hash(sig.params); + wasm::rehash(digest, sig.results); return digest; } size_t hash::operator()(const wasm::Field& field) const { - auto digest = wasm::hash(field.type.getID()); - wasm::rehash(digest, uint32_t(field.packedType)); + auto digest = wasm::hash(field.type); + wasm::rehash(digest, field.packedType); wasm::rehash(digest, field.mutable_); return digest; } -size_t hash::operator()(const wasm::TypeDef& typeDef) const { - auto kind = typeDef.kind; - auto digest = wasm::hash(uint32_t(kind)); - switch (kind) { - case wasm::TypeDef::TupleKind: { - auto& types = typeDef.tuple.types; - for (auto t : types) { - wasm::rehash(digest, t.getID()); - } - return digest; - } - case wasm::TypeDef::SignatureRefKind: { - auto& sig = typeDef.signatureRef.signature; - wasm::rehash(digest, sig.params.getID()); - wasm::rehash(digest, sig.results.getID()); - wasm::rehash(digest, typeDef.isNullable()); - return digest; - } - case wasm::TypeDef::StructRefKind: { - auto& fields = typeDef.structRef.struct_.fields; - wasm::rehash(digest, fields.size()); - for (auto f : fields) { - wasm::rehash(digest, f); - } - wasm::rehash(digest, typeDef.isNullable()); - return digest; - } - case wasm::TypeDef::ArrayRefKind: { - auto& array = typeDef.arrayRef.array; - wasm::rehash(digest, array.element); - wasm::rehash(digest, typeDef.isNullable()); - return digest; - } - } - WASM_UNREACHABLE("unexpected kind"); +size_t hash::operator()(const wasm::Struct& struct_) const { + auto digest = wasm::hash(0); + wasm::rehash(digest, struct_.fields); + return digest; +} + +size_t hash::operator()(const wasm::Array& array) const { + return wasm::hash(array.element); } } // namespace std @@ -223,46 +242,46 @@ namespace { std::mutex mutex; // Track unique_ptrs for constructed types to avoid leaks -std::vector> constructedTypes; +std::vector> constructedTypes; // Maps from constructed types to the canonical Type ID. -std::unordered_map indices = { +std::unordered_map indices = { // If a Type is constructed from a list of types, the list of types becomes - // implicitly converted to a TypeDef before canonicalizing its id. This is + // implicitly converted to a TypeInfo before canonicalizing its id. This is // also the case if a list of just one type is provided, even though such a // list of types will be canonicalized to the BasicID of the single type. As // such, the following entries are solely placeholders to enable the lookup // of lists of just one type to the BasicID of the single type. - {TypeDef(Tuple()), Type::none}, - {TypeDef({Type::unreachable}), Type::unreachable}, - {TypeDef({Type::i32}), Type::i32}, - {TypeDef({Type::i64}), Type::i64}, - {TypeDef({Type::f32}), Type::f32}, - {TypeDef({Type::f64}), Type::f64}, - {TypeDef({Type::v128}), Type::v128}, - {TypeDef({Type::funcref}), Type::funcref}, - {TypeDef({Type::externref}), Type::externref}, - {TypeDef({Type::nullref}), Type::nullref}, - {TypeDef({Type::exnref}), Type::exnref}, + {TypeInfo(Tuple()), Type::none}, + {TypeInfo({Type::unreachable}), Type::unreachable}, + {TypeInfo({Type::i32}), Type::i32}, + {TypeInfo({Type::i64}), Type::i64}, + {TypeInfo({Type::f32}), Type::f32}, + {TypeInfo({Type::f64}), Type::f64}, + {TypeInfo({Type::v128}), Type::v128}, + {TypeInfo({Type::funcref}), Type::funcref}, + {TypeInfo({Type::externref}), Type::externref}, + {TypeInfo({Type::nullref}), Type::nullref}, + {TypeInfo({Type::exnref}), Type::exnref}, }; } // anonymous namespace -static uintptr_t canonicalize(const TypeDef& typeDef) { +static uintptr_t canonicalize(const TypeInfo& info) { std::lock_guard lock(mutex); - auto indexIt = indices.find(typeDef); + auto indexIt = indices.find(info); if (indexIt != indices.end()) { return indexIt->second; } - auto ptr = std::make_unique(typeDef); + auto ptr = std::make_unique(info); auto id = uintptr_t(ptr.get()); constructedTypes.push_back(std::move(ptr)); assert(id > Type::_last_basic_id); - indices[typeDef] = id; + indices[info] = id; return id; } -static TypeDef* getDef(Type type) { return (TypeDef*)type.getID(); } +static TypeInfo* getTypeInfo(Type type) { return (TypeInfo*)type.getID(); } Type::Type(std::initializer_list types) : Type(Tuple(types)) {} @@ -281,11 +300,11 @@ Type::Type(const Tuple& tuple) { *this = types[0]; return; } - id = canonicalize(TypeDef(tuple)); + id = canonicalize(TypeInfo(tuple)); } Type::Type(const Signature signature, bool nullable) { - id = canonicalize(TypeDef(signature, nullable)); + id = canonicalize(TypeInfo(signature, nullable)); } Type::Type(const Struct& struct_, bool nullable) { @@ -294,19 +313,19 @@ Type::Type(const Struct& struct_, bool nullable) { assert(f.type.isSingle()); } #endif - id = canonicalize(TypeDef(struct_, nullable)); + id = canonicalize(TypeInfo(struct_, nullable)); } Type::Type(const Array& array, bool nullable) { assert(array.element.type.isSingle()); - id = canonicalize(TypeDef(array, nullable)); + id = canonicalize(TypeInfo(array, nullable)); } bool Type::isTuple() const { if (isBasic()) { return false; } else { - return getDef(*this)->isTuple(); + return getTypeInfo(*this)->isTuple(); } } @@ -314,12 +333,12 @@ bool Type::isRef() const { if (isBasic()) { return id >= funcref && id <= exnref; } else { - switch (getDef(*this)->kind) { - case TypeDef::TupleKind: + switch (getTypeInfo(*this)->kind) { + case TypeInfo::TupleKind: return false; - case TypeDef::SignatureRefKind: - case TypeDef::StructRefKind: - case TypeDef::ArrayRefKind: + case TypeInfo::SignatureRefKind: + case TypeInfo::StructRefKind: + case TypeInfo::ArrayRefKind: return true; } WASM_UNREACHABLE("unexpected kind"); @@ -330,7 +349,7 @@ bool Type::isNullable() const { if (isBasic()) { return id >= funcref && id <= exnref; } else { - return getDef(*this)->isNullable(); + return getTypeInfo(*this)->isNullable(); } } @@ -498,7 +517,7 @@ Type Type::getLeastUpperBound(Type a, Type b) { Type::Iterator Type::end() const { if (isTuple()) { - return Iterator(this, getDef(*this)->tuple.types.size()); + return Iterator(this, getTypeInfo(*this)->tuple.types.size()); } else { // TODO: unreachable is special and expands to {unreachable} currently. // see also: https://github.com/WebAssembly/binaryen/issues/3062 @@ -508,7 +527,7 @@ Type::Iterator Type::end() const { const Type& Type::Iterator::operator*() const { if (parent->isTuple()) { - return getDef(*parent)->tuple.types[index]; + return getTypeInfo(*parent)->tuple.types[index]; } else { // TODO: see comment in Type::end() assert(index == 0 && parent->id != Type::none && "Index out of bounds"); @@ -518,7 +537,7 @@ const Type& Type::Iterator::operator*() const { const Type& Type::operator[](size_t index) const { if (isTuple()) { - return getDef(*this)->tuple.types[index]; + return getTypeInfo(*this)->tuple.types[index]; } else { assert(index == 0 && "Index out of bounds"); return *begin(); @@ -559,7 +578,7 @@ std::string Struct::toString() const { return genericToString(*this); } std::string Array::toString() const { return genericToString(*this); } -std::string TypeDef::toString() const { return genericToString(*this); } +std::string TypeInfo::toString() const { return genericToString(*this); } bool Signature::operator<(const Signature& other) const { if (results < other.results) { @@ -609,7 +628,7 @@ std::ostream& operator<<(std::ostream& os, Type type) { break; } } else { - os << *getDef(type); + os << *getTypeInfo(type); } return os; } @@ -686,31 +705,31 @@ std::ostream& operator<<(std::ostream& os, Array array) { return os << "(array " << array.element << ")"; } -std::ostream& operator<<(std::ostream& os, TypeDef typeDef) { - switch (typeDef.kind) { - case TypeDef::TupleKind: { - return os << typeDef.tuple; +std::ostream& operator<<(std::ostream& os, TypeInfo info) { + switch (info.kind) { + case TypeInfo::TupleKind: { + return os << info.tuple; } - case TypeDef::SignatureRefKind: { + case TypeInfo::SignatureRefKind: { os << "(ref "; - if (typeDef.signatureRef.nullable) { + if (info.signatureRef.nullable) { os << "null "; } - return os << typeDef.signatureRef.signature << ")"; + return os << info.signatureRef.signature << ")"; } - case TypeDef::StructRefKind: { + case TypeInfo::StructRefKind: { os << "(ref "; - if (typeDef.structRef.nullable) { + if (info.structRef.nullable) { os << "null "; } - return os << typeDef.structRef.struct_ << ")"; + return os << info.structRef.struct_ << ")"; } - case TypeDef::ArrayRefKind: { + case TypeInfo::ArrayRefKind: { os << "(ref "; - if (typeDef.arrayRef.nullable) { + if (info.arrayRef.nullable) { os << "null "; } - return os << typeDef.arrayRef.array << ")"; + return os << info.arrayRef.array << ")"; } } WASM_UNREACHABLE("unexpected kind"); From cecf38ae1d9fca01fb1e813d0037480ae83493ea Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 21 Aug 2020 14:15:12 +0200 Subject: [PATCH 46/50] apply dangerous half-knowledge --- src/wasm-type.h | 28 ++++++++++++++++------------ src/wasm/wasm-type.cpp | 21 ++++++++++++--------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 3f6de50513d..c6c547e9c17 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -76,7 +76,7 @@ class Type { explicit Type(const Tuple&); // Construct from signature description - explicit Type(const Signature, bool nullable); + explicit Type(const Signature&, bool nullable); // Construct from struct description explicit Type(const Struct&, bool nullable); @@ -143,9 +143,9 @@ class Type { // otherwise ambiguous whether to convert both this and other to int or // convert other to Type. bool operator==(const Type& other) const { return id == other.id; } - bool operator==(const BasicID& other) const { return id == other; } + bool operator==(BasicID otherId) const { return id == otherId; } bool operator!=(const Type& other) const { return id != other.id; } - bool operator!=(const BasicID& other) const { return id != other; } + bool operator!=(BasicID otherId) const { return id != otherId; } // Order types by some notion of simplicity bool operator<(const Type& other) const; @@ -165,12 +165,12 @@ class Type { static Type get(unsigned byteSize, bool float_); // Returns true if left is a subtype of right. Subtype includes itself. - static bool isSubType(Type left, Type right); + static bool isSubType(const Type& left, const Type& right); // Computes the least upper bound from the type lattice. // If one of the type is unreachable, the other type becomes the result. If // the common supertype does not exist, returns none, a poison value. - static Type getLeastUpperBound(Type a, Type b); + static Type getLeastUpperBound(const Type& a, const Type& b); // Computes the least upper bound for all types in the given list. template static Type mergeTypes(const T& types) { @@ -216,14 +216,14 @@ class Type { // Wrapper type for formatting types as "(param i32 i64 f32)" struct ParamType { Type type; - ParamType(Type type) : type(type) {} + ParamType(const Type& type) : type(type) {} std::string toString() const; }; // Wrapper type for formatting types as "(result i32 i64 f32)" struct ResultType { Type type; - ResultType(Type type) : type(type) {} + ResultType(const Type& type) : type(type) {} std::string toString() const; }; @@ -231,7 +231,8 @@ struct Tuple { TypeList types; Tuple() : types() {} Tuple(std::initializer_list types) : types(types) {} - Tuple(TypeList types) : types(types) {} + Tuple(const TypeList& types) : types(types) {} + Tuple(TypeList&& types) : types(std::move(types)) {} bool operator==(const Tuple& other) const { return types == other.types; } bool operator!=(const Tuple& other) const { return !(*this == other); } std::string toString() const; @@ -241,7 +242,8 @@ struct Signature { Type params; Type results; Signature() : params(Type::none), results(Type::none) {} - Signature(Type params, Type results) : params(params), results(results) {} + Signature(const Type& params, const Type& results) + : params(params), results(results) {} bool operator==(const Signature& other) const { return params == other.params && results == other.results; } @@ -259,7 +261,7 @@ struct Field { } packedType; // applicable iff type=i32 bool mutable_; - Field(Type type, bool mutable_ = false) + Field(const Type& type, bool mutable_ = false) : type(type), packedType(not_packed), mutable_(mutable_) {} Field(PackedType packedType, bool mutable_ = false) : type(Type::i32), packedType(packedType), mutable_(mutable_) {} @@ -285,7 +287,8 @@ typedef std::vector FieldList; struct Struct { FieldList fields; Struct(const Struct& other) : fields(other.fields) {} - Struct(FieldList fields) : fields(fields) {} + Struct(const FieldList& fields) : fields(fields) {} + Struct(FieldList&& fields) : fields(std::move(fields)) {} bool operator==(const Struct& other) const { return fields == other.fields; } bool operator!=(const Struct& other) const { return !(*this == other); } std::string toString() const; @@ -294,7 +297,8 @@ struct Struct { struct Array { Field element; Array(const Array& other) : element(other.element) {} - Array(Field element) : element(element) {} + Array(const Field& element) : element(element) {} + Array(Field&& element) : element(std::move(element)) {} bool operator==(const Array& other) const { return element == other.element; } bool operator!=(const Array& other) const { return !(*this == other); } std::string toString() const; diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 87ca429719f..9f9439d8e7d 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -48,12 +48,13 @@ struct TypeInfo { ArrayRef arrayRef; }; - TypeInfo(Tuple tuple) : kind(TupleKind), tuple(tuple) {} - TypeInfo(Signature signature, bool nullable) + TypeInfo(const Tuple& tuple) : kind(TupleKind), tuple(tuple) {} + TypeInfo(Tuple&& tuple) : kind(TupleKind), tuple(std::move(tuple)) {} + TypeInfo(const Signature& signature, bool nullable) : kind(SignatureRefKind), signatureRef{signature, nullable} {} - TypeInfo(Struct struct_, bool nullable) + TypeInfo(const Struct& struct_, bool nullable) : kind(StructRefKind), structRef{struct_, nullable} {} - TypeInfo(Array array, bool nullable) + TypeInfo(const Array& array, bool nullable) : kind(ArrayRefKind), arrayRef{array, nullable} {} TypeInfo(const TypeInfo& other) { kind = other.kind; @@ -281,7 +282,9 @@ static uintptr_t canonicalize(const TypeInfo& info) { return id; } -static TypeInfo* getTypeInfo(Type type) { return (TypeInfo*)type.getID(); } +static TypeInfo* getTypeInfo(const Type& type) { + return (TypeInfo*)type.getID(); +} Type::Type(std::initializer_list types) : Type(Tuple(types)) {} @@ -303,7 +306,7 @@ Type::Type(const Tuple& tuple) { id = canonicalize(TypeInfo(tuple)); } -Type::Type(const Signature signature, bool nullable) { +Type::Type(const Signature& signature, bool nullable) { id = canonicalize(TypeInfo(signature, nullable)); } @@ -415,7 +418,7 @@ Type Type::reinterpret() const { } FeatureSet Type::getFeatures() const { - auto getSingleFeatures = [](Type t) -> FeatureSet { + auto getSingleFeatures = [](const Type& t) -> FeatureSet { TODO_SINGLE_COMPOUND(t); switch (t.getBasic()) { case Type::v128: @@ -457,7 +460,7 @@ Type Type::get(unsigned byteSize, bool float_) { WASM_UNREACHABLE("invalid size"); } -bool Type::isSubType(Type left, Type right) { +bool Type::isSubType(const Type& left, const Type& right) { if (left == right) { return true; } @@ -479,7 +482,7 @@ bool Type::isSubType(Type left, Type right) { return false; } -Type Type::getLeastUpperBound(Type a, Type b) { +Type Type::getLeastUpperBound(const Type& a, const Type& b) { if (a == b) { return a; } From fa620d9795b4cb936030713047df4bc8bb8866df Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 21 Aug 2020 16:56:44 +0200 Subject: [PATCH 47/50] interesting tests --- test/example/typedef.cpp | 112 -------------------- test/example/typedef.txt | 18 ---- test/example/typeinfo.cpp | 218 ++++++++++++++++++++++++++++++++++++++ test/example/typeinfo.txt | 70 ++++++++++++ 4 files changed, 288 insertions(+), 130 deletions(-) delete mode 100644 test/example/typedef.cpp delete mode 100644 test/example/typedef.txt create mode 100644 test/example/typeinfo.cpp create mode 100644 test/example/typeinfo.txt diff --git a/test/example/typedef.cpp b/test/example/typedef.cpp deleted file mode 100644 index a43b513ea8a..00000000000 --- a/test/example/typedef.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include -#include - -#include "wasm-type.h" - -using namespace wasm; - -void test_compound() { - { - Signature signature(Type::i32, Type::none); - assert(Type(signature, false).getID() == Type(signature, false).getID()); - assert(Type(signature, false).getID() != Type(signature, true).getID()); - - Signature sameSignature(Type::i32, Type::none); - assert(Type(signature, false).getID() == - Type(sameSignature, false).getID()); - - Signature otherSignature(Type::f64, Type::none); - assert(Type(signature, false).getID() != - Type(otherSignature, false).getID()); - } - { - Struct struct_({}); - assert(Type(struct_, false).getID() == Type(struct_, false).getID()); - assert(Type(struct_, false).getID() != Type(struct_, true).getID()); - - Struct sameStruct({}); - assert(Type(struct_, false).getID() == Type(sameStruct, false).getID()); - - Struct otherStruct({{Type::i32, false}}); - assert(Type(struct_, false).getID() != Type(otherStruct, false).getID()); - } - { - Array array({Type::i32, false}); - assert(Type(array, false).getID() == Type(array, false).getID()); - assert(Type(array, false).getID() != Type(array, true).getID()); - - Array sameArray({Type::i32, false}); - assert(Type(array, false).getID() == Type(sameArray, false).getID()); - - Array otherArray({Type::f64, true}); - assert(Type(array, false).getID() != Type(otherArray, false).getID()); - } - { - Tuple singleTuple({Type::i32}); - assert(Type(singleTuple).getID() == Type::i32); - - Tuple tuple({Type::i32, Type::f64}); - assert(Type(tuple).getID() == Type(tuple).getID()); - - Tuple sameTuple({Type::i32, Type::f64}); - assert(Type(tuple).getID() == Type(sameTuple).getID()); - - Tuple otherTuple({Type::f64, Type::externref}); - assert(Type(tuple).getID() != Type(otherTuple).getID()); - } -} - -void test_printing() { - { - std::cout << "# Signature\n"; - Signature signature(Type::i32, Type::none); - std::cout << signature << "\n"; - std::cout << Type(signature, false) << "\n"; - std::cout << Type(signature, true) << "\n"; - } - { - std::cout << "# Struct\n"; - Struct struct_({ - {Type::i32, false}, - {Type::i64, false}, - {Type::f32, true}, - {Type::f64, true}, - {Type::externref, false}, - }); - std::cout << struct_ << "\n"; - std::cout << Type(struct_, false) << "\n"; - std::cout << Type(struct_, true) << "\n"; - } - { - std::cout << "# Array\n"; - Array array({Type::i32, false}); - std::cout << array << "\n"; - std::cout << Type(array, false) << "\n"; - std::cout << Type(array, true) << "\n"; - Array arrayMut({Type::externref, true}); - std::cout << arrayMut << "\n"; - std::cout << Type(arrayMut, false) << "\n"; - std::cout << Type(arrayMut, true) << "\n"; - } - { - std::cout << "# Tuple\n"; - Tuple tuple({ - Type::i32, - Type::f64, - Type::externref, - }); - std::cout << tuple << "\n"; - std::cout << Type(tuple) << "\n"; - } - // FIXME: Can't expand a single compound `params` type, see - // https://github.com/WebAssembly/binaryen/pull/3012#discussion_r471842763 - // { - // Signature signature(Type(Array({Type::i32, false}), false), Type::none); - // std::cout << signature << "\n"; - // } -} - -int main() { - test_compound(); - test_printing(); -} diff --git a/test/example/typedef.txt b/test/example/typedef.txt deleted file mode 100644 index cc3c3caa53d..00000000000 --- a/test/example/typedef.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Signature -(func (param i32)) -(ref (func (param i32))) -(ref null (func (param i32))) -# Struct -(struct (field i32 i64 (mut f32) (mut f64) externref)) -(ref (struct (field i32 i64 (mut f32) (mut f64) externref))) -(ref null (struct (field i32 i64 (mut f32) (mut f64) externref))) -# Array -(array i32) -(ref (array i32)) -(ref null (array i32)) -(array (mut externref)) -(ref (array (mut externref))) -(ref null (array (mut externref))) -# Tuple -(i32 f64 externref) -(i32 f64 externref) diff --git a/test/example/typeinfo.cpp b/test/example/typeinfo.cpp new file mode 100644 index 00000000000..dc98667060f --- /dev/null +++ b/test/example/typeinfo.cpp @@ -0,0 +1,218 @@ +#include +#include + +#include "wasm-type.h" + +using namespace wasm; + +void test_compound() { + { + Signature signature(Type::i32, Type::none); + assert(Type(signature, false).getID() == Type(signature, false).getID()); + assert(Type(signature, false).getID() != Type(signature, true).getID()); + + Signature sameSignature(Type::i32, Type::none); + assert(Type(signature, false).getID() == + Type(sameSignature, false).getID()); + + Signature otherSignature(Type::f64, Type::none); + assert(Type(signature, false).getID() != + Type(otherSignature, false).getID()); + } + { + Struct struct_({}); + assert(Type(struct_, false).getID() == Type(struct_, false).getID()); + assert(Type(struct_, false).getID() != Type(struct_, true).getID()); + + Struct sameStruct({}); + assert(Type(struct_, false).getID() == Type(sameStruct, false).getID()); + + Struct otherStruct({{Type::i32, false}}); + assert(Type(struct_, false).getID() != Type(otherStruct, false).getID()); + } + { + Array array({Type::i32, false}); + assert(Type(array, false).getID() == Type(array, false).getID()); + assert(Type(array, false).getID() != Type(array, true).getID()); + + Array sameArray({Type::i32, false}); + assert(Type(array, false).getID() == Type(sameArray, false).getID()); + + Array otherArray({Type::f64, true}); + assert(Type(array, false).getID() != Type(otherArray, false).getID()); + } + { + Tuple singleTuple({Type::i32}); + assert(Type(singleTuple).getID() == Type::i32); + + Tuple tuple({Type::i32, Type::f64}); + assert(Type(tuple).getID() == Type(tuple).getID()); + + Tuple sameTuple({Type::i32, Type::f64}); + assert(Type(tuple).getID() == Type(sameTuple).getID()); + + Tuple otherTuple({Type::f64, Type::externref}); + assert(Type(tuple).getID() != Type(otherTuple).getID()); + } +} + +void test_printing() { + { + std::cout << ";; Signature\n"; + Signature emptySignature(Type::none, Type::none); + std::cout << emptySignature << "\n"; + std::cout << Type(emptySignature, false) << "\n"; + std::cout << Type(emptySignature, true) << "\n"; + Signature signature(Type::i32, Type::f64); + std::cout << signature << "\n"; + std::cout << Type(signature, false) << "\n"; + std::cout << Type(signature, true) << "\n"; + } + { + std::cout << "\n;; Struct\n"; + Struct emptyStruct({}); + std::cout << emptyStruct << "\n"; + std::cout << Type(emptyStruct, false) << "\n"; + std::cout << Type(emptyStruct, true) << "\n"; + Struct struct_({ + {Type::i32, false}, + {Type::i64, false}, + {Type::f32, true}, + {Type::f64, true}, + {Type::externref, false}, + }); + std::cout << struct_ << "\n"; + std::cout << Type(struct_, false) << "\n"; + std::cout << Type(struct_, true) << "\n"; + } + { + std::cout << "\n;; Array\n"; + Array array({Type::i32, false}); + std::cout << array << "\n"; + std::cout << Type(array, false) << "\n"; + std::cout << Type(array, true) << "\n"; + Array arrayMut({Type::externref, true}); + std::cout << arrayMut << "\n"; + std::cout << Type(arrayMut, false) << "\n"; + std::cout << Type(arrayMut, true) << "\n"; + } + { + std::cout << "\n;; Tuple\n"; + Tuple emptyTuple({}); + std::cout << emptyTuple << "\n"; + std::cout << Type(emptyTuple) << "\n"; + Tuple tuple({ + Type::i32, + Type::f64, + Type::externref, + }); + std::cout << tuple << "\n"; + std::cout << Type(tuple) << "\n"; + } + { + std::cout << "\n;; Signature of references (param/result)\n"; + Signature signature(Type(Struct({}), true), + Type(Array({Type::i32, true}), false)); + std::cout << signature << "\n"; + } + { + std::cout << "\n;; Signature of references (params/results)\n"; + Signature signature(Type({ + Type(Struct({}), true), + Type(Array({Type::i32, true}), false), + }), + Type({ + Type(Struct({}), false), + Type(Array({Type::i32, false}), true), + })); + std::cout << signature << "\n"; + } + { + std::cout << "\n;; Struct of references\n"; + Struct structOfSignature({ + {Type(Signature(Type::none, Type::none), false), false}, + {Type(Signature(Type::none, Type::none), false), true}, + {Type(Signature(Type::none, Type::none), true), false}, + {Type(Signature(Type::none, Type::none), true), true}, + }); + std::cout << structOfSignature << "\n"; + std::cout << Type(structOfSignature, false) << "\n"; + std::cout << Type(structOfSignature, true) << "\n"; + Struct structOfStruct({ + {Type(Struct({}), false), false}, + {Type(Struct({}), false), true}, + {Type(Struct({}), true), false}, + {Type(Struct({}), true), true}, + }); + std::cout << structOfStruct << "\n"; + std::cout << Type(structOfStruct, false) << "\n"; + std::cout << Type(structOfStruct, true) << "\n"; + Struct structOfArray({ + {Type(Array({Type::i32, false}), false), false}, + {Type(Array({Type::i32, false}), false), true}, + {Type(Array({Type::i32, false}), true), false}, + {Type(Array({Type::i32, false}), true), true}, + }); + std::cout << structOfArray << "\n"; + std::cout << Type(structOfArray, false) << "\n"; + std::cout << Type(structOfArray, true) << "\n"; + Struct structOfEverything({ + {Type::i32, true}, + {Type(Signature(Type::none, Type::none), true), true}, + {Type(Struct({}), true), true}, + {Type(Array({Type::i32, true}), true), true}, + }); + std::cout << structOfEverything << "\n"; + std::cout << Type(structOfEverything, false) << "\n"; + std::cout << Type(structOfEverything, true) << "\n"; + } + { + std::cout << "\n;; Array of references\n"; + Array arrayOfSignature( + {Type(Signature(Type::none, Type::none), true), false}); + std::cout << arrayOfSignature << "\n"; + std::cout << Type(arrayOfSignature, false) << "\n"; + std::cout << Type(arrayOfSignature, true) << "\n"; + Array arrayOfStruct({Type(Struct({}), true), true}); + std::cout << arrayOfStruct << "\n"; + std::cout << Type(arrayOfStruct, false) << "\n"; + std::cout << Type(arrayOfStruct, true) << "\n"; + Array arrayOfArray({Type(Array({Type::i32, false}), true), false}); + std::cout << arrayOfArray << "\n"; + std::cout << Type(arrayOfArray, false) << "\n"; + std::cout << Type(arrayOfArray, true) << "\n"; + } + { + std::cout << "\n;; Tuple of references\n"; + Tuple tuple({ + Type(Signature(Type::none, Type::none), false), + Type(Signature(Type::none, Type::none), true), + Type(Struct({}), false), + Type(Struct({}), true), + Type(Array({Type::i32, false}), false), + Type(Array({Type::i32, false}), true), + }); + std::cout << tuple << "\n"; + std::cout << Type(tuple) << "\n"; + } + // TODO: Think about recursive types. Currently impossible to construct. + { + std::cout << "\n;; Recursive\n"; + Signature signatureSignature(Type::none, Type::none); + signatureSignature.params = Type(signatureSignature, false); + // ^ copies + std::cout << signatureSignature << "\n"; + std::cout << Type(signatureSignature, false) << "\n"; + Signature signatureArraySignature(Type::none, Type::none); + signatureArraySignature.params = + Type(Array({Type(signatureArraySignature, false), false}), false); + // ^ copies + std::cout << signatureArraySignature << "\n"; + std::cout << Type(signatureArraySignature, false) << "\n"; + } +} + +int main() { + test_compound(); + test_printing(); +} diff --git a/test/example/typeinfo.txt b/test/example/typeinfo.txt new file mode 100644 index 00000000000..71e9a3e9c78 --- /dev/null +++ b/test/example/typeinfo.txt @@ -0,0 +1,70 @@ +;; Signature +(func) +(ref (func)) +(ref null (func)) +(func (param i32) (result f64)) +(ref (func (param i32) (result f64))) +(ref null (func (param i32) (result f64))) + +;; Struct +(struct) +(ref (struct)) +(ref null (struct)) +(struct (field i32 i64 (mut f32) (mut f64) externref)) +(ref (struct (field i32 i64 (mut f32) (mut f64) externref))) +(ref null (struct (field i32 i64 (mut f32) (mut f64) externref))) + +;; Array +(array i32) +(ref (array i32)) +(ref null (array i32)) +(array (mut externref)) +(ref (array (mut externref))) +(ref null (array (mut externref))) + +;; Tuple +() +none +(i32 f64 externref) +(i32 f64 externref) + +;; Signature of references (param/result) +(func (param (ref null (struct))) (result (ref (array (mut i32))))) + +;; Signature of references (params/results) +(func (param (ref null (struct)) (ref (array (mut i32)))) (result (ref (struct)) (ref null (array i32)))) + +;; Struct of references +(struct (field (ref (func)) (mut (ref (func))) (ref null (func)) (mut (ref null (func))))) +(ref (struct (field (ref (func)) (mut (ref (func))) (ref null (func)) (mut (ref null (func)))))) +(ref null (struct (field (ref (func)) (mut (ref (func))) (ref null (func)) (mut (ref null (func)))))) +(struct (field (ref (struct)) (mut (ref (struct))) (ref null (struct)) (mut (ref null (struct))))) +(ref (struct (field (ref (struct)) (mut (ref (struct))) (ref null (struct)) (mut (ref null (struct)))))) +(ref null (struct (field (ref (struct)) (mut (ref (struct))) (ref null (struct)) (mut (ref null (struct)))))) +(struct (field (ref (array i32)) (mut (ref (array i32))) (ref null (array i32)) (mut (ref null (array i32))))) +(ref (struct (field (ref (array i32)) (mut (ref (array i32))) (ref null (array i32)) (mut (ref null (array i32)))))) +(ref null (struct (field (ref (array i32)) (mut (ref (array i32))) (ref null (array i32)) (mut (ref null (array i32)))))) +(struct (field (mut i32) (mut (ref null (func))) (mut (ref null (struct))) (mut (ref null (array (mut i32)))))) +(ref (struct (field (mut i32) (mut (ref null (func))) (mut (ref null (struct))) (mut (ref null (array (mut i32))))))) +(ref null (struct (field (mut i32) (mut (ref null (func))) (mut (ref null (struct))) (mut (ref null (array (mut i32))))))) + +;; Array of references +(array (ref null (func))) +(ref (array (ref null (func)))) +(ref null (array (ref null (func)))) +(array (mut (ref null (struct)))) +(ref (array (mut (ref null (struct))))) +(ref null (array (mut (ref null (struct))))) +(array (ref null (array i32))) +(ref (array (ref null (array i32)))) +(ref null (array (ref null (array i32)))) + +;; Tuple of references +((ref (func)) (ref null (func)) (ref (struct)) (ref null (struct)) (ref (array i32)) (ref null (array i32))) +((ref (func)) (ref null (func)) (ref (struct)) (ref null (struct)) (ref (array i32)) (ref null (array i32))) + +;; Recursive +(func (param (ref (func)))) +(ref (func (param (ref (func))))) +(func (param (ref (array (ref (func)))))) +(ref (func (param (ref (array (ref (func))))))) From 9d206afe8f2aab413a25bf4983f71056bd71e929 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 23 Aug 2020 15:58:01 +0200 Subject: [PATCH 48/50] revert dangerous half-knowledge --- src/wasm-type.h | 14 +++++++------- src/wasm/wasm-type.cpp | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index c6c547e9c17..434aeb9b597 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -76,7 +76,7 @@ class Type { explicit Type(const Tuple&); // Construct from signature description - explicit Type(const Signature&, bool nullable); + explicit Type(const Signature, bool nullable); // Construct from struct description explicit Type(const Struct&, bool nullable); @@ -143,9 +143,9 @@ class Type { // otherwise ambiguous whether to convert both this and other to int or // convert other to Type. bool operator==(const Type& other) const { return id == other.id; } - bool operator==(BasicID otherId) const { return id == otherId; } + bool operator==(const BasicID& otherId) const { return id == otherId; } bool operator!=(const Type& other) const { return id != other.id; } - bool operator!=(BasicID otherId) const { return id != otherId; } + bool operator!=(const BasicID& otherId) const { return id != otherId; } // Order types by some notion of simplicity bool operator<(const Type& other) const; @@ -165,12 +165,12 @@ class Type { static Type get(unsigned byteSize, bool float_); // Returns true if left is a subtype of right. Subtype includes itself. - static bool isSubType(const Type& left, const Type& right); + static bool isSubType(Type left, Type right); // Computes the least upper bound from the type lattice. // If one of the type is unreachable, the other type becomes the result. If // the common supertype does not exist, returns none, a poison value. - static Type getLeastUpperBound(const Type& a, const Type& b); + static Type getLeastUpperBound(Type a, Type b); // Computes the least upper bound for all types in the given list. template static Type mergeTypes(const T& types) { @@ -216,14 +216,14 @@ class Type { // Wrapper type for formatting types as "(param i32 i64 f32)" struct ParamType { Type type; - ParamType(const Type& type) : type(type) {} + ParamType(Type type) : type(type) {} std::string toString() const; }; // Wrapper type for formatting types as "(result i32 i64 f32)" struct ResultType { Type type; - ResultType(const Type& type) : type(type) {} + ResultType(Type type) : type(type) {} std::string toString() const; }; diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 9f9439d8e7d..5247ebb6f36 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -306,7 +306,7 @@ Type::Type(const Tuple& tuple) { id = canonicalize(TypeInfo(tuple)); } -Type::Type(const Signature& signature, bool nullable) { +Type::Type(const Signature signature, bool nullable) { id = canonicalize(TypeInfo(signature, nullable)); } @@ -418,7 +418,7 @@ Type Type::reinterpret() const { } FeatureSet Type::getFeatures() const { - auto getSingleFeatures = [](const Type& t) -> FeatureSet { + auto getSingleFeatures = [](Type t) -> FeatureSet { TODO_SINGLE_COMPOUND(t); switch (t.getBasic()) { case Type::v128: @@ -460,7 +460,7 @@ Type Type::get(unsigned byteSize, bool float_) { WASM_UNREACHABLE("invalid size"); } -bool Type::isSubType(const Type& left, const Type& right) { +bool Type::isSubType(Type left, Type right) { if (left == right) { return true; } @@ -482,7 +482,7 @@ bool Type::isSubType(const Type& left, const Type& right) { return false; } -Type Type::getLeastUpperBound(const Type& a, const Type& b) { +Type Type::getLeastUpperBound(Type a, Type b) { if (a == b) { return a; } From b8d6faf5e086827f372cd76e8022e50aba008fcf Mon Sep 17 00:00:00 2001 From: Daniel Wirtz Date: Mon, 24 Aug 2020 11:22:56 +0200 Subject: [PATCH 49/50] Update src/wasm-type.h Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com> --- src/wasm-type.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index 434aeb9b597..c7888e00ee0 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -242,8 +242,7 @@ struct Signature { Type params; Type results; Signature() : params(Type::none), results(Type::none) {} - Signature(const Type& params, const Type& results) - : params(params), results(results) {} + Signature(Type params, Type results) : params(params), results(results) {} bool operator==(const Signature& other) const { return params == other.params && results == other.results; } From fd81477b3503dbc39afdc6d3a6ebfeb0cf13f4be Mon Sep 17 00:00:00 2001 From: Daniel Wirtz Date: Mon, 24 Aug 2020 11:23:11 +0200 Subject: [PATCH 50/50] Update src/wasm-type.h Co-authored-by: Thomas Lively <7121787+tlively@users.noreply.github.com> --- src/wasm-type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm-type.h b/src/wasm-type.h index c7888e00ee0..cee8dae0355 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -260,7 +260,7 @@ struct Field { } packedType; // applicable iff type=i32 bool mutable_; - Field(const Type& type, bool mutable_ = false) + Field(Type type, bool mutable_ = false) : type(type), packedType(not_packed), mutable_(mutable_) {} Field(PackedType packedType, bool mutable_ = false) : type(Type::i32), packedType(packedType), mutable_(mutable_) {}