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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dart2js.resolution.class_hierarchy; 5 library dart2js.resolution.class_hierarchy;
6 6
7 import '../common.dart'; 7 import '../common.dart';
8 import '../common/resolution.dart' show Resolution; 8 import '../common/resolution.dart' show Resolution;
9 import '../common_elements.dart' show CommonElements; 9 import '../common_elements.dart' show CommonElements;
10 import '../elements/resolution_types.dart'; 10 import '../elements/resolution_types.dart';
11 import '../elements/elements.dart'; 11 import '../elements/elements.dart';
12 import '../elements/modelx.dart' 12 import '../elements/modelx.dart'
13 show 13 show
14 BaseClassElementX, 14 BaseClassElementX,
15 ErroneousElementX, 15 ErroneousElementX,
16 LibraryElementX,
16 MixinApplicationElementX, 17 MixinApplicationElementX,
17 SynthesizedConstructorElementX, 18 SynthesizedConstructorElementX,
18 TypeVariableElementX, 19 TypeVariableElementX,
19 UnnamedMixinApplicationElementX; 20 UnnamedMixinApplicationElementX;
20 import '../elements/names.dart'; 21 import '../elements/names.dart';
21 import '../ordered_typeset.dart' 22 import '../ordered_typeset.dart'
22 show OrderedTypeSet, ResolutionOrderedTypeSetBuilder; 23 show OrderedTypeSet, ResolutionOrderedTypeSetBuilder;
23 import '../tree/tree.dart'; 24 import '../tree/tree.dart';
24 import '../universe/call_structure.dart' show CallStructure; 25 import '../universe/call_structure.dart' show CallStructure;
25 import '../universe/feature.dart' show Feature; 26 import '../universe/feature.dart' show Feature;
26 import '../util/util.dart' show Link, Setlet; 27 import '../util/util.dart' show Link, Setlet;
27 import 'enum_creator.dart'; 28 import 'enum_creator.dart';
28 import 'members.dart' show lookupInScope; 29 import 'members.dart' show lookupInScope;
29 import 'registry.dart' show ResolutionRegistry; 30 import 'registry.dart' show ResolutionRegistry;
30 import 'resolution_common.dart' show CommonResolverVisitor, MappingVisitor; 31 import 'resolution_common.dart' show CommonResolverVisitor, MappingVisitor;
31 import 'scope.dart' show Scope, TypeDeclarationScope; 32 import 'scope.dart' show Scope, TypeDeclarationScope;
32 33
34 /// If `true` compatible mixin applications are shared within a library. This
35 /// matches the mixins generated by fasta.
36 bool useOptimizedMixins = false;
37
33 class TypeDefinitionVisitor extends MappingVisitor<ResolutionDartType> { 38 class TypeDefinitionVisitor extends MappingVisitor<ResolutionDartType> {
34 Scope scope; 39 Scope scope;
35 final TypeDeclarationElement enclosingElement; 40 final TypeDeclarationElement enclosingElement;
36 TypeDeclarationElement get element => enclosingElement; 41 TypeDeclarationElement get element => enclosingElement;
37 42
38 TypeDefinitionVisitor(Resolution resolution, TypeDeclarationElement element, 43 TypeDefinitionVisitor(Resolution resolution, TypeDeclarationElement element,
39 ResolutionRegistry registry) 44 ResolutionRegistry registry)
40 : this.enclosingElement = element, 45 : this.enclosingElement = element,
41 scope = Scope.buildEnclosingScope(element), 46 scope = Scope.buildEnclosingScope(element),
42 super(resolution, registry); 47 super(resolution, registry);
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 // TODO(ahe): It is not safe to call resolveTypeVariableBounds yet. 143 // TODO(ahe): It is not safe to call resolveTypeVariableBounds yet.
139 // As a side-effect, this may get us back here trying to 144 // As a side-effect, this may get us back here trying to
140 // resolve this class again. 145 // resolve this class again.
141 resolveTypeVariableBounds(node.typeParameters); 146 resolveTypeVariableBounds(node.typeParameters);
142 147
143 // Setup the supertype for the element (if there is a cycle in the 148 // Setup the supertype for the element (if there is a cycle in the
144 // class hierarchy, it has already been set to Object). 149 // class hierarchy, it has already been set to Object).
145 if (element.supertype == null && node.superclass != null) { 150 if (element.supertype == null && node.superclass != null) {
146 MixinApplication superMixin = node.superclass.asMixinApplication(); 151 MixinApplication superMixin = node.superclass.asMixinApplication();
147 if (superMixin != null) { 152 if (superMixin != null) {
148 ResolutionDartType supertype = 153 if (useOptimizedMixins) {
149 resolveSupertype(element, superMixin.superclass); 154 element.supertype = createMixinsOptimized(element, superMixin);
150 Link<Node> link = superMixin.mixins.nodes; 155 } else {
151 while (!link.isEmpty) { 156 element.supertype = createMixins(element, superMixin);
152 supertype =
153 applyMixin(supertype, checkMixinType(link.head), link.head);
154 link = link.tail;
155 } 157 }
156 element.supertype = supertype;
157 } else { 158 } else {
158 element.supertype = resolveSupertype(element, node.superclass); 159 element.supertype = resolveSupertype(element, node.superclass);
159 } 160 }
160 } 161 }
161 // If the super type isn't specified, we provide a default. The language 162 // If the super type isn't specified, we provide a default. The language
162 // specifies [Object] but the backend can pick a specific 'implementation' 163 // specifies [Object] but the backend can pick a specific 'implementation'
163 // of Object - the JavaScript backend chooses between Object and 164 // of Object - the JavaScript backend chooses between Object and
164 // Interceptor. 165 // Interceptor.
165 if (element.supertype == null) { 166 if (element.supertype == null) {
166 ClassElement superElement = registry.defaultSuperclass(element); 167 ClassElement superElement = registry.defaultSuperclass(element);
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 throw reporter.internalError( 279 throw reporter.internalError(
279 element, 'cyclic resolution of class $element'); 280 element, 'cyclic resolution of class $element');
280 } 281 }
281 282
282 element.computeType(resolution); 283 element.computeType(resolution);
283 scope = new TypeDeclarationScope(scope, element); 284 scope = new TypeDeclarationScope(scope, element);
284 resolveTypeVariableBounds(node.typeParameters); 285 resolveTypeVariableBounds(node.typeParameters);
285 286
286 // Generate anonymous mixin application elements for the 287 // Generate anonymous mixin application elements for the
287 // intermediate mixin applications (excluding the last). 288 // intermediate mixin applications (excluding the last).
289 if (useOptimizedMixins) {
290 createMixinsOptimized(element, node, isNamed: true);
291 } else {
292 createMixins(element, node, isNamed: true);
293 }
294 return element.computeType(resolution);
295 }
296
297 /// Create the mixin applications for [superMixin].
298 ///
299 /// This algorithm is ported from
300 /// `package:front_end/src/fasta/kernel/kernel_library_builder.dart` and
301 /// added create allow for equivalence testing between the AST and kernel
302 /// based compilations in face of shared mixins. It will be removed when we
303 /// no longer need equivalence testing.
304 ResolutionDartType createMixinsOptimized(
305 BaseClassElementX element, MixinApplication superMixin,
306 {bool isNamed: false}) {
307 LibraryElementX library = element.library;
308 Map<String, MixinApplicationElementX> mixinApplicationClasses =
309 library.mixinApplicationCache;
310
311 String name = element.isNamedMixinApplication ? element.name : null;
312 ResolutionDartType supertype =
313 resolveSupertype(element, superMixin.superclass);
314 Link<Node> link = superMixin.mixins.nodes;
315 List<ResolutionDartType> mixins = <ResolutionDartType>[];
316 List<Node> mixinNodes = <Node>[];
317 while (!link.isEmpty) {
318 mixins.add(checkMixinType(link.head));
319 mixinNodes.add(link.head);
320 link = link.tail;
321 }
322
323 List<List<String>> signatureParts = <List<String>>[];
324 Map<String, ResolutionDartType> freeTypes = <String, ResolutionDartType>{};
325
326 {
327 Map<String, String> unresolved = <String, String>{};
328 int unresolvedCount = 0;
329
330 /// Compute a signature of the type arguments used by the supertype and
331 /// mixins. These types are free variables. At this point we can't
332 /// trust that the number of type arguments match the type parameters,
333 /// so we also need to be able to detect missing type arguments. To do
334 /// so, we separate each list of type arguments by `^` and type
335 /// arguments by `&`. For example, the mixin `C<S> with M<T, U>` would
336 /// look like this:
337 ///
338 /// ^#U0^#U1&#U2
339 ///
340 /// Where `#U0`, `#U1`, and `#U2` are the free variables arising from
341 /// `S`, `T`, and `U` respectively.
342 ///
343 /// As we can resolve any type parameters used at this point, those are
344 /// named `#T0` and so forth. This reduces the number of free variables
345 /// which is crucial for memory usage and the Dart VM's bootstrap
346 /// sequence.
347 ///
348 /// For example, consider this use of mixin applications:
349 ///
350 /// class _InternalLinkedHashMap<K, V> extends _HashVMBase
351 /// with
352 /// MapMixin<K, V>,
353 /// _LinkedHashMapMixin<K, V>,
354 /// _HashBase,
355 /// _OperatorEqualsAndHashCode {}
356 ///
357 /// In this case, only two variables are free, and we produce this
358 /// signature: `^^#T0&#T1^#T0&#T1^^`. Assume another class uses the
359 /// sames mixins but with missing type arguments for `MapMixin`, its
360 /// signature would be: `^^^#T0&#T1^^`.
361 ///
362 /// Note that we do not need to compute a signature for a named mixin
363 /// application with only one mixin as we don't have to invent a name
364 /// for any classes in this situation.
365 void analyzeArguments(ResolutionDartType type, {bool isLast}) {
366 if (isNamed && isLast) {
367 // The last mixin of a named mixin application doesn't contribute
368 // to free variables.
369 return;
370 }
371 if (type is GenericType) {
372 List<String> part = <String>[];
373 for (int i = 0; i < type.typeArguments.length; i++) {
374 var argument = type.typeArguments[i];
375 String name;
376 if (argument is ResolutionTypeVariableType) {
377 int index = element.typeVariables.indexOf(argument) ?? -1;
378 if (index != -1) {
379 name = "#T${index}";
380 }
381 } else if (argument is GenericType && argument.isRaw) {
382 name = unresolved[argument.name] ??= "#U${unresolvedCount++}";
383 }
384 name ??= "#U${unresolvedCount++}";
385 freeTypes[name] = argument;
386 part.add(name);
387 }
388 signatureParts.add(part);
389 }
390 }
391
392 analyzeArguments(supertype, isLast: false);
393 for (int i = 0; i < mixins.length; i++) {
394 analyzeArguments(mixins[i], isLast: i == mixins.length - 1);
395 }
396 }
397
398 List<List<String>> currentSignatureParts = <List<String>>[];
399 String computeSignature(int index) {
400 if (freeTypes.isEmpty) return "";
401 currentSignatureParts.add(signatureParts[index]);
402 if (currentSignatureParts.any((l) => l.isNotEmpty)) {
403 return "^${currentSignatureParts.map((l) => l.join('&')).join('^')}";
404 } else {
405 return "";
406 }
407 }
408
409 Map<String, ResolutionTypeVariableType> computeTypeVariables(
410 ClassElement cls, Node node) {
411 Map<String, ResolutionTypeVariableType> variables =
412 <String, ResolutionTypeVariableType>{};
413 int index = 0;
414 for (List<String> strings in currentSignatureParts) {
415 for (String name in strings) {
416 variables[name] ??= new ResolutionTypeVariableType(
417 new TypeVariableElementX(name, cls, index++, node));
418 }
419 }
420 return variables;
421 }
422
423 computeSignature(0); // This combines the supertype with the first mixin.
424
425 for (int i = 0; i < mixins.length; i++) {
426 int signatureIndex = i + 1;
427 Set<String> supertypeArguments = new Set<String>();
428 for (List<String> part in currentSignatureParts) {
429 supertypeArguments.addAll(part);
430 }
431 Node node = mixinNodes[i];
432 ResolutionDartType mixin = mixins[i];
433
434 bool lastAndNamed = i == mixins.length - 1 && isNamed;
435
436 ResolutionInterfaceType createMixinApplication() {
437 Map<String, ResolutionDartType> variables;
438 MixinApplicationElementX mixinElement;
439 ResolutionInterfaceType mixinType;
440 if (lastAndNamed) {
441 mixinElement = element;
442 variables = freeTypes;
443 } else {
444 String signature = computeSignature(signatureIndex);
445 name = supertype.name;
446 int index = name.indexOf("^");
447 if (index != -1) {
448 name = name.substring(0, index);
449 }
450 name = "$name&${mixin.name}$signature";
451 mixinElement = mixinApplicationClasses[name];
452 if (mixinElement != null) return mixinElement.thisType;
453
454 mixinElement = new UnnamedMixinApplicationElementX(
455 name, element, resolution.idGenerator.getNextFreeId(), node);
456 variables = computeTypeVariables(mixinElement, node);
457 mixinElement.setThisAndRawTypes(variables.values.toList());
458 mixinApplicationClasses[name] = mixinElement;
459 }
460
461 if (supertypeArguments.isNotEmpty) {
462 List<ResolutionDartType> supertypeTypeArguments =
463 <ResolutionDartType>[];
464 for (String part in supertypeArguments) {
465 supertypeTypeArguments.add(variables[part]);
466 }
467 supertype = new ResolutionInterfaceType(
468 supertype.element, supertypeTypeArguments);
469 }
470
471 if (lastAndNamed) {
472 mixinType = mixin;
473 } else {
474 List<ResolutionDartType> mixinTypeArguments = <ResolutionDartType>[];
475 for (String part in signatureParts[signatureIndex]) {
476 mixinTypeArguments.add(variables[part]);
477 }
478 mixinType =
479 new ResolutionInterfaceType(mixin.element, mixinTypeArguments);
480 }
481
482 doApplyMixinTo(mixinElement, supertype, mixinType);
483 mixinElement.resolutionState = STATE_DONE;
484 mixinElement.supertypeLoadState = STATE_DONE;
485 return mixinElement.thisType;
486 }
487
488 supertype = createMixinApplication();
489 }
490
491 return new ResolutionInterfaceType(
492 supertype.element, freeTypes.values.toList());
493 }
494
495 ResolutionDartType createMixins(ClassElement element, MixinApplication node,
496 {bool isNamed: false}) {
288 ResolutionDartType supertype = resolveSupertype(element, node.superclass); 497 ResolutionDartType supertype = resolveSupertype(element, node.superclass);
289 Link<Node> link = node.mixins.nodes; 498 Link<Node> link = node.mixins.nodes;
290 while (!link.tail.isEmpty) { 499 while (!link.isEmpty) {
500 if (isNamed && link.tail.isEmpty) {
501 doApplyMixinTo(element, supertype, checkMixinType(link.head));
502 return supertype;
503 }
291 supertype = applyMixin(supertype, checkMixinType(link.head), link.head); 504 supertype = applyMixin(supertype, checkMixinType(link.head), link.head);
292 link = link.tail; 505 link = link.tail;
293 } 506 }
294 doApplyMixinTo(element, supertype, checkMixinType(link.head)); 507 return supertype;
295 return element.computeType(resolution);
296 } 508 }
297 509
298 ResolutionDartType applyMixin( 510 ResolutionDartType applyMixin(
299 ResolutionDartType supertype, ResolutionDartType mixinType, Node node) { 511 ResolutionDartType supertype, ResolutionDartType mixinType, Node node) {
300 String superName = supertype.name; 512 String superName = supertype.name;
301 String mixinName = mixinType.name; 513 String mixinName = mixinType.name;
302 MixinApplicationElementX mixinApplication = 514 MixinApplicationElementX mixinApplication =
303 new UnnamedMixinApplicationElementX("${superName}+${mixinName}", 515 new UnnamedMixinApplicationElementX("${superName}+${mixinName}",
304 element, resolution.idGenerator.getNextFreeId(), node); 516 element, resolution.idGenerator.getNextFreeId(), node);
305 // Create synthetic type variables for the mixin application. 517 // Create synthetic type variables for the mixin application.
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after
646 Identifier selector = node.selector.asIdentifier(); 858 Identifier selector = node.selector.asIdentifier();
647 var e = prefixElement.lookupLocalMember(selector.source); 859 var e = prefixElement.lookupLocalMember(selector.source);
648 if (e == null || !e.impliesType) { 860 if (e == null || !e.impliesType) {
649 reporter.reportErrorMessage(node.selector, 861 reporter.reportErrorMessage(node.selector,
650 MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.selector}); 862 MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.selector});
651 return; 863 return;
652 } 864 }
653 loadSupertype(e, node); 865 loadSupertype(e, node);
654 } 866 }
655 } 867 }
OLDNEW
« 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