@@ -451,6 +451,8 @@ struct TypeTree {
451451// the final update of data structures is different. This CRTP utility
452452// deduplicates the shared logic.
453453template <typename Self> struct Noter {
454+ DBG (Module* wasm = nullptr );
455+
454456 Self& self () { return *static_cast <Self*>(this ); }
455457
456458 void noteSubtype (HeapType sub, HeapType super) {
@@ -559,8 +561,6 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
559561 // Map from cast source types to their destinations.
560562 Map<HeapType, std::vector<HeapType>> casts;
561563
562- DBG (Module* wasm = nullptr );
563-
564564 void run (Module* wasm) override {
565565 DBG (this ->wasm = wasm);
566566 if (!wasm->features .hasGC ()) {
@@ -574,7 +574,7 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
574574 // Initialize the subtype relation based on what is immediately required to
575575 // keep the code and public types valid.
576576 analyzePublicTypes (*wasm);
577- analyzeJSCalledFunctions (*wasm);
577+ analyzeJSInterface (*wasm);
578578 analyzeModule (*wasm);
579579
580580 // Find further subtypings and iterate to a fixed point.
@@ -635,25 +635,105 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
635635 }
636636 }
637637
638- void analyzeJSCalledFunctions (Module& wasm) {
638+ void analyzeJSInterface (Module& wasm) {
639639 if (!wasm.features .hasCustomDescriptors ()) {
640640 return ;
641641 }
642642 Type anyref (HeapType::any, Nullable);
643- for (auto func : Intrinsics (wasm).getJSCalledFunctions ()) {
644- // Parameter types flow into Wasm and are implicitly cast from any.
645- for (auto type : wasm.getFunction (func)->getParams ()) {
646- if (Type::isSubType (type, anyref)) {
647- noteCast (HeapType::any, type);
643+
644+ // Values flowing in from JS are implicitly cast from any.
645+ auto flowIn = [&](Type type) {
646+ if (Type::isSubType (type, anyref)) {
647+ noteCast (HeapType::any, type);
648+ }
649+ };
650+
651+ // Values flowing out to JS are converted to extern and might come back in
652+ // as anyrefs. Their descriptors may need to be kept to configure JS
653+ // prototypes.
654+ auto flowOut = [&](Type type) {
655+ if (Type::isSubType (type, anyref)) {
656+ auto heapType = type.getHeapType ();
657+ noteSubtype (heapType, HeapType::any);
658+ noteExposedToJS (heapType);
659+ }
660+ };
661+
662+ // @binaryen.js.called functions are called from JS. Their parameters flow
663+ // in from JS and their results flow back out.
664+ for (auto f : Intrinsics (wasm).getJSCalledFunctions ()) {
665+ auto * func = wasm.getFunction (f);
666+ for (auto type : func->getParams ()) {
667+ flowIn (type);
668+ }
669+ for (auto type : func->getResults ()) {
670+ flowOut (type);
671+ }
672+ }
673+
674+ for (auto & ex : wasm.exports ) {
675+ switch (ex->kind ) {
676+ case ExternalKindImpl::Function: {
677+ // Exported functions are also called from JS. Their parameters flow
678+ // in from JS and their result flow back out.
679+ auto * func = wasm.getFunction (*ex->getInternalName ());
680+ for (auto type : func->getParams ()) {
681+ flowIn (type);
682+ }
683+ for (auto type : func->getResults ()) {
684+ flowOut (type);
685+ }
686+ break ;
687+ }
688+ case ExternalKindImpl::Table: {
689+ // Exported tables let values flow in and out.
690+ auto * table = wasm.getTable (*ex->getInternalName ());
691+ flowOut (table->type );
692+ flowIn (table->type );
693+ break ;
694+ }
695+ case ExternalKindImpl::Global: {
696+ // Exported globals let values flow out. Iff they are mutable, they
697+ // also let values flow back in.
698+ auto * global = wasm.getGlobal (*ex->getInternalName ());
699+ flowOut (global->type );
700+ if (global->mutable_ ) {
701+ flowIn (global->type );
702+ }
703+ break ;
704+ }
705+ case ExternalKindImpl::Memory:
706+ case ExternalKindImpl::Tag:
707+ case ExternalKindImpl::Invalid:
708+ break ;
709+ }
710+ }
711+ for (auto & func : wasm.functions ) {
712+ // Imported functions are the opposite of exported functions. Their
713+ // parameters flow out and their results flow in.
714+ if (func->imported ()) {
715+ for (auto type : func->getParams ()) {
716+ flowOut (type);
648717 }
718+ for (auto type : func->getResults ()) {
719+ flowIn (type);
720+ }
721+ }
722+ }
723+ for (auto & table : wasm.tables ) {
724+ // Imported tables, like exported tables, let values flow in and out.
725+ if (table->imported ()) {
726+ flowOut (table->type );
727+ flowIn (table->type );
649728 }
650- for (auto type : wasm.getFunction (func)->getResults ()) {
651- // Result types flow into JS and are implicitly converted from any to
652- // extern. They may also expose configured prototypes that we must keep.
653- if (Type::isSubType (type, anyref)) {
654- auto heapType = type.getHeapType ();
655- noteSubtype (heapType, HeapType::any);
656- noteExposedToJS (heapType);
729+ }
730+ for (auto & global : wasm.globals ) {
731+ // Imported mutable globals let values flow in and out. Imported immutable
732+ // globals imply that values will flow in.
733+ if (global->imported ()) {
734+ flowIn (global->type );
735+ if (global->mutable_ ) {
736+ flowOut (global->type );
657737 }
658738 }
659739 }
@@ -683,8 +763,10 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
683763 Info& info;
684764 bool trapsNeverHappen;
685765
686- Collector (Info& info, bool trapsNeverHappen)
687- : info(info), trapsNeverHappen(trapsNeverHappen) {}
766+ Collector (Info& info, bool trapsNeverHappen, Module* wasm)
767+ : info(info), trapsNeverHappen(trapsNeverHappen) {
768+ DBG (this ->wasm = wasm);
769+ }
688770
689771 void doNoteSubtype (HeapType sub, HeapType super) {
690772 info.subtypings .insert ({sub, super});
@@ -783,7 +865,8 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
783865 ModuleUtils::ParallelFunctionAnalysis<Info> analysis (
784866 wasm, [&](Function* func, Info& info) {
785867 if (!func->imported ()) {
786- Collector (info, trapsNeverHappen).walkFunctionInModule (func, &wasm);
868+ Collector (info, trapsNeverHappen, &wasm)
869+ .walkFunctionInModule (func, &wasm);
787870 }
788871 });
789872
@@ -799,7 +882,7 @@ struct Unsubtyping : Pass, Noter<Unsubtyping> {
799882 }
800883
801884 // Collect constraints from module-level code as well.
802- Collector collector (collectedInfo, trapsNeverHappen);
885+ Collector collector (collectedInfo, trapsNeverHappen, &wasm );
803886 collector.walkModuleCode (&wasm);
804887 collector.setModule (&wasm);
805888 for (auto & global : wasm.globals ) {
0 commit comments