@@ -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,14 @@ 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+ // extern.convert_any makes its operand type visible to JS, which may
773+ // require us to keep descriptors that configure prototypes.
774+ if (curr->op == ExternConvertAny && curr->value ->type .isRef ()) {
775+ info.exposedToJS .insert (curr->value ->type .getHeapType ());
776+ }
777+ }
742778 };
743779
744780 bool trapsNeverHappen = getPassOptions ().trapsNeverHappen ;
@@ -758,6 +794,8 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
758794 info.subtypings .end ());
759795 collectedInfo.descriptors .insert (info.descriptors .begin (),
760796 info.descriptors .end ());
797+ collectedInfo.exposedToJS .insert (info.exposedToJS .begin (),
798+ info.exposedToJS .end ());
761799 }
762800
763801 // Collect constraints from module-level code as well.
@@ -772,6 +810,9 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
772810 }
773811
774812 // Prepare the collected information for the upcoming processing loop.
813+ for (auto type : collectedInfo.exposedToJS ) {
814+ noteExposedToJS (type);
815+ }
775816 for (auto & [sub, super] : collectedInfo.subtypings ) {
776817 noteSubtype (sub, super);
777818 }
@@ -820,6 +861,11 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
820861
821862 types.setSupertype (sub, super);
822863
864+ // If the supertype is exposed to JS, the subtype potentially is as well.
865+ if (types.isExposedToJS (super)) {
866+ noteExposedToJS (sub);
867+ }
868+
823869 // Complete the descriptor squares to the left and right of the new
824870 // subtyping edge if those squares can possibly exist based on the original
825871 // types.
@@ -948,11 +994,7 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
948994 // Add all the edges. Don't worry about duplicating existing edges because
949995 // checking whether they're necessary now would be about as expensive as
950996 // 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- }
997+ noteSubtype (*sub, *super);
956998 noteSubtype (*subDesc, *superDesc);
957999 noteDescriptor (*super, *superDesc);
9581000 noteDescriptor (*sub, *subDesc);
0 commit comments