Skip to content

Commit 07e02d2

Browse files
authored
[Custom Descriptors] Fix GTO placeholders for unused types (#7908)
GTO emits placeholder describee types when it optimizes descriptor types that must remain descriptors. However, it previously tried to emit a placeholder describee type even for a descriptor type that is unused in the module and therefore not included in the rebuilt types. These dangling describees caused validation faillures when rebuilding the types. Fix the problem by emitting placeholder describees only for descriptors that will be rebuilt.
1 parent d1f6e2d commit 07e02d2

File tree

2 files changed

+44
-9
lines changed

2 files changed

+44
-9
lines changed

src/passes/GlobalTypeOptimization.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ struct GlobalTypeOptimization : public Pass {
141141
// still need to be descriptors for their own subtypes and supertypes to be
142142
// valid. We will keep them descriptors by having them describe trivial new
143143
// placeholder types.
144-
InsertOrderedMap<HeapType, Index> descriptorsOfPlaceholders;
144+
std::vector<HeapType> descriptorsOfPlaceholders;
145145

146146
void run(Module* module) override {
147147
if (!module->features.hasGC()) {
@@ -473,8 +473,7 @@ struct GlobalTypeOptimization : public Pass {
473473
auto desc = type.getDescribedType();
474474
assert(desc);
475475
if (haveUnneededDescriptors.count(*desc)) {
476-
descriptorsOfPlaceholders.insert(
477-
{type, descriptorsOfPlaceholders.size()});
476+
descriptorsOfPlaceholders.push_back(type);
478477
}
479478
}
480479
}
@@ -498,20 +497,30 @@ struct GlobalTypeOptimization : public Pass {
498497
void updateTypes(Module& wasm) {
499498
class TypeRewriter : public GlobalTypeRewriter {
500499
GlobalTypeOptimization& parent;
500+
InsertOrderedMap<HeapType, Index> placeholderIndices;
501501
InsertOrderedMap<HeapType, Index>::iterator placeholderIt;
502502

503503
public:
504504
TypeRewriter(Module& wasm, GlobalTypeOptimization& parent)
505505
: GlobalTypeRewriter(wasm), parent(parent),
506-
placeholderIt(parent.descriptorsOfPlaceholders.begin()) {}
506+
placeholderIt(placeholderIndices.begin()) {}
507507

508508
std::vector<HeapType> getSortedTypes(PredecessorGraph preds) override {
509509
auto types = GlobalTypeRewriter::getSortedTypes(std::move(preds));
510+
// Some of the descriptors of placeholders may not end up being used at
511+
// all, so we will not rebuild them. Record the used types that need
512+
// placeholder describees and assign them placeholder indices.
513+
std::unordered_set<HeapType> typeSet(types.begin(), types.end());
514+
for (auto desc : parent.descriptorsOfPlaceholders) {
515+
if (typeSet.count(desc)) {
516+
placeholderIndices.insert({desc, placeholderIndices.size()});
517+
}
518+
}
519+
placeholderIt = placeholderIndices.begin();
510520
// Prefix the types with placeholders to be overwritten with the
511521
// placeholder describees.
512522
HeapType placeholder = Struct{};
513-
types.insert(
514-
types.begin(), parent.descriptorsOfPlaceholders.size(), placeholder);
523+
types.insert(types.begin(), placeholderIndices.size(), placeholder);
515524
return types;
516525
}
517526

@@ -577,19 +586,20 @@ struct GlobalTypeOptimization : public Pass {
577586

578587
// Until we've created all the placeholders, create a placeholder
579588
// describee type for the next descriptor that needs one.
580-
if (placeholderIt != parent.descriptorsOfPlaceholders.end()) {
589+
if (placeholderIt != placeholderIndices.end()) {
581590
auto descriptor = placeholderIt->first;
582591
typeBuilder[i].descriptor(getTempHeapType(descriptor));
583592
typeBuilder[i].setShared(descriptor.getShared());
593+
584594
++placeholderIt;
585595
return;
586596
}
587597

588598
// Remove an unneeded describee or describe a placeholder type.
589599
if (auto described = oldType.getDescribedType()) {
590600
if (parent.haveUnneededDescriptors.count(*described)) {
591-
if (auto it = parent.descriptorsOfPlaceholders.find(oldType);
592-
it != parent.descriptorsOfPlaceholders.end()) {
601+
if (auto it = placeholderIndices.find(oldType);
602+
it != placeholderIndices.end()) {
593603
typeBuilder[i].describes(typeBuilder[it->second]);
594604
} else {
595605
typeBuilder[i].describes(std::nullopt);

test/lit/passes/gto-desc.wast

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,8 +1173,33 @@
11731173
)
11741174
)
11751175

1176+
;; Here we would optimize $unused with a placeholder, except that we don't
1177+
;; include it in the output at all because it is unused. We should not get
1178+
;; confused and try to emit a placeholder for it anyway.
1179+
(module
1180+
(rec
1181+
;; CHECK: (rec
1182+
;; CHECK-NEXT: (type $public (sub (descriptor $public.desc (struct))))
1183+
(type $public (sub (descriptor $public.desc (struct))))
1184+
;; CHECK: (type $public.desc (sub (describes $public (struct))))
1185+
(type $public.desc (sub (describes $public (struct))))
1186+
)
1187+
(rec
1188+
(type $unused (descriptor $unused.desc (struct)))
1189+
(type $unused.desc (sub $public.desc (describes $unused (struct))))
1190+
;; CHECK: (type $private (struct))
1191+
(type $private (struct))
1192+
)
1193+
1194+
;; CHECK: (global $public (ref null $public) (ref.null none))
1195+
(global $public (export "public") (ref null $public) (ref.null none))
1196+
;; CHECK: (global $private (ref null $private) (ref.null none))
1197+
(global $private (ref null $private) (ref.null none))
1198+
)
1199+
11761200
;; Sibling types $A and $B. The supertype that connects them should not stop us
11771201
;; from optimizing $B here, even though $A cannot be optimized.
1202+
;; CHECK: (export "public" (global $public))
11781203
(module
11791204
(rec
11801205
;; CHECK: (rec

0 commit comments

Comments
 (0)