summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Wirtz <dcode@dcode.io>2020-08-26 23:05:36 +0200
committerGitHub <noreply@github.com>2020-08-26 23:05:36 +0200
commita61b9dff9be3da4d4c56f92f494e5f2914f32e1e (patch)
treedd00fd7998998819ebb571f09bdc8954b6e08a0b /src
parent9371352930ccfc1947dadb8130530db65608732b (diff)
downloadbinaryen-a61b9dff9be3da4d4c56f92f494e5f2914f32e1e.tar.gz
binaryen-a61b9dff9be3da4d4c56f92f494e5f2914f32e1e.tar.bz2
binaryen-a61b9dff9be3da4d4c56f92f494e5f2914f32e1e.zip
Add new compound Rtt type (#3076)
Extends compound types introduced in #3012 with a representation of `Rtt`s as described in the GC proposal, by also introducing the concept of a `HeapType` shared between `TypeInfo` and `Rtt`. Again, this should be a non-functional change since `Rtt`s are not used anywhere yet. Subtyping rules and updating the `xref` aliases is left for future work.
Diffstat (limited to 'src')
-rw-r--r--src/wasm-type.h120
-rw-r--r--src/wasm/wasm-type.cpp328
2 files changed, 311 insertions, 137 deletions
diff --git a/src/wasm-type.h b/src/wasm-type.h
index cee8dae03..8a9e58ec9 100644
--- a/src/wasm-type.h
+++ b/src/wasm-type.h
@@ -31,13 +31,6 @@
namespace wasm {
-struct Tuple;
-struct Signature;
-struct Struct;
-struct Array;
-
-typedef std::vector<class Type> 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 `BasicID`
@@ -73,16 +66,14 @@ public:
Type(std::initializer_list<Type>);
// Construct from tuple description
- explicit Type(const Tuple&);
-
- // Construct from signature description
- explicit Type(const Signature, bool nullable);
+ explicit Type(const struct Tuple&);
- // Construct from struct description
- explicit Type(const Struct&, bool nullable);
+ // Construct from a heap type description. Also covers construction from
+ // Signature, Struct or Array via implicit conversion to HeapType.
+ explicit Type(const struct HeapType&, bool nullable);
- // Construct from array description
- explicit Type(const Array&, bool nullable);
+ // Construct from rtt description
+ explicit Type(const struct Rtt&);
// Predicates
// Compound Concrete
@@ -96,16 +87,18 @@ public:
// │ f32 ║ x │ │ x │ x │ F │ │ F_loat
// │ f64 ║ x │ │ x │ x │ F │ │ V_ector
// │ v128 ║ x │ │ x │ x │ V │ ┘
- // ├─────────────╫───┼───┼───┼───┤───────┤
- // │ funcref ║ x │ │ x │ x │ f │ ┐ Ref
- // │ externref ║ x │ │ x │ x │ │ │ f_unc
- // │ nullref ║ x │ │ x │ x │ │ │
- // │ exnref ║ x │ │ x │ x │ │ │
- // ├─────────────╫───┼───┼───┼───┤───────┤ │
- // │ Signature ║ │ x │ x │ x │ f │ │
- // │ Struct ║ │ x │ x │ x │ │ │
- // │ Array ║ │ x │ x │ x │ │ ┘
+ // ├─ Aliases ───╫───┼───┼───┼───┤───────┤
+ // │ funcref ║ x │ │ x │ x │ f n │ ┐ Ref
+ // │ externref ║ x │ │ x │ x │ f? n │ │ f_unc, n_ullable
+ // │ anyref ║ x │ │ x │ x │ f? n │ │ ┐
+ // │ eqref ║ x │ │ x │ x │ n │ │ │ TODO (GC)
+ // │ i31ref ║ x │ │ x │ x │ │ │ ┘
+ // │ nullref ║ x │ │ x │ x │ f? n │ │ ◄ TODO (removed)
+ // │ exnref ║ x │ │ x │ x │ n │ │
+ // ├─ Compound ──╫───┼───┼───┼───┤───────┤ │
+ // │ Ref ║ │ x │ x │ x │ f? n? │◄┘
// │ Tuple ║ │ x │ │ x │ │
+ // │ Rtt ║ │ x │ x │ x │ │
// └─────────────╨───┴───┴───┴───┴───────┘
constexpr bool isBasic() const { return id <= _last_basic_id; }
constexpr bool isCompound() const { return id > _last_basic_id; }
@@ -118,6 +111,7 @@ public:
bool isSingle() const { return isConcrete() && !isTuple(); }
bool isRef() const;
bool isNullable() const;
+ bool isRtt() const;
private:
template<bool (Type::*pred)() const> bool hasPredicate() {
@@ -227,6 +221,8 @@ struct ResultType {
std::string toString() const;
};
+typedef std::vector<Type> TypeList;
+
struct Tuple {
TypeList types;
Tuple() : types() {}
@@ -303,6 +299,72 @@ struct Array {
std::string toString() const;
};
+struct HeapType {
+ enum Kind {
+ FuncKind,
+ ExternKind,
+ AnyKind,
+ EqKind,
+ I31Kind,
+ ExnKind,
+ _last_basic_kind = ExnKind,
+ SignatureKind,
+ StructKind,
+ ArrayKind,
+ } kind;
+ union {
+ Signature signature;
+ Struct struct_;
+ Array array;
+ };
+ HeapType(Kind kind) : kind(kind) { assert(kind <= _last_basic_kind); }
+ HeapType(const Signature& signature)
+ : kind(SignatureKind), signature(signature) {}
+ HeapType(Signature&& signature)
+ : kind(SignatureKind), signature(std::move(signature)) {}
+ HeapType(const Struct& struct_) : kind(StructKind), struct_(struct_) {}
+ HeapType(Struct&& struct_) : kind(StructKind), struct_(std::move(struct_)) {}
+ HeapType(const Array& array) : kind(ArrayKind), array(array) {}
+ HeapType(Array&& array) : kind(ArrayKind), array(std::move(array)) {}
+ HeapType(const HeapType& other);
+ ~HeapType();
+
+ bool isSignature() const { return kind == SignatureKind; }
+ Signature getSignature() const {
+ assert(isSignature() && "Not a signature");
+ return signature;
+ }
+ bool isStruct() const { return kind == StructKind; }
+ Struct getStruct() const {
+ assert(isStruct() && "Not a struct");
+ return struct_;
+ }
+ bool isArray() const { return kind == ArrayKind; }
+ Array getArray() const {
+ assert(isArray() && "Not an array");
+ return array;
+ }
+
+ bool operator==(const HeapType& other) const;
+ bool operator!=(const HeapType& other) const { return !(*this == other); }
+ HeapType& operator=(const HeapType& other);
+ std::string toString() const;
+};
+
+struct Rtt {
+ uint32_t depth;
+ HeapType heapType;
+ Rtt(uint32_t depth, const HeapType& heapType)
+ : depth(depth), heapType(heapType) {}
+ Rtt(uint32_t depth, HeapType&& heapType)
+ : depth(depth), heapType(std::move(heapType)) {}
+ bool operator==(const Rtt& other) const {
+ return depth == other.depth && heapType == other.heapType;
+ }
+ bool operator!=(const Rtt& other) const { return !(*this == other); }
+ std::string toString() const;
+};
+
std::ostream& operator<<(std::ostream&, Type);
std::ostream& operator<<(std::ostream&, ParamType);
std::ostream& operator<<(std::ostream&, ResultType);
@@ -311,6 +373,8 @@ 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&, HeapType);
+std::ostream& operator<<(std::ostream&, Rtt);
} // namespace wasm
@@ -340,6 +404,14 @@ template<> class hash<wasm::Array> {
public:
size_t operator()(const wasm::Array&) const;
};
+template<> class hash<wasm::HeapType> {
+public:
+ size_t operator()(const wasm::HeapType&) const;
+};
+template<> class hash<wasm::Rtt> {
+public:
+ size_t operator()(const wasm::Rtt&) const;
+};
} // namespace std
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp
index 5247ebb6f..e46cb5886 100644
--- a/src/wasm/wasm-type.cpp
+++ b/src/wasm/wasm-type.cpp
@@ -28,48 +28,40 @@
namespace wasm {
struct TypeInfo {
- enum Kind { TupleKind, SignatureRefKind, StructRefKind, ArrayRefKind } kind;
- struct SignatureRef {
- Signature signature;
- bool nullable;
- };
- struct StructRef {
- Struct struct_;
- bool nullable;
- };
- struct ArrayRef {
- Array array;
+ enum Kind {
+ TupleKind,
+ RefKind,
+ RttKind,
+ } kind;
+ struct Ref {
+ HeapType heapType;
bool nullable;
};
union {
Tuple tuple;
- SignatureRef signatureRef;
- StructRef structRef;
- ArrayRef arrayRef;
+ Ref ref;
+ Rtt rtt;
};
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(const Struct& struct_, bool nullable)
- : kind(StructRefKind), structRef{struct_, nullable} {}
- TypeInfo(const Array& array, bool nullable)
- : kind(ArrayRefKind), arrayRef{array, nullable} {}
+ TypeInfo(const HeapType& heapType, bool nullable)
+ : kind(RefKind), ref{heapType, nullable} {}
+ TypeInfo(HeapType&& heapType, bool nullable)
+ : kind(RefKind), ref{std::move(heapType), nullable} {}
+ TypeInfo(const Rtt& rtt) : kind(RttKind), rtt(rtt) {}
+ TypeInfo(Rtt&& rtt) : kind(RttKind), rtt(std::move(rtt)) {}
TypeInfo(const TypeInfo& other) {
kind = other.kind;
switch (kind) {
case TupleKind:
new (&tuple) auto(other.tuple);
return;
- case SignatureRefKind:
- new (&signatureRef) auto(other.signatureRef);
+ case RefKind:
+ new (&ref) auto(other.ref);
return;
- case StructRefKind:
- new (&structRef) auto(other.structRef);
- return;
- case ArrayRefKind:
- new (&arrayRef) auto(other.arrayRef);
+ case RttKind:
+ new (&rtt) auto(other.rtt);
return;
}
WASM_UNREACHABLE("unexpected kind");
@@ -80,16 +72,12 @@ struct TypeInfo {
tuple.~Tuple();
return;
}
- case SignatureRefKind: {
- signatureRef.~SignatureRef();
- return;
- }
- case StructRefKind: {
- structRef.~StructRef();
+ case RefKind: {
+ ref.~Ref();
return;
}
- case ArrayRefKind: {
- arrayRef.~ArrayRef();
+ case RttKind: {
+ rtt.~Rtt();
return;
}
}
@@ -97,23 +85,10 @@ struct TypeInfo {
}
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; }
+ constexpr bool isRef() const { return kind == RefKind; }
+ constexpr bool isRtt() const { return kind == RttKind; }
- 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 isNullable() const { return kind == RefKind && ref.nullable; }
bool operator==(const TypeInfo& other) const {
if (kind != other.kind) {
@@ -122,15 +97,11 @@ struct TypeInfo {
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;
+ case RefKind:
+ return ref.heapType == other.ref.heapType &&
+ ref.nullable == other.ref.nullable;
+ case RttKind:
+ return rtt == other.rtt;
}
WASM_UNREACHABLE("unexpected kind");
}
@@ -180,22 +151,16 @@ public:
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);
+ wasm::rehash(digest, info.tuple);
return digest;
}
- case wasm::TypeInfo::StructRefKind: {
- wasm::rehash(digest, info.structRef.struct_);
- wasm::rehash(digest, info.structRef.nullable);
+ case wasm::TypeInfo::RefKind: {
+ wasm::rehash(digest, info.ref.heapType);
+ wasm::rehash(digest, info.ref.nullable);
return digest;
}
- case wasm::TypeInfo::ArrayRefKind: {
- wasm::rehash(digest, info.arrayRef.array);
- wasm::rehash(digest, info.arrayRef.nullable);
+ case wasm::TypeInfo::RttKind: {
+ wasm::rehash(digest, info.rtt);
return digest;
}
}
@@ -225,15 +190,42 @@ size_t hash<wasm::Field>::operator()(const wasm::Field& field) const {
}
size_t hash<wasm::Struct>::operator()(const wasm::Struct& struct_) const {
- auto digest = wasm::hash(0);
- wasm::rehash(digest, struct_.fields);
- return digest;
+ return wasm::hash(struct_.fields);
}
size_t hash<wasm::Array>::operator()(const wasm::Array& array) const {
return wasm::hash(array.element);
}
+size_t hash<wasm::HeapType>::operator()(const wasm::HeapType& heapType) const {
+ auto digest = wasm::hash(heapType.kind);
+ switch (heapType.kind) {
+ case wasm::HeapType::FuncKind:
+ case wasm::HeapType::ExternKind:
+ case wasm::HeapType::AnyKind:
+ case wasm::HeapType::EqKind:
+ case wasm::HeapType::I31Kind:
+ case wasm::HeapType::ExnKind:
+ return digest;
+ case wasm::HeapType::SignatureKind:
+ wasm::rehash(digest, heapType.signature);
+ return digest;
+ case wasm::HeapType::StructKind:
+ wasm::rehash(digest, heapType.struct_);
+ return digest;
+ case wasm::HeapType::ArrayKind:
+ wasm::rehash(digest, heapType.array);
+ return digest;
+ }
+ WASM_UNREACHABLE("unexpected kind");
+}
+
+size_t hash<wasm::Rtt>::operator()(const wasm::Rtt& rtt) const {
+ auto digest = wasm::hash(rtt.depth);
+ wasm::rehash(digest, rtt.heapType);
+ return digest;
+}
+
} // namespace std
namespace wasm {
@@ -261,9 +253,16 @@ std::unordered_map<TypeInfo, uintptr_t> indices = {
{TypeInfo({Type::f64}), Type::f64},
{TypeInfo({Type::v128}), Type::v128},
{TypeInfo({Type::funcref}), Type::funcref},
+ {TypeInfo(HeapType(HeapType::FuncKind), true), Type::funcref},
{TypeInfo({Type::externref}), Type::externref},
- {TypeInfo({Type::nullref}), Type::nullref},
+ {TypeInfo(HeapType(HeapType::ExternKind), true), Type::externref},
+ // TODO (GC): Add canonical ids
+ // * `(ref null any) == anyref`
+ // * `(ref null eq) == eqref`
+ // * `(ref i31) == i31ref`
+ {TypeInfo({Type::nullref}), Type::nullref}, // TODO (removed)
{TypeInfo({Type::exnref}), Type::exnref},
+ {TypeInfo(HeapType(HeapType::ExnKind), true), Type::exnref},
};
} // anonymous namespace
@@ -306,23 +305,31 @@ Type::Type(const Tuple& tuple) {
id = canonicalize(TypeInfo(tuple));
}
-Type::Type(const Signature signature, bool nullable) {
- id = canonicalize(TypeInfo(signature, nullable));
-}
-
-Type::Type(const Struct& struct_, bool nullable) {
+Type::Type(const HeapType& heapType, bool nullable) {
#ifndef NDEBUG
- for (Field f : struct_.fields) {
- assert(f.type.isSingle());
+ switch (heapType.kind) {
+ case HeapType::FuncKind:
+ case HeapType::ExternKind:
+ case HeapType::AnyKind:
+ case HeapType::EqKind:
+ case HeapType::I31Kind:
+ case HeapType::ExnKind:
+ case HeapType::SignatureKind:
+ break;
+ case HeapType::StructKind:
+ for (Field f : heapType.struct_.fields) {
+ assert(f.type.isSingle());
+ }
+ break;
+ case HeapType::ArrayKind:
+ assert(heapType.array.element.type.isSingle());
+ break;
}
#endif
- id = canonicalize(TypeInfo(struct_, nullable));
+ id = canonicalize(TypeInfo(heapType, nullable));
}
-Type::Type(const Array& array, bool nullable) {
- assert(array.element.type.isSingle());
- id = canonicalize(TypeInfo(array, nullable));
-}
+Type::Type(const Rtt& rtt) { id = canonicalize(TypeInfo(rtt)); }
bool Type::isTuple() const {
if (isBasic()) {
@@ -336,15 +343,7 @@ bool Type::isRef() const {
if (isBasic()) {
return id >= funcref && id <= exnref;
} else {
- switch (getTypeInfo(*this)->kind) {
- case TypeInfo::TupleKind:
- return false;
- case TypeInfo::SignatureRefKind:
- case TypeInfo::StructRefKind:
- case TypeInfo::ArrayRefKind:
- return true;
- }
- WASM_UNREACHABLE("unexpected kind");
+ return getTypeInfo(*this)->isRef();
}
}
@@ -356,6 +355,14 @@ bool Type::isNullable() const {
}
}
+bool Type::isRtt() const {
+ if (isBasic()) {
+ return false;
+ } else {
+ return getTypeInfo(*this)->isRtt();
+ }
+}
+
bool Type::operator<(const Type& other) const {
return std::lexicographical_compare(begin(),
end(),
@@ -547,6 +554,80 @@ const Type& Type::operator[](size_t index) const {
}
}
+HeapType::HeapType(const HeapType& other) {
+ kind = other.kind;
+ switch (kind) {
+ case FuncKind:
+ case ExternKind:
+ case AnyKind:
+ case EqKind:
+ case I31Kind:
+ case ExnKind:
+ return;
+ case SignatureKind:
+ new (&signature) auto(other.signature);
+ return;
+ case StructKind:
+ new (&struct_) auto(other.struct_);
+ return;
+ case ArrayKind:
+ new (&array) auto(other.array);
+ return;
+ }
+ WASM_UNREACHABLE("unexpected kind");
+}
+
+HeapType::~HeapType() {
+ switch (kind) {
+ case FuncKind:
+ case ExternKind:
+ case AnyKind:
+ case EqKind:
+ case I31Kind:
+ case ExnKind:
+ return;
+ case SignatureKind:
+ signature.~Signature();
+ return;
+ case StructKind:
+ struct_.~Struct();
+ return;
+ case ArrayKind:
+ array.~Array();
+ return;
+ }
+}
+
+bool HeapType::operator==(const HeapType& other) const {
+ if (kind != other.kind) {
+ return false;
+ }
+ switch (kind) {
+ case FuncKind:
+ case ExternKind:
+ case AnyKind:
+ case EqKind:
+ case I31Kind:
+ case ExnKind:
+ return true;
+ case SignatureKind:
+ return signature == other.signature;
+ case StructKind:
+ return struct_ == other.struct_;
+ case ArrayKind:
+ return array == other.array;
+ }
+ WASM_UNREACHABLE("unexpected kind");
+}
+
+HeapType& HeapType::operator=(const HeapType& other) {
+ if (&other != this) {
+ this->~HeapType();
+ new (this) auto(other);
+ }
+ return *this;
+}
+
namespace {
std::ostream&
@@ -581,6 +662,10 @@ std::string Struct::toString() const { return genericToString(*this); }
std::string Array::toString() const { return genericToString(*this); }
+std::string HeapType::toString() const { return genericToString(*this); }
+
+std::string Rtt::toString() const { return genericToString(*this); }
+
std::string TypeInfo::toString() const { return genericToString(*this); }
bool Signature::operator<(const Signature& other) const {
@@ -708,31 +793,48 @@ std::ostream& operator<<(std::ostream& os, Array array) {
return os << "(array " << array.element << ")";
}
+std::ostream& operator<<(std::ostream& os, HeapType heapType) {
+ switch (heapType.kind) {
+ case wasm::HeapType::FuncKind:
+ return os << "func";
+ case wasm::HeapType::ExternKind:
+ return os << "extern";
+ case wasm::HeapType::AnyKind:
+ return os << "any";
+ case wasm::HeapType::EqKind:
+ return os << "eq";
+ case wasm::HeapType::I31Kind:
+ return os << "i31";
+ case wasm::HeapType::ExnKind:
+ return os << "exn";
+ case wasm::HeapType::SignatureKind:
+ return os << heapType.signature;
+ case wasm::HeapType::StructKind:
+ return os << heapType.struct_;
+ case wasm::HeapType::ArrayKind:
+ return os << heapType.array;
+ }
+ WASM_UNREACHABLE("unexpected kind");
+}
+
+std::ostream& operator<<(std::ostream& os, Rtt rtt) {
+ return os << "(rtt " << rtt.depth << " " << rtt.heapType << ")";
+}
+
std::ostream& operator<<(std::ostream& os, TypeInfo info) {
switch (info.kind) {
case TypeInfo::TupleKind: {
return os << info.tuple;
}
- case TypeInfo::SignatureRefKind: {
- os << "(ref ";
- if (info.signatureRef.nullable) {
- os << "null ";
- }
- return os << info.signatureRef.signature << ")";
- }
- case TypeInfo::StructRefKind: {
+ case TypeInfo::RefKind: {
os << "(ref ";
- if (info.structRef.nullable) {
+ if (info.ref.nullable) {
os << "null ";
}
- return os << info.structRef.struct_ << ")";
+ return os << info.ref.heapType << ")";
}
- case TypeInfo::ArrayRefKind: {
- os << "(ref ";
- if (info.arrayRef.nullable) {
- os << "null ";
- }
- return os << info.arrayRef.array << ")";
+ case TypeInfo::RttKind: {
+ return os << info.rtt;
}
}
WASM_UNREACHABLE("unexpected kind");