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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/inferrer/inferrer_engine.dart
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index 5ed4215b159efb16ca85e4018747508e825b9d1e..9609112faff80551a632817fc43dbd2bf10bffbe 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -8,6 +8,7 @@ import '../common.dart';
import '../common/names.dart';
import '../compiler.dart';
import '../common_elements.dart';
+import '../constants/values.dart';
import '../elements/elements.dart'
show
ClassElement,
@@ -20,16 +21,19 @@ import '../elements/names.dart';
import '../js_backend/annotations.dart';
import '../js_backend/js_backend.dart';
import '../native/behavior.dart' as native;
+import '../types/constants.dart';
import '../types/types.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
import '../universe/side_effects.dart';
import '../world.dart';
+import 'closure_tracer.dart';
import 'debug.dart' as debug;
import 'locals_handler.dart';
import 'list_tracer.dart';
import 'map_tracer.dart';
import 'builder.dart';
+import 'type_graph_dump.dart';
import 'type_graph_inferrer.dart';
import 'type_graph_nodes.dart';
import 'type_system.dart';
@@ -456,9 +460,259 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
workQueue.add(info);
}
- void runOverAllElements();
+ void runOverAllElements() {
+ if (compiler.disableTypeInference) return;
+ if (compiler.options.verbose) {
+ compiler.progress.reset();
+ }
+ analyzeAllElements();
+
+ TypeGraphDump dump = debug.PRINT_GRAPH ? new TypeGraphDump(this) : null;
+
+ dump?.beforeAnalysis();
+ buildWorkQueue();
+ refine();
+
+ // Try to infer element types of lists and compute their escape information.
+ types.allocatedLists.values.forEach((TypeInformation info) {
+ analyzeListAndEnqueue(info);
+ });
+
+ // Try to infer the key and value types for maps and compute the values'
+ // escape information.
+ types.allocatedMaps.values.forEach((TypeInformation info) {
+ analyzeMapAndEnqueue(info);
+ });
+
+ Set<FunctionEntity> bailedOutOn = new Set<FunctionEntity>();
+
+ // Trace closures to potentially infer argument types.
+ types.allocatedClosures.forEach((dynamic info) {
+ void trace(
+ Iterable<FunctionEntity> elements, ClosureTracerVisitor tracer) {
+ tracer.run();
+ if (!tracer.continueAnalyzing) {
+ elements.forEach((FunctionEntity element) {
+ closedWorldRefiner.registerMightBePassedToApply(element);
+ if (debug.VERBOSE) {
+ print("traced closure $element as ${true} (bail)");
+ }
+ forEachParameter(element, (Local parameter) {
+ types
+ .getInferredTypeOfParameter(parameter)
+ .giveUp(this, clearAssignments: false);
+ });
+ });
+ bailedOutOn.addAll(elements);
+ return;
+ }
+ elements
+ .where((e) => !bailedOutOn.contains(e))
+ .forEach((FunctionEntity element) {
+ forEachParameter(element, (Local parameter) {
+ ParameterTypeInformation info =
+ types.getInferredTypeOfParameter(parameter);
+ info.maybeResume();
+ workQueue.add(info);
+ });
+ if (tracer.tracedType.mightBePassedToFunctionApply) {
+ closedWorldRefiner.registerMightBePassedToApply(element);
+ }
+ if (debug.VERBOSE) {
+ print("traced closure $element as "
+ "${closedWorldRefiner
+ .getCurrentlyKnownMightBePassedToApply(element)}");
+ }
+ });
+ }
+
+ if (info is ClosureTypeInformation) {
+ Iterable<FunctionEntity> elements = [info.closure];
+ trace(elements, new ClosureTracerVisitor(elements, info, this));
+ } else if (info is CallSiteTypeInformation) {
+ if (info is StaticCallSiteTypeInformation &&
+ info.selector != null &&
+ info.selector.isCall) {
+ // This is a constructor call to a class with a call method. So we
+ // need to trace the call method here.
+ FunctionEntity calledElement = info.calledElement;
+ assert(calledElement is ConstructorEntity &&
+ calledElement.isGenerativeConstructor);
+ ClassEntity cls = calledElement.enclosingClass;
+ FunctionEntity callMethod = lookupCallMethod(cls);
+ assert(callMethod != null, failedAt(cls));
+ Iterable<FunctionEntity> elements = [callMethod];
+ trace(elements, new ClosureTracerVisitor(elements, info, this));
+ } else {
+ // We only are interested in functions here, as other targets
+ // of this closure call are not a root to trace but an intermediate
+ // for some other function.
+ Iterable<FunctionEntity> elements = new List<FunctionEntity>.from(
+ info.callees.where((e) => e.isFunction));
+ trace(elements, new ClosureTracerVisitor(elements, info, this));
+ }
+ } else if (info is MemberTypeInformation) {
+ trace(<FunctionEntity>[info.member],
+ new StaticTearOffClosureTracerVisitor(info.member, info, this));
+ } else if (info is ParameterTypeInformation) {
+ failedAt(
+ NO_LOCATION_SPANNABLE, 'Unexpected closure allocation info $info');
+ }
+ });
+
+ dump?.beforeTracing();
+
+ // Reset all nodes that use lists/maps that have been inferred, as well
+ // as nodes that use elements fetched from these lists/maps. The
+ // workset for a new run of the analysis will be these nodes.
+ Set<TypeInformation> seenTypes = new Set<TypeInformation>();
+ while (!workQueue.isEmpty) {
+ TypeInformation info = workQueue.remove();
+ if (seenTypes.contains(info)) continue;
+ // If the node cannot be reset, we do not need to update its users either.
+ if (!info.reset(this)) continue;
+ seenTypes.add(info);
+ workQueue.addAll(info.users);
+ }
+
+ workQueue.addAll(seenTypes);
+ refine();
+
+ if (debug.PRINT_SUMMARY) {
+ types.allocatedLists.values.forEach((_info) {
+ ListTypeInformation info = _info;
+ print('${info.type} '
+ 'for ${info.originalType.allocationNode} '
+ 'at ${info.originalType.allocationElement} '
+ 'after ${info.refineCount}');
+ });
+ types.allocatedMaps.values.forEach((_info) {
+ MapTypeInformation info = _info;
+ print('${info.type} '
+ 'for ${info.originalType.allocationNode} '
+ 'at ${info.originalType.allocationElement} '
+ 'after ${info.refineCount}');
+ });
+ types.allocatedClosures.forEach((TypeInformation info) {
+ if (info is ElementTypeInformation) {
+ print('${info.getInferredSignature(types)} for '
+ '${info.debugName}');
+ } else if (info is ClosureTypeInformation) {
+ print('${info.getInferredSignature(types)} for '
+ '${info.debugName}');
+ } else if (info is DynamicCallSiteTypeInformation) {
+ for (MemberEntity target in info.targets) {
+ if (target is FunctionEntity) {
+ print(
+ '${types.getInferredSignatureOfMethod(target)} for ${target}');
+ } else {
+ print(
+ '${types.getInferredTypeOfMember(target).type} for ${target}');
+ }
+ }
+ } else if (info is StaticCallSiteTypeInformation) {
+ ClassEntity cls = info.calledElement.enclosingClass;
+ FunctionEntity callMethod = lookupCallMethod(cls);
+ print('${types.getInferredSignatureOfMethod(callMethod)} for ${cls}');
+ } else {
+ print('${info.type} for some unknown kind of closure');
+ }
+ });
+ analyzedElements.forEach((MemberEntity elem) {
+ TypeInformation type = types.getInferredTypeOfMember(elem);
+ print('${elem} :: ${type} from ${type.assignments} ');
+ });
+ }
+ dump?.afterAnalysis();
+
+ reporter.log('Inferred $overallRefineCount types.');
+
+ processLoopInformation();
+ }
+
+ /// Call [analyze] for all live members.
+ void analyzeAllElements();
- void analyze(MemberEntity element, T body, ArgumentsTypes arguments);
+ /// Calls [f] for each parameter of [method].
+ void forEachParameter(FunctionEntity method, void f(Local parameter));
+
+ /// Returns the `call` method on [cls] or the `noSuchMethod` if [cls] doesn't
+ /// implement `call`.
+ FunctionEntity lookupCallMethod(ClassEntity cls);
+
+ void analyze(MemberEntity element, T body, ArgumentsTypes arguments) {
+ assert(!(element is MemberElement && !element.isDeclaration));
+ if (analyzedElements.contains(element)) return;
+ analyzedElements.add(element);
+
+ TypeInformation type;
+ reporter.withCurrentElement(element, () {
+ type = computeMemberTypeInformation(element, body);
+ });
+ addedInGraph++;
+
+ if (element.isField) {
+ FieldEntity field = element;
+ if (!field.isAssignable) {
+ // If [element] is final and has an initializer, we record
+ // the inferred type.
+ if (body != null) {
+ if (type is! ListTypeInformation && type is! MapTypeInformation) {
+ // For non-container types, the constant handler does
+ // constant folding that could give more precise results.
+ ConstantValue value = getFieldConstant(field);
+ if (value != null) {
+ if (value.isFunction) {
+ FunctionConstantValue functionConstant = value;
+ FunctionEntity function = functionConstant.element;
+ type = types.allocateClosure(function);
+ } else {
+ // Although we might find a better type, we have to keep
+ // the old type around to ensure that we get a complete view
+ // of the type graph and do not drop any flow edges.
+ TypeMask refinedType = computeTypeMask(closedWorld, value);
+ assert(TypeMask.assertIsNormalized(refinedType, closedWorld));
+ type = new NarrowTypeInformation(type, refinedType);
+ types.allocatedTypes.add(type);
+ }
+ }
+ }
+ recordTypeOfField(field, type);
+ } else if (!element.isInstanceMember) {
+ recordTypeOfField(field, types.nullType);
+ }
+ } else if (body == null) {
+ // Only update types of static fields if there is no
+ // assignment. Instance fields are dealt with in the constructor.
+ if (element.isStatic || element.isTopLevel) {
+ recordTypeOfField(field, type);
+ }
+ } else {
+ recordTypeOfField(field, type);
+ }
+ if ((element.isStatic || element.isTopLevel) &&
+ body != null &&
+ !element.isConst) {
+ if (isFieldInitializerPotentiallyNull(element, body)) {
+ recordTypeOfField(field, types.nullType);
+ }
+ }
+ } else {
+ FunctionEntity method = element;
+ recordReturnType(method, type);
+ }
+ }
+
+ /// Visits [body] to compute the [TypeInformation] node for [member].
+ TypeInformation computeMemberTypeInformation(MemberEntity member, T body);
+
+ /// Returns `true` if the [initializer] of the non-const static or top-level
+ /// [field] is potentially `null`.
+ bool isFieldInitializerPotentiallyNull(FieldEntity field, T initializer);
+
+ /// Returns the [ConstantValue] for the initial value of [field], or
+ /// `null` if the initializer is not a constant value.
+ ConstantValue getFieldConstant(FieldEntity field);
void processLoopInformation() {
types.allocatedCalls.forEach((dynamic info) {
@@ -518,7 +772,67 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
void updateParameterAssignments(TypeInformation caller, MemberEntity callee,
ArgumentsTypes arguments, Selector selector, TypeMask mask,
- {bool remove, bool addToQueue: true});
+ {bool remove, bool addToQueue: true}) {
+ if (callee.name == Identifiers.noSuchMethod_) return;
+ if (callee.isField) {
+ if (selector.isSetter) {
+ ElementTypeInformation info = types.getInferredTypeOfMember(callee);
+ if (remove) {
+ info.removeAssignment(arguments.positional[0]);
+ } else {
+ info.addAssignment(arguments.positional[0]);
+ }
+ if (addToQueue) workQueue.add(info);
+ }
+ } else if (callee.isGetter) {
+ return;
+ } else if (selector != null && selector.isGetter) {
+ // We are tearing a function off and thus create a closure.
+ assert(callee.isFunction);
+ MemberTypeInformation info = types.getInferredTypeOfMember(callee);
+ if (remove) {
+ info.closurizedCount--;
+ } else {
+ info.closurizedCount++;
+ if (callee.isStatic || callee.isTopLevel) {
+ types.allocatedClosures.add(info);
+ } else {
+ // We add the call-site type information here so that we
+ // can benefit from further refinement of the selector.
+ types.allocatedClosures.add(caller);
+ }
+ forEachParameter(callee, (Local parameter) {
+ ParameterTypeInformation info =
+ types.getInferredTypeOfParameter(parameter);
+ info.tagAsTearOffClosureParameter(this);
+ if (addToQueue) workQueue.add(info);
+ });
+ }
+ } else {
+ FunctionEntity method = callee;
+ ParameterStructure parameterStructure = method.parameterStructure;
+ int parameterIndex = 0;
+ forEachParameter(callee, (Local parameter) {
+ TypeInformation type;
+ if (parameterIndex < parameterStructure.requiredParameters) {
+ type = arguments.positional[parameterIndex];
+ } else if (parameterStructure.namedParameters.isNotEmpty) {
+ type = arguments.named[parameter.name];
+ } else if (parameterIndex < arguments.positional.length) {
+ type = arguments.positional[parameterIndex];
+ }
+ if (type == null) type = getDefaultTypeOfParameter(parameter);
+ TypeInformation info = types.getInferredTypeOfParameter(parameter);
+ if (remove) {
+ info.removeAssignment(type);
+ } else {
+ info.addAssignment(type);
+ }
+ parameterIndex++;
+ if (addToQueue) workQueue.add(info);
+ });
+ }
+ }
void setDefaultTypeOfParameter(Local parameter, TypeInformation type,
{bool isInstanceMember}) {
« 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