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

Side by Side Diff: pkg/compiler/lib/src/resolution/class_hierarchy.dart

Issue 2983013002: Implement optimized mixin application in dart2js (Closed)
Patch Set: 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 ResolutionDartType createMixinsOptimized(
298 BaseClassElementX element, MixinApplication superMixin,
299 {bool isNamed: false}) {
300 LibraryElementX library = element.library;
301 Map<String, MixinApplicationElementX> mixinApplicationClasses =
302 library.mixinApplicationCache;
303
304 String name = element.isNamedMixinApplication ? element.name : null;
305 ResolutionDartType supertype =
306 resolveSupertype(element, superMixin.superclass);
307 Link<Node> link = superMixin.mixins.nodes;
308 List<ResolutionDartType> mixins = <ResolutionDartType>[];
309 List<Node> mixinNodes = <Node>[];
310 while (!link.isEmpty) {
311 mixins.add(checkMixinType(link.head));
312 mixinNodes.add(link.head);
313 link = link.tail;
314 }
315
316 List<List<String>> signatureParts = <List<String>>[];
317 Map<String, ResolutionDartType> freeTypes = <String, ResolutionDartType>{};
318
319 {
320 Map<String, String> unresolved = <String, String>{};
321 int unresolvedCount = 0;
322
323 /// Compute a signature of the type arguments used by the supertype and
324 /// mixins. These types are free variables. At this point we can't
325 /// trust that the number of type arguments match the type parameters,
326 /// so we also need to be able to detect missing type arguments. To do
327 /// so, we separate each list of type arguments by `^` and type
328 /// arguments by `&`. For example, the mixin `C<S> with M<T, U>` would
329 /// look like this:
330 ///
331 /// ^#U0^#U1&#U2
332 ///
333 /// Where `#U0`, `#U1`, and `#U2` are the free variables arising from
334 /// `S`, `T`, and `U` respectively.
335 ///
336 /// As we can resolve any type parameters used at this point, those are
337 /// named `#T0` and so forth. This reduces the number of free variables
338 /// 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.
339 /// sequence.
340 ///
341 /// For example, consider this use of mixin applications:
342 ///
343 /// class _InternalLinkedHashMap<K, V> extends _HashVMBase
344 /// with
345 /// MapMixin<K, V>,
346 /// _LinkedHashMapMixin<K, V>,
347 /// _HashBase,
348 /// _OperatorEqualsAndHashCode {}
349 ///
350 /// In this case, only two variables are free, and we produce this
351 /// signature: `^^#T0&#T1^#T0&#T1^^`. Assume another class uses the
352 /// sames mixins but with missing type arguments for `MapMixin`, its
353 /// signature would be: `^^^#T0&#T1^^`.
354 ///
355 /// Note that we do not need to compute a signature for a named mixin
356 /// application with only one mixin as we don't have to invent a name
357 /// for any classes in this situation.
358 void analyzeArguments(ResolutionDartType type, {bool isLast}) {
359 if (isNamed && isLast) {
360 // The last mixin of a named mixin application doesn't contribute
361 // to free variables.
362 return;
363 }
364 if (type is GenericType) {
365 List<String> part = <String>[];
366 for (int i = 0; i < type.typeArguments.length; i++) {
367 var argument = type.typeArguments[i];
368 String name;
369 if (argument is ResolutionTypeVariableType) {
370 int index = element.typeVariables.indexOf(argument) ?? -1;
371 if (index != -1) {
372 name = "#T${index}";
373 }
374 } else if (argument is GenericType && argument.isRaw) {
375 name = unresolved[argument.name] ??= "#U${unresolvedCount++}";
376 }
377 name ??= "#U${unresolvedCount++}";
378 freeTypes[name] = argument;
379 part.add(name);
380 }
381 signatureParts.add(part);
382 }
383 }
384
385 analyzeArguments(supertype, isLast: false);
386 for (int i = 0; i < mixins.length; i++) {
387 analyzeArguments(mixins[i], isLast: i == mixins.length - 1);
388 }
389 }
390
391 List<List<String>> currentSignatureParts = <List<String>>[];
392 String computeSignature(int index) {
393 if (freeTypes.isEmpty) return "";
394 currentSignatureParts.add(signatureParts[index]);
395 if (currentSignatureParts.any((l) => l.isNotEmpty)) {
396 return "^${currentSignatureParts.map((l) => l.join('&')).join('^')}";
397 } else {
398 return "";
399 }
400 }
401
402 Map<String, ResolutionTypeVariableType> computeTypeVariables(
403 ClassElement cls, Node node) {
404 Map<String, ResolutionTypeVariableType> variables =
405 <String, ResolutionTypeVariableType>{};
406 int index = 0;
407 for (List<String> strings in currentSignatureParts) {
408 for (String name in strings) {
409 variables[name] ??= new ResolutionTypeVariableType(
410 new TypeVariableElementX(name, cls, index++, node));
411 }
412 }
413 return variables;
414 }
415
416 computeSignature(0); // This combines the supertype with the first mixin.
417
418 for (int i = 0; i < mixins.length; i++) {
419 int signatureIndex = i + 1;
420 Set<String> supertypeArguments = new Set<String>();
421 for (List<String> part in currentSignatureParts) {
422 supertypeArguments.addAll(part);
423 }
424 Node node = mixinNodes[i];
425 ResolutionDartType mixin = mixins[i];
426
427 bool lastAndNamed = i == mixins.length - 1 && isNamed;
428
429 ResolutionInterfaceType createMixinApplication() {
430 Map<String, ResolutionDartType> variables;
431 MixinApplicationElementX mixinElement;
432 ResolutionInterfaceType mixinType;
433 if (lastAndNamed) {
434 mixinElement = element;
435 variables = freeTypes;
436 } else {
437 String signature = computeSignature(signatureIndex);
438 name = supertype.name;
439 int index = name.indexOf("^");
440 if (index != -1) {
441 name = name.substring(0, index);
442 }
443 name = "$name&${mixin.name}$signature";
444 mixinElement = mixinApplicationClasses[name];
445 if (mixinElement != null) return mixinElement.thisType;
446
447 mixinElement = new UnnamedMixinApplicationElementX(
448 name, element, resolution.idGenerator.getNextFreeId(), node);
449 variables = computeTypeVariables(mixinElement, node);
450 mixinElement.setThisAndRawTypes(variables.values.toList());
451 mixinApplicationClasses[name] = mixinElement;
452 }
453
454 if (supertypeArguments.isNotEmpty) {
455 List<ResolutionDartType> supertypeTypeArguments =
456 <ResolutionDartType>[];
457 for (String part in supertypeArguments) {
458 supertypeTypeArguments.add(variables[part]);
459 }
460 supertype = new ResolutionInterfaceType(
461 supertype.element, supertypeTypeArguments);
462 }
463
464 if (lastAndNamed) {
465 mixinType = mixin;
466 } else {
467 List<ResolutionDartType> mixinTypeArguments = <ResolutionDartType>[];
468 for (String part in signatureParts[signatureIndex]) {
469 mixinTypeArguments.add(variables[part]);
470 }
471 mixinType =
472 new ResolutionInterfaceType(mixin.element, mixinTypeArguments);
473 }
474
475 doApplyMixinTo(mixinElement, supertype, mixinType);
476 mixinElement.resolutionState = STATE_DONE;
477 mixinElement.supertypeLoadState = STATE_DONE;
478 return mixinElement.thisType;
479 }
480
481 supertype = createMixinApplication();
482 }
483
484 return new ResolutionInterfaceType(
485 supertype.element, freeTypes.values.toList());
486 }
487
488 ResolutionDartType createMixins(ClassElement element, MixinApplication node,
489 {bool isNamed: false}) {
288 ResolutionDartType supertype = resolveSupertype(element, node.superclass); 490 ResolutionDartType supertype = resolveSupertype(element, node.superclass);
289 Link<Node> link = node.mixins.nodes; 491 Link<Node> link = node.mixins.nodes;
290 while (!link.tail.isEmpty) { 492 while (!link.isEmpty) {
493 if (isNamed && link.tail.isEmpty) {
494 doApplyMixinTo(element, supertype, checkMixinType(link.head));
495 return supertype;
496 }
291 supertype = applyMixin(supertype, checkMixinType(link.head), link.head); 497 supertype = applyMixin(supertype, checkMixinType(link.head), link.head);
292 link = link.tail; 498 link = link.tail;
293 } 499 }
294 doApplyMixinTo(element, supertype, checkMixinType(link.head)); 500 return supertype;
295 return element.computeType(resolution);
296 } 501 }
297 502
298 ResolutionDartType applyMixin( 503 ResolutionDartType applyMixin(
299 ResolutionDartType supertype, ResolutionDartType mixinType, Node node) { 504 ResolutionDartType supertype, ResolutionDartType mixinType, Node node) {
300 String superName = supertype.name; 505 String superName = supertype.name;
301 String mixinName = mixinType.name; 506 String mixinName = mixinType.name;
302 MixinApplicationElementX mixinApplication = 507 MixinApplicationElementX mixinApplication =
303 new UnnamedMixinApplicationElementX("${superName}+${mixinName}", 508 new UnnamedMixinApplicationElementX("${superName}+${mixinName}",
304 element, resolution.idGenerator.getNextFreeId(), node); 509 element, resolution.idGenerator.getNextFreeId(), node);
305 // Create synthetic type variables for the mixin application. 510 // 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(); 851 Identifier selector = node.selector.asIdentifier();
647 var e = prefixElement.lookupLocalMember(selector.source); 852 var e = prefixElement.lookupLocalMember(selector.source);
648 if (e == null || !e.impliesType) { 853 if (e == null || !e.impliesType) {
649 reporter.reportErrorMessage(node.selector, 854 reporter.reportErrorMessage(node.selector,
650 MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.selector}); 855 MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.selector});
651 return; 856 return;
652 } 857 }
653 loadSupertype(e, node); 858 loadSupertype(e, node);
654 } 859 }
655 } 860 }
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