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

Side by Side Diff: pkg/compiler/lib/src/inferrer/inferrer_engine.dart

Issue 2993713002: Move most code from AstInferrerEngine to InferrerEngineImpl (Closed)
Patch Set: Created 3 years, 4 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
« no previous file with comments | « pkg/compiler/lib/src/inferrer/ast_inferrer_engine.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, 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 import 'package:kernel/ast.dart' as ir; 5 import 'package:kernel/ast.dart' as ir;
6 6
7 import '../common.dart'; 7 import '../common.dart';
8 import '../common/names.dart'; 8 import '../common/names.dart';
9 import '../compiler.dart'; 9 import '../compiler.dart';
10 import '../common_elements.dart'; 10 import '../common_elements.dart';
11 import '../constants/values.dart';
11 import '../elements/elements.dart' 12 import '../elements/elements.dart'
12 show 13 show
13 ClassElement, 14 ClassElement,
14 ConstructorElement, 15 ConstructorElement,
15 Elements, 16 Elements,
16 MemberElement, 17 MemberElement,
17 ParameterElement; 18 ParameterElement;
18 import '../elements/entities.dart'; 19 import '../elements/entities.dart';
19 import '../elements/names.dart'; 20 import '../elements/names.dart';
20 import '../js_backend/annotations.dart'; 21 import '../js_backend/annotations.dart';
21 import '../js_backend/js_backend.dart'; 22 import '../js_backend/js_backend.dart';
22 import '../native/behavior.dart' as native; 23 import '../native/behavior.dart' as native;
24 import '../types/constants.dart';
23 import '../types/types.dart'; 25 import '../types/types.dart';
24 import '../universe/call_structure.dart'; 26 import '../universe/call_structure.dart';
25 import '../universe/selector.dart'; 27 import '../universe/selector.dart';
26 import '../universe/side_effects.dart'; 28 import '../universe/side_effects.dart';
27 import '../world.dart'; 29 import '../world.dart';
30 import 'closure_tracer.dart';
28 import 'debug.dart' as debug; 31 import 'debug.dart' as debug;
29 import 'locals_handler.dart'; 32 import 'locals_handler.dart';
30 import 'list_tracer.dart'; 33 import 'list_tracer.dart';
31 import 'map_tracer.dart'; 34 import 'map_tracer.dart';
32 import 'builder.dart'; 35 import 'builder.dart';
36 import 'type_graph_dump.dart';
33 import 'type_graph_inferrer.dart'; 37 import 'type_graph_inferrer.dart';
34 import 'type_graph_nodes.dart'; 38 import 'type_graph_nodes.dart';
35 import 'type_system.dart'; 39 import 'type_system.dart';
36 40
37 /// An inferencing engine that computes a call graph of [TypeInformation] nodes 41 /// An inferencing engine that computes a call graph of [TypeInformation] nodes
38 /// by visiting the AST of the application, and then does the inferencing on the 42 /// by visiting the AST of the application, and then does the inferencing on the
39 /// graph. 43 /// graph.
40 abstract class InferrerEngine<T> { 44 abstract class InferrerEngine<T> {
41 /// A set of selector names that [List] implements, that we know return their 45 /// A set of selector names that [List] implements, that we know return their
42 /// element type. 46 /// element type.
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 workQueue.addAll(info.addMapAssignment(map)); 453 workQueue.addAll(info.addMapAssignment(map));
450 } 454 }
451 455
452 info.markAsInferred(); 456 info.markAsInferred();
453 workQueue.add(info.keyType); 457 workQueue.add(info.keyType);
454 workQueue.add(info.valueType); 458 workQueue.add(info.valueType);
455 workQueue.addAll(info.typeInfoMap.values); 459 workQueue.addAll(info.typeInfoMap.values);
456 workQueue.add(info); 460 workQueue.add(info);
457 } 461 }
458 462
459 void runOverAllElements(); 463 void runOverAllElements() {
460 464 if (compiler.disableTypeInference) return;
461 void analyze(MemberEntity element, T body, ArgumentsTypes arguments); 465 if (compiler.options.verbose) {
466 compiler.progress.reset();
467 }
468 analyzeAllElements();
469
470 TypeGraphDump dump = debug.PRINT_GRAPH ? new TypeGraphDump(this) : null;
471
472 dump?.beforeAnalysis();
473 buildWorkQueue();
474 refine();
475
476 // Try to infer element types of lists and compute their escape information.
477 types.allocatedLists.values.forEach((TypeInformation info) {
478 analyzeListAndEnqueue(info);
479 });
480
481 // Try to infer the key and value types for maps and compute the values'
482 // escape information.
483 types.allocatedMaps.values.forEach((TypeInformation info) {
484 analyzeMapAndEnqueue(info);
485 });
486
487 Set<FunctionEntity> bailedOutOn = new Set<FunctionEntity>();
488
489 // Trace closures to potentially infer argument types.
490 types.allocatedClosures.forEach((dynamic info) {
491 void trace(
492 Iterable<FunctionEntity> elements, ClosureTracerVisitor tracer) {
493 tracer.run();
494 if (!tracer.continueAnalyzing) {
495 elements.forEach((FunctionEntity element) {
496 closedWorldRefiner.registerMightBePassedToApply(element);
497 if (debug.VERBOSE) {
498 print("traced closure $element as ${true} (bail)");
499 }
500 forEachParameter(element, (Local parameter) {
501 types
502 .getInferredTypeOfParameter(parameter)
503 .giveUp(this, clearAssignments: false);
504 });
505 });
506 bailedOutOn.addAll(elements);
507 return;
508 }
509 elements
510 .where((e) => !bailedOutOn.contains(e))
511 .forEach((FunctionEntity element) {
512 forEachParameter(element, (Local parameter) {
513 ParameterTypeInformation info =
514 types.getInferredTypeOfParameter(parameter);
515 info.maybeResume();
516 workQueue.add(info);
517 });
518 if (tracer.tracedType.mightBePassedToFunctionApply) {
519 closedWorldRefiner.registerMightBePassedToApply(element);
520 }
521 if (debug.VERBOSE) {
522 print("traced closure $element as "
523 "${closedWorldRefiner
524 .getCurrentlyKnownMightBePassedToApply(element)}");
525 }
526 });
527 }
528
529 if (info is ClosureTypeInformation) {
530 Iterable<FunctionEntity> elements = [info.closure];
531 trace(elements, new ClosureTracerVisitor(elements, info, this));
532 } else if (info is CallSiteTypeInformation) {
533 if (info is StaticCallSiteTypeInformation &&
534 info.selector != null &&
535 info.selector.isCall) {
536 // This is a constructor call to a class with a call method. So we
537 // need to trace the call method here.
538 FunctionEntity calledElement = info.calledElement;
539 assert(calledElement is ConstructorEntity &&
540 calledElement.isGenerativeConstructor);
541 ClassEntity cls = calledElement.enclosingClass;
542 FunctionEntity callMethod = lookupCallMethod(cls);
543 assert(callMethod != null, failedAt(cls));
544 Iterable<FunctionEntity> elements = [callMethod];
545 trace(elements, new ClosureTracerVisitor(elements, info, this));
546 } else {
547 // We only are interested in functions here, as other targets
548 // of this closure call are not a root to trace but an intermediate
549 // for some other function.
550 Iterable<FunctionEntity> elements = new List<FunctionEntity>.from(
551 info.callees.where((e) => e.isFunction));
552 trace(elements, new ClosureTracerVisitor(elements, info, this));
553 }
554 } else if (info is MemberTypeInformation) {
555 trace(<FunctionEntity>[info.member],
556 new StaticTearOffClosureTracerVisitor(info.member, info, this));
557 } else if (info is ParameterTypeInformation) {
558 failedAt(
559 NO_LOCATION_SPANNABLE, 'Unexpected closure allocation info $info');
560 }
561 });
562
563 dump?.beforeTracing();
564
565 // Reset all nodes that use lists/maps that have been inferred, as well
566 // as nodes that use elements fetched from these lists/maps. The
567 // workset for a new run of the analysis will be these nodes.
568 Set<TypeInformation> seenTypes = new Set<TypeInformation>();
569 while (!workQueue.isEmpty) {
570 TypeInformation info = workQueue.remove();
571 if (seenTypes.contains(info)) continue;
572 // If the node cannot be reset, we do not need to update its users either.
573 if (!info.reset(this)) continue;
574 seenTypes.add(info);
575 workQueue.addAll(info.users);
576 }
577
578 workQueue.addAll(seenTypes);
579 refine();
580
581 if (debug.PRINT_SUMMARY) {
582 types.allocatedLists.values.forEach((_info) {
583 ListTypeInformation info = _info;
584 print('${info.type} '
585 'for ${info.originalType.allocationNode} '
586 'at ${info.originalType.allocationElement} '
587 'after ${info.refineCount}');
588 });
589 types.allocatedMaps.values.forEach((_info) {
590 MapTypeInformation info = _info;
591 print('${info.type} '
592 'for ${info.originalType.allocationNode} '
593 'at ${info.originalType.allocationElement} '
594 'after ${info.refineCount}');
595 });
596 types.allocatedClosures.forEach((TypeInformation info) {
597 if (info is ElementTypeInformation) {
598 print('${info.getInferredSignature(types)} for '
599 '${info.debugName}');
600 } else if (info is ClosureTypeInformation) {
601 print('${info.getInferredSignature(types)} for '
602 '${info.debugName}');
603 } else if (info is DynamicCallSiteTypeInformation) {
604 for (MemberEntity target in info.targets) {
605 if (target is FunctionEntity) {
606 print(
607 '${types.getInferredSignatureOfMethod(target)} for ${target}') ;
608 } else {
609 print(
610 '${types.getInferredTypeOfMember(target).type} for ${target}') ;
611 }
612 }
613 } else if (info is StaticCallSiteTypeInformation) {
614 ClassEntity cls = info.calledElement.enclosingClass;
615 FunctionEntity callMethod = lookupCallMethod(cls);
616 print('${types.getInferredSignatureOfMethod(callMethod)} for ${cls}');
617 } else {
618 print('${info.type} for some unknown kind of closure');
619 }
620 });
621 analyzedElements.forEach((MemberEntity elem) {
622 TypeInformation type = types.getInferredTypeOfMember(elem);
623 print('${elem} :: ${type} from ${type.assignments} ');
624 });
625 }
626 dump?.afterAnalysis();
627
628 reporter.log('Inferred $overallRefineCount types.');
629
630 processLoopInformation();
631 }
632
633 /// Call [analyze] for all live members.
634 void analyzeAllElements();
635
636 /// Calls [f] for each parameter of [method].
637 void forEachParameter(FunctionEntity method, void f(Local parameter));
638
639 /// Returns the `call` method on [cls] or the `noSuchMethod` if [cls] doesn't
640 /// implement `call`.
641 FunctionEntity lookupCallMethod(ClassEntity cls);
642
643 void analyze(MemberEntity element, T body, ArgumentsTypes arguments) {
644 assert(!(element is MemberElement && !element.isDeclaration));
645 if (analyzedElements.contains(element)) return;
646 analyzedElements.add(element);
647
648 TypeInformation type;
649 reporter.withCurrentElement(element, () {
650 type = computeMemberTypeInformation(element, body);
651 });
652 addedInGraph++;
653
654 if (element.isField) {
655 FieldEntity field = element;
656 if (!field.isAssignable) {
657 // If [element] is final and has an initializer, we record
658 // the inferred type.
659 if (body != null) {
660 if (type is! ListTypeInformation && type is! MapTypeInformation) {
661 // For non-container types, the constant handler does
662 // constant folding that could give more precise results.
663 ConstantValue value = getFieldConstant(field);
664 if (value != null) {
665 if (value.isFunction) {
666 FunctionConstantValue functionConstant = value;
667 FunctionEntity function = functionConstant.element;
668 type = types.allocateClosure(function);
669 } else {
670 // Although we might find a better type, we have to keep
671 // the old type around to ensure that we get a complete view
672 // of the type graph and do not drop any flow edges.
673 TypeMask refinedType = computeTypeMask(closedWorld, value);
674 assert(TypeMask.assertIsNormalized(refinedType, closedWorld));
675 type = new NarrowTypeInformation(type, refinedType);
676 types.allocatedTypes.add(type);
677 }
678 }
679 }
680 recordTypeOfField(field, type);
681 } else if (!element.isInstanceMember) {
682 recordTypeOfField(field, types.nullType);
683 }
684 } else if (body == null) {
685 // Only update types of static fields if there is no
686 // assignment. Instance fields are dealt with in the constructor.
687 if (element.isStatic || element.isTopLevel) {
688 recordTypeOfField(field, type);
689 }
690 } else {
691 recordTypeOfField(field, type);
692 }
693 if ((element.isStatic || element.isTopLevel) &&
694 body != null &&
695 !element.isConst) {
696 if (isFieldInitializerPotentiallyNull(element, body)) {
697 recordTypeOfField(field, types.nullType);
698 }
699 }
700 } else {
701 FunctionEntity method = element;
702 recordReturnType(method, type);
703 }
704 }
705
706 /// Visits [body] to compute the [TypeInformation] node for [member].
707 TypeInformation computeMemberTypeInformation(MemberEntity member, T body);
708
709 /// Returns `true` if the [initializer] of the non-const static or top-level
710 /// [field] is potentially `null`.
711 bool isFieldInitializerPotentiallyNull(FieldEntity field, T initializer);
712
713 /// Returns the [ConstantValue] for the initial value of [field], or
714 /// `null` if the initializer is not a constant value.
715 ConstantValue getFieldConstant(FieldEntity field);
462 716
463 void processLoopInformation() { 717 void processLoopInformation() {
464 types.allocatedCalls.forEach((dynamic info) { 718 types.allocatedCalls.forEach((dynamic info) {
465 if (!info.inLoop) return; 719 if (!info.inLoop) return;
466 if (info is StaticCallSiteTypeInformation) { 720 if (info is StaticCallSiteTypeInformation) {
467 MemberEntity member = info.calledElement; 721 MemberEntity member = info.calledElement;
468 closedWorldRefiner.addFunctionCalledInLoop(member); 722 closedWorldRefiner.addFunctionCalledInLoop(member);
469 } else if (info.mask != null && !info.mask.containsAll(closedWorld)) { 723 } else if (info.mask != null && !info.mask.containsAll(closedWorld)) {
470 // For instance methods, we only register a selector called in a 724 // For instance methods, we only register a selector called in a
471 // loop if it is a typed selector, to avoid marking too many 725 // loop if it is a typed selector, to avoid marking too many
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
511 765
512 void buildWorkQueue() { 766 void buildWorkQueue() {
513 workQueue.addAll(types.orderedTypeInformations); 767 workQueue.addAll(types.orderedTypeInformations);
514 workQueue.addAll(types.allocatedTypes); 768 workQueue.addAll(types.allocatedTypes);
515 workQueue.addAll(types.allocatedClosures); 769 workQueue.addAll(types.allocatedClosures);
516 workQueue.addAll(types.allocatedCalls); 770 workQueue.addAll(types.allocatedCalls);
517 } 771 }
518 772
519 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, 773 void updateParameterAssignments(TypeInformation caller, MemberEntity callee,
520 ArgumentsTypes arguments, Selector selector, TypeMask mask, 774 ArgumentsTypes arguments, Selector selector, TypeMask mask,
521 {bool remove, bool addToQueue: true}); 775 {bool remove, bool addToQueue: true}) {
776 if (callee.name == Identifiers.noSuchMethod_) return;
777 if (callee.isField) {
778 if (selector.isSetter) {
779 ElementTypeInformation info = types.getInferredTypeOfMember(callee);
780 if (remove) {
781 info.removeAssignment(arguments.positional[0]);
782 } else {
783 info.addAssignment(arguments.positional[0]);
784 }
785 if (addToQueue) workQueue.add(info);
786 }
787 } else if (callee.isGetter) {
788 return;
789 } else if (selector != null && selector.isGetter) {
790 // We are tearing a function off and thus create a closure.
791 assert(callee.isFunction);
792 MemberTypeInformation info = types.getInferredTypeOfMember(callee);
793 if (remove) {
794 info.closurizedCount--;
795 } else {
796 info.closurizedCount++;
797 if (callee.isStatic || callee.isTopLevel) {
798 types.allocatedClosures.add(info);
799 } else {
800 // We add the call-site type information here so that we
801 // can benefit from further refinement of the selector.
802 types.allocatedClosures.add(caller);
803 }
804 forEachParameter(callee, (Local parameter) {
805 ParameterTypeInformation info =
806 types.getInferredTypeOfParameter(parameter);
807 info.tagAsTearOffClosureParameter(this);
808 if (addToQueue) workQueue.add(info);
809 });
810 }
811 } else {
812 FunctionEntity method = callee;
813 ParameterStructure parameterStructure = method.parameterStructure;
814 int parameterIndex = 0;
815 forEachParameter(callee, (Local parameter) {
816 TypeInformation type;
817 if (parameterIndex < parameterStructure.requiredParameters) {
818 type = arguments.positional[parameterIndex];
819 } else if (parameterStructure.namedParameters.isNotEmpty) {
820 type = arguments.named[parameter.name];
821 } else if (parameterIndex < arguments.positional.length) {
822 type = arguments.positional[parameterIndex];
823 }
824 if (type == null) type = getDefaultTypeOfParameter(parameter);
825 TypeInformation info = types.getInferredTypeOfParameter(parameter);
826 if (remove) {
827 info.removeAssignment(type);
828 } else {
829 info.addAssignment(type);
830 }
831 parameterIndex++;
832 if (addToQueue) workQueue.add(info);
833 });
834 }
835 }
522 836
523 void setDefaultTypeOfParameter(Local parameter, TypeInformation type, 837 void setDefaultTypeOfParameter(Local parameter, TypeInformation type,
524 {bool isInstanceMember}) { 838 {bool isInstanceMember}) {
525 assert(!(parameter is ParameterElement && !parameter.isImplementation)); 839 assert(!(parameter is ParameterElement && !parameter.isImplementation));
526 TypeInformation existing = defaultTypeOfParameter[parameter]; 840 TypeInformation existing = defaultTypeOfParameter[parameter];
527 defaultTypeOfParameter[parameter] = type; 841 defaultTypeOfParameter[parameter] = type;
528 TypeInformation info = types.getInferredTypeOfParameter(parameter); 842 TypeInformation info = types.getInferredTypeOfParameter(parameter);
529 if (existing != null && existing is PlaceholderTypeInformation) { 843 if (existing != null && existing is PlaceholderTypeInformation) {
530 // Replace references to [existing] to use [type] instead. 844 // Replace references to [existing] to use [type] instead.
531 if (isInstanceMember) { 845 if (isInstanceMember) {
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
774 return returnTypeOfMember(element); 1088 return returnTypeOfMember(element);
775 } 1089 }
776 } else if (element.isGetter || element.isField) { 1090 } else if (element.isGetter || element.isField) {
777 assert(selector.isCall || selector.isSetter); 1091 assert(selector.isCall || selector.isSetter);
778 return types.dynamicType; 1092 return types.dynamicType;
779 } else { 1093 } else {
780 return returnTypeOfMember(element); 1094 return returnTypeOfMember(element);
781 } 1095 }
782 } 1096 }
783 } 1097 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/inferrer/ast_inferrer_engine.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698