@@ -79,6 +79,8 @@ struct GlobalStructInference : public Pass {
79
79
// optimizable it will have an entry here, and not if not.
80
80
std::unordered_map<HeapType, std::vector<Name>> typeGlobals;
81
81
82
+ std::unique_ptr<SubTypes> subTypes;
83
+
82
84
void run (Module* module ) override {
83
85
if (!module ->features .hasGC ()) {
84
86
return ;
@@ -208,6 +210,12 @@ struct GlobalStructInference : public Pass {
208
210
return ;
209
211
}
210
212
213
+ // When CD is enabled, we can optimize to ref.get_desc, depending on the
214
+ // presence of subtypes.
215
+ if (module ->features .hasCustomDescriptors ()) {
216
+ subTypes = std::make_unique<SubTypes>(*module );
217
+ }
218
+
211
219
// The above loop on typeGlobalsCopy is on an unsorted data structure, and
212
220
// that can lead to nondeterminism in typeGlobals. Sort the vectors there to
213
221
// ensure determinism.
@@ -528,6 +536,53 @@ struct GlobalStructInference : public Pass {
528
536
right));
529
537
}
530
538
539
+ void visitRefCast (RefCast* curr) {
540
+ // When we see (ref.cast $T), and the type has a descriptor, and that
541
+ // desceriptor only has a single global, then we can do (ref.cast_desc)
542
+ // using the descriptor. Descriptor XXX
543
+ // casts are usually more efficient than normal ones (and even more so
544
+ // if we get lucky and are in a loop, where the global.get of the
545
+ // descriptor can be hoisted).
546
+
547
+ // Check if we have a descriptor.
548
+ auto type = curr->type ;
549
+ if (type == Type::unreachable) {
550
+ return ;
551
+ }
552
+ auto heapType = type.getHeapType ();
553
+ auto desc = heapType.getDescriptorType ();
554
+ if (!desc) {
555
+ return ;
556
+ }
557
+
558
+ // Check if the type has no subtypes, as a ref.cast_desc will find
559
+ // precisely that type and nothing else.
560
+ if (!parent.subTypes ->getStrictSubTypes (heapType).empty ()) {
561
+ return ;
562
+ }
563
+
564
+ // Check if we have a single global for the descriptor.
565
+ auto iter = parent.typeGlobals .find (*desc);
566
+ if (iter == parent.typeGlobals .end ()) {
567
+ return ;
568
+ }
569
+ const auto & globals = iter->second ;
570
+ if (globals.size () != 1 ) {
571
+ return ;
572
+ }
573
+
574
+ // We can optimize!
575
+ auto global = globals[0 ];
576
+ auto & wasm = *getModule ();
577
+ Builder builder (wasm);
578
+ auto * getGlobal =
579
+ builder.makeGlobalGet (global, wasm.getGlobal (global)->type );
580
+ auto * castDesc = builder.makeRefCast (curr->ref , getGlobal, curr->type );
581
+ replaceCurrent (castDesc);
582
+
583
+ // TODO nullable cast?
584
+ }
585
+
531
586
void visitFunction (Function* func) {
532
587
if (refinalize) {
533
588
ReFinalize ().walkFunctionInModule (func, getModule ());
0 commit comments