@@ -430,93 +430,114 @@ class DynamicModuleInfo {
430430 b.global_set (moduleIdGlobal);
431431 }
432432
433- void _initializeCallableReferences () {
434- void collectCallableReference (Reference reference) {
435- final member = reference.asMember;
433+ bool _isClassDynamicModuleInstantiable (Class cls) {
434+ return cls.isDynamicModuleExtendable (translator.coreTypes) ||
435+ cls.constructors
436+ .any ((e) => e.isDynamicModuleCallable (translator.coreTypes)) ||
437+ cls.procedures.any ((e) =>
438+ e.isFactory && e.isDynamicModuleCallable (translator.coreTypes));
439+ }
436440
437- if (member.isExternal) {
438- final isGeneratedIntrinsic = member is Procedure &&
439- MemberIntrinsic .fromProcedure (translator.coreTypes, member) != null ;
440- if (! isGeneratedIntrinsic) return ;
441+ void _initializeCallableReferences () {
442+ for (final lib in translator.component.libraries) {
443+ for (final member in lib.members) {
444+ if (! member.isDynamicModuleCallable (translator.coreTypes)) continue ;
445+ _forEachMemberReference (member, _registerStaticCallableTarget);
441446 }
447+ }
442448
443- if (! member.isInstanceMember) {
444- // Generate static members immediately since they are unconditionally
445- // callable.
446- metadata.callableReferenceIds[reference] ?? =
447- metadata.callableReferenceIds.length;
448- translator.functions.getFunction (reference);
449- return ;
450- }
449+ for (final classInfo in translator.classesSupersFirst) {
450+ final cls = classInfo.cls;
451+ if (cls == null ) continue ;
451452
452- final selector = translator.dispatchTable.selectorForTarget (reference);
453- final targetRanges = selector
454- .targets (unchecked: false )
455- .targetRanges
456- .followedBy (selector.targets (unchecked: true ).targetRanges);
457- // Record usage of the target on all classes that inherit the member. The
458- // class must be allocated in order for the target to be live.
459- for (final (: range, : target) in targetRanges) {
460- // Match any reference for the callable member, even if the reference
461- // kind is not the same.
462- if (target.asMember != member) continue ;
463- metadata.callableReferenceIds[target] ?? =
464- metadata.callableReferenceIds.length;
465- for (int classId = range.start; classId <= range.end; ++ classId) {
466- translator.functions.recordClassTargetUse (classId, target);
453+ // Register any callable functions defined within this class.
454+ for (final member in cls.members) {
455+ if (! member.isDynamicModuleCallable (translator.coreTypes)) continue ;
456+
457+ if (! member.isInstanceMember) {
458+ // Generate static members immediately since they are unconditionally
459+ // callable.
460+ _forEachMemberReference (member, _registerStaticCallableTarget);
461+ continue ;
467462 }
468- }
469- }
470463
471- void collectCallableReferences (Member member) {
472- if (member is Procedure ) {
473- collectCallableReference (member.reference);
474- // We ignore the tear-off and let each dynamic module generate it for
475- // itself.
476- } else if (member is Field ) {
477- collectCallableReference (member.getterReference);
478- if (member.hasSetter) {
479- collectCallableReference (member.setterReference! );
464+ // Consider callable references invoked and therefore if they're
465+ // overrideable include them in the runtime dispatch table.
466+ if (member.isDynamicModuleOverrideable (translator.coreTypes)) {
467+ _forEachMemberReference (
468+ member, metadata.invokedOverrideableReferences.add);
480469 }
481- } else if (member is Constructor &&
482- // Skip types that don't extend Object in the wasm type hierarchy.
483- // These types do not have directly invokable constructors.
484- translator.classInfo[member.enclosingClass]! .struct
485- .isSubtypeOf (translator.objectInfo.struct)) {
486- collectCallableReference (member.reference);
487- collectCallableReference (member.initializerReference);
488- collectCallableReference (member.constructorBodyReference);
489470 }
490- }
491471
492- for (final lib in translator.component.libraries) {
493- for (final member in lib.members) {
494- if (member.isDynamicModuleCallable (translator.coreTypes)) {
495- collectCallableReferences (member);
496- }
472+ // Anonymous mixins' targets don't need to be registered since they aren't
473+ // directly allocatable.
474+ if (cls.isAnonymousMixin) continue ;
475+
476+ if (cls.isAbstract && ! _isClassDynamicModuleInstantiable (cls)) {
477+ continue ;
497478 }
498479
499- for (final cls in lib.classes) {
500- for (final member in cls.members) {
501- if (member.isDynamicModuleCallable (translator.coreTypes)) {
502- collectCallableReferences (member);
503- }
504- }
480+ // For each dispatch target, register the member as callable from this
481+ // class.
482+ final targets = translator.hierarchy.getDispatchTargets (cls).followedBy (
483+ translator.hierarchy.getDispatchTargets (cls, setters: true ));
484+ for (final member in targets) {
485+ if (! member.isDynamicModuleCallable (translator.coreTypes)) continue ;
486+
487+ _forEachMemberReference (member,
488+ (reference) => _registerCallableDispatchTarget (reference, cls));
505489 }
506490 }
507491 }
508492
493+ /// If class [cls] is marked allocated then ensure we compile [target] .
494+ ///
495+ /// The [cls] may be marked allocated in
496+ /// [_initializeDynamicAllocatableClasses] which (together with this) will
497+ /// enqueue the [target] for compilation. Otherwise the [cls] must be
498+ /// allocated via a constructor call in the program itself.
499+ void _registerCallableDispatchTarget (Reference target, Class cls) {
500+ final member = target.asMember;
501+
502+ if (member.isExternal) {
503+ final isGeneratedIntrinsic = member is Procedure &&
504+ MemberIntrinsic .fromProcedure (translator.coreTypes, member) != null ;
505+ if (! isGeneratedIntrinsic) return ;
506+ }
507+
508+ final classId =
509+ (translator.classInfo[cls]! .classId as AbsoluteClassId ).value;
510+
511+ metadata.callableReferenceIds[target] ?? =
512+ metadata.callableReferenceIds.length;
513+ // The class must be allocated in order for the target to be live.
514+ translator.functions.recordClassTargetUse (classId, target);
515+ }
516+
517+ void _registerStaticCallableTarget (Reference target) {
518+ final member = target.asMember;
519+
520+ if (member.isExternal) {
521+ final isGeneratedIntrinsic = member is Procedure &&
522+ MemberIntrinsic .fromProcedure (translator.coreTypes, member) != null ;
523+ if (! isGeneratedIntrinsic) return ;
524+ }
525+
526+ // Generate static members immediately since they are unconditionally
527+ // callable.
528+ metadata.callableReferenceIds[target] ?? =
529+ metadata.callableReferenceIds.length;
530+ translator.functions.getFunction (target);
531+ }
532+
509533 void _initializeDynamicAllocatableClasses () {
510- for (final lib in translator.component.libraries) {
511- for (final cls in lib.classes) {
512- if (cls.isAnonymousMixin) continue ;
513-
514- if (cls.isDynamicModuleExtendable (translator.coreTypes) ||
515- cls.constructors
516- .any ((e) => e.isDynamicModuleCallable (translator.coreTypes))) {
517- translator.functions
518- .recordClassAllocation (translator.classInfo[cls]! .classId);
519- }
534+ for (final classInfo in translator.classesSupersFirst) {
535+ final cls = classInfo.cls;
536+ if (cls == null ) continue ;
537+ if (cls.isAnonymousMixin) continue ;
538+
539+ if (_isClassDynamicModuleInstantiable (cls)) {
540+ translator.functions.recordClassAllocation (classInfo.classId);
520541 }
521542 }
522543 }
@@ -529,11 +550,12 @@ class DynamicModuleInfo {
529550 name: '#r_${builtin .name }' );
530551 }
531552
532- for (final reference in metadata.invokedReferences ) {
553+ for (final reference in metadata.invokedOverrideableReferences ) {
533554 final selector = translator.dispatchTable.selectorForTarget (reference);
534555 translator.functions.recordSelectorUse (selector, false );
535556
536- final mainSelector = translator.dynamicMainModuleDispatchTable!
557+ final mainSelector = (translator.dynamicMainModuleDispatchTable ??
558+ translator.dispatchTable)
537559 .selectorForTarget (reference);
538560 final signature = _getGeneralizedSignature (mainSelector);
539561 final buildMain = buildSelectorBranch (reference, mainSelector);
@@ -547,6 +569,39 @@ class DynamicModuleInfo {
547569 }
548570 }
549571
572+ void _forEachMemberReference (Member member, void Function (Reference ) f) {
573+ void passReference (Reference reference) {
574+ final checkedReference =
575+ translator.getFunctionEntry (reference, uncheckedEntry: false );
576+ f (checkedReference);
577+
578+ final uncheckedReference =
579+ translator.getFunctionEntry (reference, uncheckedEntry: true );
580+ if (uncheckedReference != checkedReference) {
581+ f (uncheckedReference);
582+ }
583+ }
584+
585+ if (member is Procedure ) {
586+ passReference (member.reference);
587+ // We ignore the tear-off and let each dynamic module generate it for
588+ // itself.
589+ } else if (member is Field ) {
590+ passReference (member.getterReference);
591+ if (member.hasSetter) {
592+ passReference (member.setterReference! );
593+ }
594+ } else if (member is Constructor &&
595+ // Skip types that don't extend Object in the wasm type hierarchy.
596+ // These types do not have directly invokable constructors.
597+ translator.classInfo[member.enclosingClass]! .struct
598+ .isSubtypeOf (translator.objectInfo.struct)) {
599+ passReference (member.reference);
600+ passReference (member.initializerReference);
601+ passReference (member.constructorBodyReference);
602+ }
603+ }
604+
550605 void finishDynamicModule () {
551606 _registerModuleRefs (
552607 isDynamicModule ? initFunction.body : translator.initFunction.body);
@@ -776,7 +831,7 @@ class DynamicModuleInfo {
776831 void callOverrideableDispatch (
777832 w.InstructionsBuilder b, SelectorInfo selector, Reference interfaceTarget,
778833 {required bool useUncheckedEntry}) {
779- metadata.invokedReferences .add (interfaceTarget);
834+ metadata.invokedOverrideableReferences .add (interfaceTarget);
780835
781836 final localSignature = selector.signature;
782837 // If any input is not a RefType (i.e. it's an unboxed value) then wrap it
0 commit comments