Skip to content

Public type mismatch between collectHeapTypeInfo and getPublicHeapTypes #7103

Description

@kripken

Testcase:

(module
 (type $1 (sub (struct (field (mut (ref null $1))))))
 (rec
  (type $5 (sub (struct (field (ref func)))))
  (type $6 (sub $1 (struct (field (mut (ref null $1))))))
 )
 (rec
  (type $7 (sub (struct (field (ref $1)))))
  (type $8 (sub (func)))
 )
 (type $9 (sub $6 (struct (field (mut (ref null $1))))))

 (export "func" (func $1))

 (func $1 (result (ref null $8))
  (local $l (ref $9))
  (drop
   (struct.get $5 0
    (struct.new $5
     (ref.func $1)
    )
   )
  )
  (ref.null $8)
 )
)
$ bin/wasm-opt a.wat -all --closed-world --type-refining
Fatal: Internal GlobalTypeRewriter build error: Heap type has an invalid supertype at index 1

Looking into this, it seems like the two APIs mentioned in the title disagree. The pass uses the latter, while GlobalTypeRewriter uses the former, and they disagree on whether $1 is public or not, leading to that error. Here is how I checked that:

diff --git a/src/ir/type-updating.cpp b/src/ir/type-updating.cpp
index 8b74ebfcd..9906615a6 100644
--- a/src/ir/type-updating.cpp
+++ b/src/ir/type-updating.cpp
@@ -38,20 +38,34 @@ GlobalTypeRewriter::TypeMap GlobalTypeRewriter::rebuildTypes(
   const std::vector<HeapType>& additionalPrivateTypes) {
   // Find the heap types that are not publicly observable. Even in a closed
   // world scenario, don't modify public types because we assume that they may
   // be reflected on or used for linking. Figure out where each private type
   // will be located in the builder.
   auto typeInfo = ModuleUtils::collectHeapTypeInfo(
     wasm,
     ModuleUtils::TypeInclusion::UsedIRTypes,
     ModuleUtils::VisibilityHandling::FindVisibility);
 
+  for (auto& [t, info] : typeInfo) {
+    std::cout << "collectHeapTypeInfo: " << wasm.typeNames[t].name << ": " << (info.visibility == ModuleUtils::Visibility::Private ? "private" : "public") << '\n';
+  }
+
+  {
+    auto publicTypes = ModuleUtils::getPublicHeapTypes(wasm);
+    std::unordered_set<HeapType> publicTypesSet(publicTypes.begin(),
+                                                publicTypes.end());
+    for (auto t : publicTypes) {
+      std::cout << "getPublicHeapTypes says this is public: " << wasm.typeNames[t].name << '\n';
+    }
+  }
+
+  assert(additionalPrivateTypes.empty());
   std::unordered_set<HeapType> additionalSet(additionalPrivateTypes.begin(),
                                              additionalPrivateTypes.end());
 
   std::vector<std::pair<HeapType, SmallVector<HeapType, 1>>> privateSupertypes;
   privateSupertypes.reserve(typeInfo.size());
   for (auto& [type, info] : typeInfo) {
     if (info.visibility != ModuleUtils::Visibility::Private &&
         !additionalSet.count(type)) {
       continue;
     }

This prints out

collectHeapTypeInfo: (null Name): public
collectHeapTypeInfo: 9: private
collectHeapTypeInfo: 5: private
collectHeapTypeInfo: 8: public
collectHeapTypeInfo: 1: private
collectHeapTypeInfo: 6: private
getPublicHeapTypes says this is public: (null Name)
getPublicHeapTypes says this is public: 8
getPublicHeapTypes says this is public: 1
getPublicHeapTypes says this is public: 7

So $1 is mismatched.

@tlively in your refactoring of those APIs, I thought one was built on top of the other - how can they disagree?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions