diff options
-rw-r--r-- | src/literal.h | 67 | ||||
-rw-r--r-- | src/wasm/literal.cpp | 73 |
2 files changed, 107 insertions, 33 deletions
diff --git a/src/literal.h b/src/literal.h index ce245d940..c0e43eb88 100644 --- a/src/literal.h +++ b/src/literal.h @@ -215,6 +215,7 @@ public: int64_t getInteger() const; uint64_t getUnsigned() const; double getFloat() const; + // Obtains the bits of a basic value typed literal. void getBits(uint8_t (&buf)[16]) const; // Equality checks for the type and the bits, so a nan float would // be compared bitwise (which means that a Literal containing a nan @@ -562,14 +563,66 @@ std::ostream& operator<<(std::ostream& o, const ExceptionPackage& exn); namespace std { template<> struct hash<wasm::Literal> { size_t operator()(const wasm::Literal& a) const { - uint8_t bytes[16]; - a.getBits(bytes); - int64_t chunks[2]; - memcpy(chunks, bytes, sizeof(chunks)); auto digest = wasm::hash(a.type.getID()); - wasm::rehash(digest, chunks[0]); - wasm::rehash(digest, chunks[1]); - return digest; + auto hashRef = [&]() { + assert(a.type.isRef()); + if (a.isNull()) { + return digest; + } + if (a.type.isFunction()) { + wasm::rehash(digest, a.getFunc()); + return digest; + } + if (a.type.isException()) { + auto exn = a.getExceptionPackage(); + wasm::rehash(digest, exn.event); + wasm::rehash(digest, exn.values); + return digest; + } + // other non-null reference type literals cannot represent concrete + // values, i.e. there is no concrete externref, anyref or eqref other than + // null. + WASM_UNREACHABLE("unexpected type"); + }; + if (a.type.isBasic()) { + switch (a.type.getBasic()) { + case wasm::Type::i32: + wasm::rehash(digest, a.geti32()); + return digest; + case wasm::Type::f32: + wasm::rehash(digest, a.reinterpreti32()); + return digest; + case wasm::Type::i64: + wasm::rehash(digest, a.geti64()); + return digest; + case wasm::Type::f64: + wasm::rehash(digest, a.reinterpreti64()); + return digest; + case wasm::Type::v128: + uint64_t chunks[2]; + memcpy(&chunks, a.getv128Ptr(), 16); + wasm::rehash(digest, chunks[0]); + wasm::rehash(digest, chunks[1]); + return digest; + case wasm::Type::funcref: + case wasm::Type::externref: + case wasm::Type::exnref: + case wasm::Type::anyref: + case wasm::Type::eqref: + return hashRef(); + case wasm::Type::i31ref: + wasm::rehash(digest, a.geti31(true)); + return digest; + case wasm::Type::none: + case wasm::Type::unreachable: + break; + } + } else if (a.type.isRef()) { + return hashRef(); + } else if (a.type.isRtt()) { + WASM_UNREACHABLE("TODO: rtt literals"); + } + WASM_UNREACHABLE("unexpected type"); } }; template<> struct hash<wasm::Literals> { diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 6b63d2ca5..a7c14fdb6 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -220,11 +220,9 @@ double Literal::getFloat() const { void Literal::getBits(uint8_t (&buf)[16]) const { memset(buf, 0, 16); - TODO_SINGLE_COMPOUND(type); switch (type.getBasic()) { case Type::i32: case Type::f32: - case Type::i31ref: memcpy(buf, &i32, sizeof(i32)); break; case Type::i64: @@ -234,19 +232,14 @@ void Literal::getBits(uint8_t (&buf)[16]) const { case Type::v128: memcpy(buf, &v128, sizeof(v128)); break; - // TODO: investigate changing bits returned for reference types. currently, - // `null` values and even non-`null` functions return all zeroes, but only - // to avoid introducing a functional change. + case Type::none: + case Type::unreachable: case Type::funcref: - break; case Type::externref: case Type::exnref: case Type::anyref: case Type::eqref: - assert(isNull() && "unexpected non-null reference type literal"); - break; - case Type::none: - case Type::unreachable: + case Type::i31ref: WASM_UNREACHABLE("invalid type"); } } @@ -255,23 +248,51 @@ bool Literal::operator==(const Literal& other) const { if (type != other.type) { return false; } - if (type == Type::none) { - return true; - } - if (isNull() || other.isNull()) { - return isNull() == other.isNull(); - } - if (type.isFunction()) { - return func == other.func; - } - if (type.isException()) { - assert(exn != nullptr && other.exn != nullptr); - return *exn == *other.exn; + auto compareRef = [&]() { + assert(type.isRef()); + if (isNull() || other.isNull()) { + return isNull() == other.isNull(); + } + if (type.isFunction()) { + assert(func.is() && other.func.is()); + return func == other.func; + } + if (type.isException()) { + assert(exn != nullptr && other.exn != nullptr); + return *exn == *other.exn; + } + // other non-null reference type literals cannot represent concrete values, + // i.e. there is no concrete externref, anyref or eqref other than null. + WASM_UNREACHABLE("unexpected type"); + }; + if (type.isBasic()) { + switch (type.getBasic()) { + case Type::none: + return true; // special voided literal + case Type::i32: + case Type::f32: + case Type::i31ref: + return i32 == other.i32; + case Type::i64: + case Type::f64: + return i64 == other.i64; + case Type::v128: + return memcmp(v128, other.v128, 16) == 0; + case Type::funcref: + case Type::externref: + case Type::exnref: + case Type::anyref: + case Type::eqref: + return compareRef(); + case Type::unreachable: + break; + } + } else if (type.isRef()) { + return compareRef(); + } else if (type.isRtt()) { + WASM_UNREACHABLE("TODO: rtt literals"); } - uint8_t bits[16], other_bits[16]; - getBits(bits); - other.getBits(other_bits); - return memcmp(bits, other_bits, 16) == 0; + WASM_UNREACHABLE("unexpected type"); } bool Literal::operator!=(const Literal& other) const { |