Chromium Code Reviews| 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..076d6e0a78037fb333e4bec3293814008799e7cc 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,218 @@ 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); |
| + } |
| + |
| + 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 |
|
Siggi Cherem (dart-lang)
2017/07/19 04:38:34
VM bootstrap? I just realized this code was ported
Johnni Winther
2017/07/19 11:33:58
Done.
|
| + /// 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( |