@@ -171,6 +171,9 @@ struct TypeTree {
171171 // The index of the described and descriptor types, if they are necessary.
172172 std::optional<Index> described;
173173 std::optional<Index> descriptor;
174+ // Whether this type might flow out to JS from a JS-called function or via
175+ // extern.convert_any.
176+ bool exposedToJS = false ;
174177
175178 Node (HeapType type, Index index) : type(type), parent(index) {}
176179 };
@@ -248,6 +251,19 @@ struct TypeTree {
248251 return std::nullopt ;
249252 }
250253
254+ void setExposedToJS (HeapType type) {
255+ auto index = getIndex (type);
256+ nodes[index].exposedToJS = true ;
257+ }
258+
259+ bool isExposedToJS (HeapType type) const {
260+ auto index = maybeGetIndex (type);
261+ if (!index) {
262+ return false ;
263+ }
264+ return nodes[*index].exposedToJS ;
265+ }
266+
251267 struct SupertypeIterator {
252268 using value_type = const HeapType;
253269 using difference_type = std::ptrdiff_t ;
@@ -404,6 +420,9 @@ struct TypeTree {
404420 for (auto child : node.children ) {
405421 std::cerr << " " << ModuleHeapType (wasm, nodes[child].type );
406422 }
423+ if (node.exposedToJS ) {
424+ std::cerr << " , exposed to JS" ;
425+ }
407426 std::cerr << ' \n ' ;
408427 }
409428 }
@@ -595,6 +614,15 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
595614 work.push_back ({Kind::Descriptor, described, descriptor});
596615 }
597616
617+ void noteExposedToJS (HeapType type) {
618+ types.setExposedToJS (type);
619+ // Keep any descriptor that may configure a prototype.
620+ if (auto desc = type.getDescriptorType ();
621+ desc && StructUtils::hasPossibleJSPrototypeField (*desc)) {
622+ noteDescriptor (type, *desc);
623+ }
624+ }
625+
598626 void analyzePublicTypes (Module& wasm) {
599627 // We cannot change supertypes for anything public.
600628 for (auto type : ModuleUtils::getPublicHeapTypes (wasm)) {
@@ -625,10 +653,7 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
625653 if (Type::isSubType (type, anyref)) {
626654 auto heapType = type.getHeapType ();
627655 noteSubtype (heapType, HeapType::any);
628- if (auto desc = heapType.getDescriptorType ();
629- desc && StructUtils::hasPossibleJSPrototypeField (*desc)) {
630- noteDescriptor (heapType, *desc);
631- }
656+ noteExposedToJS (heapType);
632657 }
633658 }
634659 }
@@ -644,6 +669,9 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
644669
645670 // Observed (described, descriptor) requirements.
646671 Set<std::pair<HeapType, HeapType>> descriptors;
672+
673+ // Observed externalized types.
674+ Set<HeapType> exposedToJS;
647675 };
648676
649677 struct Collector
@@ -739,6 +767,12 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
739767 // expression is removed.
740768 noteDescribed (curr->type .getHeapType ());
741769 }
770+ void visitRefAs (RefAs* curr) {
771+ Super::visitRefAs (curr);
772+ if (curr->op == ExternConvertAny && curr->value ->type .isRef ()) {
773+ info.exposedToJS .insert (curr->value ->type .getHeapType ());
774+ }
775+ }
742776 };
743777
744778 bool trapsNeverHappen = getPassOptions ().trapsNeverHappen ;
@@ -758,6 +792,8 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
758792 info.subtypings .end ());
759793 collectedInfo.descriptors .insert (info.descriptors .begin (),
760794 info.descriptors .end ());
795+ collectedInfo.exposedToJS .insert (info.exposedToJS .begin (),
796+ info.exposedToJS .end ());
761797 }
762798
763799 // Collect constraints from module-level code as well.
@@ -772,6 +808,9 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
772808 }
773809
774810 // Prepare the collected information for the upcoming processing loop.
811+ for (auto type : collectedInfo.exposedToJS ) {
812+ noteExposedToJS (type);
813+ }
775814 for (auto & [sub, super] : collectedInfo.subtypings ) {
776815 noteSubtype (sub, super);
777816 }
@@ -820,6 +859,11 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
820859
821860 types.setSupertype (sub, super);
822861
862+ // If the supertype is exposed to JS, the subtype potentially is as well.
863+ if (types.isExposedToJS (super)) {
864+ noteExposedToJS (sub);
865+ }
866+
823867 // Complete the descriptor squares to the left and right of the new
824868 // subtyping edge if those squares can possibly exist based on the original
825869 // types.
@@ -948,11 +992,7 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
948992 // Add all the edges. Don't worry about duplicating existing edges because
949993 // checking whether they're necessary now would be about as expensive as
950994 // discarding them later.
951- // TODO: We will be able to assume this once we update the descriptor
952- // validation rules.
953- if (HeapType::isSubType (*sub, *super)) {
954- noteSubtype (*sub, *super);
955- }
995+ noteSubtype (*sub, *super);
956996 noteSubtype (*subDesc, *superDesc);
957997 noteDescriptor (*super, *superDesc);
958998 noteDescriptor (*sub, *subDesc);
0 commit comments