[dart2js] Add member applies to sets and builder.
Will be used during call hierarchy analysis in combination with explicit call graph construction.
Currently typemasks do not support the `difference` operation and so we cannot fully narrow the type cones based on the call hierarchy. An implementation is included here of the applies-to set with subtraction of overrides.
Change-Id: I3f6c113787a4d26e9751added482791365c12832
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/259560
Reviewed-by: Mayank Patke <fishythefish@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
diff --git a/pkg/compiler/lib/src/call_graph/applies_to.dart b/pkg/compiler/lib/src/call_graph/applies_to.dart
new file mode 100644
index 0000000..74b49ed
--- /dev/null
+++ b/pkg/compiler/lib/src/call_graph/applies_to.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:compiler/src/common/names.dart';
+import 'package:compiler/src/elements/entities.dart';
+import 'package:compiler/src/inferrer/abstract_value_domain.dart';
+import 'package:compiler/src/world_interfaces.dart';
+import 'package:compiler/src/universe/selector.dart';
+
+class MemberAppliesTo {
+ final MemberEntity member;
+ AbstractValue mask;
+
+ MemberAppliesTo(this.member, this.mask);
+
+ @override
+ String toString() => 'MemberAppliesTo($member:$mask)';
+}
+
+class MemberAppliesToBuilder {
+ final JClosedWorld _closedWorld;
+ final Map<Selector, Iterable<MemberAppliesTo>> _memberSetsBySelector = {};
+ final Map<Selector, List<MemberEntity>> _membersBySelector = {};
+
+ MemberAppliesToBuilder(this._closedWorld) {
+ for (final member in _closedWorld.liveInstanceMembers) {
+ if (member.isFunction || member.isGetter || member.isSetter) {
+ (_membersBySelector[Selector.fromElement(member)] ??= []).add(member);
+ }
+ }
+ }
+
+ Iterable<MemberAppliesTo> _buildSets(Selector selector) {
+ final List<MemberAppliesTo> memberSets = [];
+ final members = _membersBySelector.remove(selector);
+ if (members == null) {
+ return selector == Selectors.noSuchMethod_
+ ? const []
+ : forSelector(Selectors.noSuchMethod_);
+ }
+ for (final member in members) {
+ // TODO(fishythefish): Use type cone mask here.
+ final mask = _closedWorld.abstractValueDomain
+ .createNonNullSubclass(member.enclosingClass!);
+ final memberSet = MemberAppliesTo(member, mask);
+ memberSets.add(memberSet);
+ }
+ return memberSets;
+ }
+
+ Iterable<MemberAppliesTo> forSelector(Selector selector) =>
+ _memberSetsBySelector[selector] ??= _buildSets(selector);
+}
diff --git a/pkg/compiler/lib/src/js_model/js_world.dart b/pkg/compiler/lib/src/js_model/js_world.dart
index 7f0bb7b..0e949b5 100644
--- a/pkg/compiler/lib/src/js_model/js_world.dart
+++ b/pkg/compiler/lib/src/js_model/js_world.dart
@@ -65,6 +65,7 @@
// TODO(johnniwinther): Can this be derived from [ClassSet]s?
final Set<ClassEntity> implementedClasses;
+ @override
final Set<MemberEntity> liveInstanceMembers;
/// Members that are written either directly or through a setter selector.
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 9c400e0..7935546 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -69,6 +69,9 @@
Iterable<MemberEntity> get processedMembers;
+ @override
+ Iterable<MemberEntity> get liveInstanceMembers;
+
/// Returns the set of interfaces passed as type arguments to the internal
/// `extractTypeArguments` function.
Set<ClassEntity> get extractTypeArgumentsInterfacesNewRti;
diff --git a/pkg/compiler/lib/src/world_interfaces.dart b/pkg/compiler/lib/src/world_interfaces.dart
index fadcbce..1bde083 100644
--- a/pkg/compiler/lib/src/world_interfaces.dart
+++ b/pkg/compiler/lib/src/world_interfaces.dart
@@ -29,6 +29,8 @@
AnnotationsData get annotationsData;
+ Iterable<MemberEntity> get liveInstanceMembers;
+
bool isUsedAsMixin(ClassEntity cls);
bool includesClosureCall(Selector selector, AbstractValue? receiver);