Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Unified Diff: pkg/compiler/lib/src/resolution/class_hierarchy.dart

Issue 2983013002: Implement optimized mixin application in dart2js (Closed)
Patch Set: Updated cf. comment Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/resolution/class_hierarchy.dart
diff --git a/pkg/compiler/lib/src/resolution/class_hierarchy.dart b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
index 3b867eabc10860eb90ec417a956bb0004213d16e..0d9b50cfa0dac064c6ac80c4bb704f652d22ce50 100644
--- a/pkg/compiler/lib/src/resolution/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
@@ -13,6 +13,7 @@ import '../elements/modelx.dart'
show
BaseClassElementX,
ErroneousElementX,
+ LibraryElementX,
MixinApplicationElementX,
SynthesizedConstructorElementX,
TypeVariableElementX,
@@ -30,6 +31,10 @@ import 'registry.dart' show ResolutionRegistry;
import 'resolution_common.dart' show CommonResolverVisitor, MappingVisitor;
import 'scope.dart' show Scope, TypeDeclarationScope;
+/// If `true` compatible mixin applications are shared within a library. This
+/// matches the mixins generated by fasta.
+bool useOptimizedMixins = false;
+
class TypeDefinitionVisitor extends MappingVisitor<ResolutionDartType> {
Scope scope;
final TypeDeclarationElement enclosingElement;
@@ -145,15 +150,11 @@ class ClassResolverVisitor extends TypeDefinitionVisitor {
if (element.supertype == null && node.superclass != null) {
MixinApplication superMixin = node.superclass.asMixinApplication();
if (superMixin != null) {
- ResolutionDartType supertype =
- resolveSupertype(element, superMixin.superclass);
- Link<Node> link = superMixin.mixins.nodes;
- while (!link.isEmpty) {
- supertype =
- applyMixin(supertype, checkMixinType(link.head), link.head);
- link = link.tail;
+ if (useOptimizedMixins) {
+ element.supertype = createMixinsOptimized(element, superMixin);
+ } else {
+ element.supertype = createMixins(element, superMixin);
}
- element.supertype = supertype;
} else {
element.supertype = resolveSupertype(element, node.superclass);
}
@@ -285,14 +286,225 @@ class ClassResolverVisitor extends TypeDefinitionVisitor {
// Generate anonymous mixin application elements for the
// intermediate mixin applications (excluding the last).
+ if (useOptimizedMixins) {
+ createMixinsOptimized(element, node, isNamed: true);
+ } else {
+ createMixins(element, node, isNamed: true);
+ }
+ return element.computeType(resolution);
+ }
+
+ /// Create the mixin applications for [superMixin].
+ ///
+ /// This algorithm is ported from
+ /// `package:front_end/src/fasta/kernel/kernel_library_builder.dart` and
+ /// added create allow for equivalence testing between the AST and kernel
+ /// based compilations in face of shared mixins. It will be removed when we
+ /// no longer need equivalence testing.
+ ResolutionDartType createMixinsOptimized(
+ BaseClassElementX element, MixinApplication superMixin,
+ {bool isNamed: false}) {
+ LibraryElementX library = element.library;
+ Map<String, MixinApplicationElementX> mixinApplicationClasses =
+ library.mixinApplicationCache;
+
+ String name = element.isNamedMixinApplication ? element.name : null;
+ ResolutionDartType supertype =
+ resolveSupertype(element, superMixin.superclass);
+ Link<Node> link = superMixin.mixins.nodes;
+ List<ResolutionDartType> mixins = <ResolutionDartType>[];
+ List<Node> mixinNodes = <Node>[];
+ while (!link.isEmpty) {
+ mixins.add(checkMixinType(link.head));
+ mixinNodes.add(link.head);
+ link = link.tail;
+ }
+
+ List<List<String>> signatureParts = <List<String>>[];
+ Map<String, ResolutionDartType> freeTypes = <String, ResolutionDartType>{};
+
+ {
+ Map<String, String> unresolved = <String, String>{};
+ int unresolvedCount = 0;
+
+ /// Compute a signature of the type arguments used by the supertype and
+ /// mixins. These types are free variables. At this point we can't
+ /// trust that the number of type arguments match the type parameters,
+ /// so we also need to be able to detect missing type arguments. To do
+ /// so, we separate each list of type arguments by `^` and type
+ /// arguments by `&`. For example, the mixin `C<S> with M<T, U>` would
+ /// look like this:
+ ///
+ /// ^#U0^#U1&#U2
+ ///
+ /// Where `#U0`, `#U1`, and `#U2` are the free variables arising from
+ /// `S`, `T`, and `U` respectively.
+ ///
+ /// As we can resolve any type parameters used at this point, those are
+ /// named `#T0` and so forth. This reduces the number of free variables
+ /// which is crucial for memory usage and the Dart VM's bootstrap
+ /// sequence.
+ ///
+ /// For example, consider this use of mixin applications:
+ ///
+ /// class _InternalLinkedHashMap<K, V> extends _HashVMBase
+ /// with
+ /// MapMixin<K, V>,
+ /// _LinkedHashMapMixin<K, V>,
+ /// _HashBase,
+ /// _OperatorEqualsAndHashCode {}
+ ///
+ /// In this case, only two variables are free, and we produce this
+ /// signature: `^^#T0&#T1^#T0&#T1^^`. Assume another class uses the
+ /// sames mixins but with missing type arguments for `MapMixin`, its
+ /// signature would be: `^^^#T0&#T1^^`.
+ ///
+ /// Note that we do not need to compute a signature for a named mixin
+ /// application with only one mixin as we don't have to invent a name
+ /// for any classes in this situation.
+ void analyzeArguments(ResolutionDartType type, {bool isLast}) {
+ if (isNamed && isLast) {
+ // The last mixin of a named mixin application doesn't contribute
+ // to free variables.
+ return;
+ }
+ if (type is GenericType) {
+ List<String> part = <String>[];
+ for (int i = 0; i < type.typeArguments.length; i++) {
+ var argument = type.typeArguments[i];
+ String name;
+ if (argument is ResolutionTypeVariableType) {
+ int index = element.typeVariables.indexOf(argument) ?? -1;
+ if (index != -1) {
+ name = "#T${index}";
+ }
+ } else if (argument is GenericType && argument.isRaw) {
+ name = unresolved[argument.name] ??= "#U${unresolvedCount++}";
+ }
+ name ??= "#U${unresolvedCount++}";
+ freeTypes[name] = argument;
+ part.add(name);
+ }
+ signatureParts.add(part);
+ }
+ }
+
+ analyzeArguments(supertype, isLast: false);
+ for (int i = 0; i < mixins.length; i++) {
+ analyzeArguments(mixins[i], isLast: i == mixins.length - 1);
+ }
+ }
+
+ List<List<String>> currentSignatureParts = <List<String>>[];
+ String computeSignature(int index) {
+ if (freeTypes.isEmpty) return "";
+ currentSignatureParts.add(signatureParts[index]);
+ if (currentSignatureParts.any((l) => l.isNotEmpty)) {
+ return "^${currentSignatureParts.map((l) => l.join('&')).join('^')}";
+ } else {
+ return "";
+ }
+ }
+
+ Map<String, ResolutionTypeVariableType> computeTypeVariables(
+ ClassElement cls, Node node) {
+ Map<String, ResolutionTypeVariableType> variables =
+ <String, ResolutionTypeVariableType>{};
+ int index = 0;
+ for (List<String> strings in currentSignatureParts) {
+ for (String name in strings) {
+ variables[name] ??= new ResolutionTypeVariableType(
+ new TypeVariableElementX(name, cls, index++, node));
+ }
+ }
+ return variables;
+ }
+
+ computeSignature(0); // This combines the supertype with the first mixin.
+
+ for (int i = 0; i < mixins.length; i++) {
+ int signatureIndex = i + 1;
+ Set<String> supertypeArguments = new Set<String>();
+ for (List<String> part in currentSignatureParts) {
+ supertypeArguments.addAll(part);
+ }
+ Node node = mixinNodes[i];
+ ResolutionDartType mixin = mixins[i];
+
+ bool lastAndNamed = i == mixins.length - 1 && isNamed;
+
+ ResolutionInterfaceType createMixinApplication() {
+ Map<String, ResolutionDartType> variables;
+ MixinApplicationElementX mixinElement;
+ ResolutionInterfaceType mixinType;
+ if (lastAndNamed) {
+ mixinElement = element;
+ variables = freeTypes;
+ } else {
+ String signature = computeSignature(signatureIndex);
+ name = supertype.name;
+ int index = name.indexOf("^");
+ if (index != -1) {
+ name = name.substring(0, index);
+ }
+ name = "$name&${mixin.name}$signature";
+ mixinElement = mixinApplicationClasses[name];
+ if (mixinElement != null) return mixinElement.thisType;
+
+ mixinElement = new UnnamedMixinApplicationElementX(
+ name, element, resolution.idGenerator.getNextFreeId(), node);
+ variables = computeTypeVariables(mixinElement, node);
+ mixinElement.setThisAndRawTypes(variables.values.toList());
+ mixinApplicationClasses[name] = mixinElement;
+ }
+
+ if (supertypeArguments.isNotEmpty) {
+ List<ResolutionDartType> supertypeTypeArguments =
+ <ResolutionDartType>[];
+ for (String part in supertypeArguments) {
+ supertypeTypeArguments.add(variables[part]);
+ }
+ supertype = new ResolutionInterfaceType(
+ supertype.element, supertypeTypeArguments);
+ }
+
+ if (lastAndNamed) {
+ mixinType = mixin;
+ } else {
+ List<ResolutionDartType> mixinTypeArguments = <ResolutionDartType>[];
+ for (String part in signatureParts[signatureIndex]) {
+ mixinTypeArguments.add(variables[part]);
+ }
+ mixinType =
+ new ResolutionInterfaceType(mixin.element, mixinTypeArguments);
+ }
+
+ doApplyMixinTo(mixinElement, supertype, mixinType);
+ mixinElement.resolutionState = STATE_DONE;
+ mixinElement.supertypeLoadState = STATE_DONE;
+ return mixinElement.thisType;
+ }
+
+ supertype = createMixinApplication();
+ }
+
+ return new ResolutionInterfaceType(
+ supertype.element, freeTypes.values.toList());
+ }
+
+ ResolutionDartType createMixins(ClassElement element, MixinApplication node,
+ {bool isNamed: false}) {
ResolutionDartType supertype = resolveSupertype(element, node.superclass);
Link<Node> link = node.mixins.nodes;
- while (!link.tail.isEmpty) {
+ while (!link.isEmpty) {
+ if (isNamed && link.tail.isEmpty) {
+ doApplyMixinTo(element, supertype, checkMixinType(link.head));
+ return supertype;
+ }
supertype = applyMixin(supertype, checkMixinType(link.head), link.head);
link = link.tail;
}
- doApplyMixinTo(element, supertype, checkMixinType(link.head));
- return element.computeType(resolution);
+ return supertype;
}
ResolutionDartType applyMixin(
« no previous file with comments | « pkg/compiler/lib/src/elements/modelx.dart ('k') | tests/compiler/dart2js/kernel/compile_from_dill_test_helper.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698