Skip to content

Commit d8ec1e0

Browse files
authored
Properly hash and compare internalized strings (#8081)
Such Literals were not handled, crashing the RSE pass.
1 parent f03355b commit d8ec1e0

File tree

3 files changed

+59
-5
lines changed

3 files changed

+59
-5
lines changed

src/literal.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -828,10 +828,19 @@ template<> struct hash<wasm::Literal> {
828828
wasm::rehash(digest, a.getFunc());
829829
return digest;
830830
}
831-
if (a.type.getHeapType().isMaybeShared(wasm::HeapType::i31)) {
831+
auto type = a.type.getHeapType();
832+
if (type.isMaybeShared(wasm::HeapType::i31)) {
832833
wasm::rehash(digest, a.geti31(true));
833834
return digest;
834835
}
836+
if (type.isMaybeShared(wasm::HeapType::any)) {
837+
// This may be an extern string that was internalized to |any|. Undo
838+
// that to get the actual value. (Rehash here with the existing digest,
839+
// which contains the |any| type, so that the final hash takes into
840+
// account the fact that it was internalized.)
841+
wasm::rehash(digest, (*this)(a.externalize()));
842+
return digest;
843+
}
835844
if (a.type.isString()) {
836845
auto& values = a.getGCData()->values;
837846
wasm::rehash(digest, values.size());
@@ -841,7 +850,8 @@ template<> struct hash<wasm::Literal> {
841850
return digest;
842851
}
843852
// other non-null reference type literals cannot represent concrete
844-
// values, i.e. there is no concrete anyref or eqref other than null.
853+
// values, i.e. there is no concrete anyref or eqref other than null and
854+
// internalized strings.
845855
WASM_UNREACHABLE("unexpected type");
846856
}
847857
WASM_UNREACHABLE("unexpected type");

src/wasm/literal.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -493,13 +493,17 @@ bool Literal::operator==(const Literal& other) const {
493493
if (type.isData()) {
494494
return gcData == other.gcData;
495495
}
496-
assert(type.getHeapType().isBasic());
497-
if (type.getHeapType().isMaybeShared(HeapType::i31)) {
496+
auto heapType = type.getHeapType();
497+
assert(heapType.isBasic());
498+
if (heapType.isMaybeShared(HeapType::i31)) {
498499
return i32 == other.i32;
499500
}
500-
if (type.getHeapType().isMaybeShared(HeapType::ext)) {
501+
if (heapType.isMaybeShared(HeapType::ext)) {
501502
return internalize() == other.internalize();
502503
}
504+
if (heapType.isMaybeShared(HeapType::any)) {
505+
return externalize() == other.externalize();
506+
}
503507
WASM_UNREACHABLE("unexpected type");
504508
}
505509
WASM_UNREACHABLE("unexpected type");

test/lit/passes/rse-gc.wast

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,4 +303,44 @@
303303
(local.get $s)
304304
)
305305
)
306+
307+
;; CHECK: (func $any-extern (type $3)
308+
;; CHECK-NEXT: (local $any anyref)
309+
;; CHECK-NEXT: (local.set $any
310+
;; CHECK-NEXT: (any.convert_extern
311+
;; CHECK-NEXT: (string.const "hello")
312+
;; CHECK-NEXT: )
313+
;; CHECK-NEXT: )
314+
;; CHECK-NEXT: (drop
315+
;; CHECK-NEXT: (any.convert_extern
316+
;; CHECK-NEXT: (string.const "hello")
317+
;; CHECK-NEXT: )
318+
;; CHECK-NEXT: )
319+
;; CHECK-NEXT: (local.set $any
320+
;; CHECK-NEXT: (any.convert_extern
321+
;; CHECK-NEXT: (string.const "world")
322+
;; CHECK-NEXT: )
323+
;; CHECK-NEXT: )
324+
;; CHECK-NEXT: )
325+
(func $any-extern
326+
;; Test internalized strings.
327+
(local $any anyref)
328+
(local.set $any
329+
(any.convert_extern
330+
(string.const "hello")
331+
)
332+
)
333+
;; This set can turn into a drop, as the value is already in the local.
334+
(local.set $any
335+
(any.convert_extern
336+
(string.const "hello")
337+
)
338+
)
339+
;; This is a different string.
340+
(local.set $any
341+
(any.convert_extern
342+
(string.const "world")
343+
)
344+
)
345+
)
306346
)

0 commit comments

Comments
 (0)