diff --git a/src/literal.h b/src/literal.h index 4d09a5883cb..8b5a8052676 100644 --- a/src/literal.h +++ b/src/literal.h @@ -828,10 +828,19 @@ template<> struct hash { wasm::rehash(digest, a.getFunc()); return digest; } - if (a.type.getHeapType().isMaybeShared(wasm::HeapType::i31)) { + auto type = a.type.getHeapType(); + if (type.isMaybeShared(wasm::HeapType::i31)) { wasm::rehash(digest, a.geti31(true)); return digest; } + if (type.isMaybeShared(wasm::HeapType::any)) { + // This may be an extern string that was internalized to |any|. Undo + // that to get the actual value. (Rehash here with the existing digest, + // which contains the |any| type, so that the final hash takes into + // account the fact that it was internalized.) + wasm::rehash(digest, (*this)(a.externalize())); + return digest; + } if (a.type.isString()) { auto& values = a.getGCData()->values; wasm::rehash(digest, values.size()); @@ -841,7 +850,8 @@ template<> struct hash { return digest; } // other non-null reference type literals cannot represent concrete - // values, i.e. there is no concrete anyref or eqref other than null. + // values, i.e. there is no concrete anyref or eqref other than null and + // internalized strings. WASM_UNREACHABLE("unexpected type"); } WASM_UNREACHABLE("unexpected type"); diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index ad5bf765daf..17c461ceb02 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -493,13 +493,17 @@ bool Literal::operator==(const Literal& other) const { if (type.isData()) { return gcData == other.gcData; } - assert(type.getHeapType().isBasic()); - if (type.getHeapType().isMaybeShared(HeapType::i31)) { + auto heapType = type.getHeapType(); + assert(heapType.isBasic()); + if (heapType.isMaybeShared(HeapType::i31)) { return i32 == other.i32; } - if (type.getHeapType().isMaybeShared(HeapType::ext)) { + if (heapType.isMaybeShared(HeapType::ext)) { return internalize() == other.internalize(); } + if (heapType.isMaybeShared(HeapType::any)) { + return externalize() == other.externalize(); + } WASM_UNREACHABLE("unexpected type"); } WASM_UNREACHABLE("unexpected type"); diff --git a/test/lit/passes/rse-gc.wast b/test/lit/passes/rse-gc.wast index d00f6d3c434..bfe85398e59 100644 --- a/test/lit/passes/rse-gc.wast +++ b/test/lit/passes/rse-gc.wast @@ -303,4 +303,44 @@ (local.get $s) ) ) + + ;; CHECK: (func $any-extern (type $3) + ;; CHECK-NEXT: (local $any anyref) + ;; CHECK-NEXT: (local.set $any + ;; CHECK-NEXT: (any.convert_extern + ;; CHECK-NEXT: (string.const "hello") + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (any.convert_extern + ;; CHECK-NEXT: (string.const "hello") + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $any + ;; CHECK-NEXT: (any.convert_extern + ;; CHECK-NEXT: (string.const "world") + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $any-extern + ;; Test internalized strings. + (local $any anyref) + (local.set $any + (any.convert_extern + (string.const "hello") + ) + ) + ;; This set can turn into a drop, as the value is already in the local. + (local.set $any + (any.convert_extern + (string.const "hello") + ) + ) + ;; This is a different string. + (local.set $any + (any.convert_extern + (string.const "world") + ) + ) + ) )