#ifndef wasm_wasm_type_h
#define wasm_wasm_type_h
#include "wasm-features.h"
#include <ostream>
#include <vector>
#define TODO_SINGLE_COMPOUND(type) \
assert(!type.isTuple() && "Unexpected tuple type"); \
assert(!type.isCompound() && "TODO: handle compound types");
namespace wasm {
class Type {
uintptr_t id;
public:
enum BasicID : uint32_t {
none,
unreachable,
i32,
i64,
f32,
f64,
v128,
funcref,
externref,
exnref,
anyref,
eqref,
i31ref,
_last_basic_id = i31ref,
};
Type() = default;
constexpr Type(BasicID id) : id(id){};
explicit Type(uint64_t id) : id(id){};
Type(std::initializer_list<Type>);
explicit Type(const struct Tuple&);
explicit Type(const struct HeapType&, bool nullable);
explicit Type(const struct Rtt&);
constexpr bool isBasic() const { return id <= _last_basic_id; }
constexpr bool isCompound() const { return 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; }
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 isRef() const;
bool isFunction() const;
bool isException() const;
bool isNullable() const;
bool isRtt() const;
private:
template<bool (Type::*pred)() const> bool hasPredicate() {
for (const auto& type : *this) {
if ((type.*pred)()) {
return true;
}
}
return false;
}
public:
bool hasVector() { return hasPredicate<&Type::isVector>(); }
bool hasRef() { return hasPredicate<&Type::isRef>(); }
constexpr uint64_t getID() const { return id; }
constexpr BasicID getBasic() const {
assert(isBasic() && "Basic type expected");
return static_cast<BasicID>(id);
}
bool operator==(const Type& other) const { return id == other.id; }
bool operator==(const BasicID& otherId) const { return id == otherId; }
bool operator!=(const Type& other) const { return id != other.id; }
bool operator!=(const BasicID& otherId) const { return id != otherId; }
bool operator<(const Type& other) const;
unsigned getByteSize() const;
Type reinterpret() const;
FeatureSet getFeatures() const;
HeapType getHeapType() const;
static Type get(unsigned byteSize, bool float_);
static bool isSubType(Type left, Type right);
static Type getLeastUpperBound(Type a, Type b);
template<typename T> static Type mergeTypes(const T& types) {
Type type = Type::unreachable;
for (auto other : types) {
type = Type::getLeastUpperBound(type, other);
}
return type;
}
std::string toString() const;
struct Iterator
: std::iterator<std::random_access_iterator_tag, Type, long, Type*, Type&> {
const Type* parent;
size_t index;
Iterator(const Type* parent, size_t index) : parent(parent), index(index) {}
bool operator==(const Iterator& other) const {
return index == other.index && parent == other.parent;
}
bool operator!=(const Iterator& other) const { return !(*this == other); }
Iterator& operator++() {
++index;
return *this;
}
Iterator& operator--() {
--index;
return *this;
}
Iterator operator++(int) {
auto it = *this;
index++;
return it;
}
Iterator operator--(int) {
auto it = *this;
index--;
return it;
}
Iterator& operator+=(difference_type off) {
index += off;
return *this;
}
Iterator operator+(difference_type off) const {
return Iterator(*this) += off;
}
Iterator& operator-=(difference_type off) {
index -= off;
return *this;
}
Iterator operator-(difference_type off) const {
return Iterator(*this) -= off;
}
difference_type operator-(const Iterator& other) const {
assert(parent == other.parent);
return index - other.index;
}
const value_type& operator*() const;
};
Iterator begin() const { return Iterator(this, 0); }
Iterator end() const;
size_t size() const { return end() - begin(); }
const Type& operator[](size_t i) const;
};
struct ParamType {
Type type;
ParamType(Type type) : type(type) {}
std::string toString() const;
};
struct ResultType {
Type type;
ResultType(Type type) : type(type) {}
std::string toString() const;
};
typedef std::vector<Type> TypeList;
struct Tuple {
TypeList types;
Tuple() : types() {}
Tuple(std::initializer_list<Type> 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;
};
struct Signature {
Type params;
Type results;
Signature() : params(Type::none), results(Type::none) {}
Signature(Type params, Type results) : params(params), results(results) {}
bool operator==(const Signature& other) const {
return params == other.params && results == other.results;
}
bool operator!=(const Signature& other) const { return !(*this == other); }
bool operator<(const Signature& other) const;
std::string toString() const;
};
struct Field {
Type type;
enum PackedType {
not_packed,
i8,
i16,
} packedType; bool mutable_;
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_) {}
constexpr bool isPacked() const {
if (packedType != not_packed) {
assert(type == Type::i32 && "unexpected type");
return true;
}
return false;
}
bool operator==(const Field& other) const {
return type == other.type && packedType == other.packedType &&
mutable_ == other.mutable_;
}
bool operator!=(const Field& other) const { return !(*this == other); }
std::string toString() const;
};
typedef std::vector<Field> FieldList;
struct Struct {
FieldList fields;
Struct(const Struct& other) : fields(other.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;
};
struct Array {
Field element;
Array(const Array& other) : element(other.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;
};
struct HeapType {
enum Kind {
FuncKind,
ExternKind,
ExnKind,
AnyKind,
EqKind,
I31Kind,
_last_basic_kind = I31Kind,
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 isException() const { return kind == ExnKind; }
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);
std::ostream& operator<<(std::ostream&, Tuple);
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 std {
template<> class hash<wasm::Type> {
public:
size_t operator()(const wasm::Type&) const;
};
template<> class hash<wasm::Tuple> {
public:
size_t operator()(const wasm::Tuple&) const;
};
template<> class hash<wasm::Signature> {
public:
size_t operator()(const wasm::Signature&) const;
};
template<> class hash<wasm::Field> {
public:
size_t operator()(const wasm::Field&) const;
};
template<> class hash<wasm::Struct> {
public:
size_t operator()(const wasm::Struct&) const;
};
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;
};
}
#endif