Skip to content

Public type mismatch between collectHeapTypeInfo and getPublicHeapTypes #7103

Closed
@kripken

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions