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

Side by Side Diff: pkg/compiler/lib/src/inferrer/ast_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 | « no previous file | pkg/compiler/lib/src/inferrer/inferrer_engine.dart » ('j') | 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 '../common.dart'; 5 import '../common.dart';
6 import '../common/names.dart'; 6 import '../common/names.dart';
7 import '../compiler.dart'; 7 import '../compiler.dart';
8 import '../constants/expressions.dart'; 8 import '../constants/expressions.dart';
9 import '../constants/values.dart'; 9 import '../constants/values.dart';
10 import '../elements/elements.dart'; 10 import '../elements/elements.dart';
11 import '../elements/entities.dart'; 11 import '../elements/entities.dart';
12 import '../resolution/tree_elements.dart'; 12 import '../resolution/tree_elements.dart';
13 import '../tree/nodes.dart' as ast; 13 import '../tree/nodes.dart' as ast;
14 import '../types/constants.dart';
15 import '../types/types.dart'; 14 import '../types/types.dart';
16 import '../universe/selector.dart';
17 import '../util/util.dart'; 15 import '../util/util.dart';
18 import '../world.dart'; 16 import '../world.dart';
19 import 'closure_tracer.dart';
20 import 'debug.dart' as debug;
21 import 'locals_handler.dart';
22 import 'builder.dart'; 17 import 'builder.dart';
23 import 'builder_kernel.dart'; 18 import 'builder_kernel.dart';
24 import 'inferrer_engine.dart'; 19 import 'inferrer_engine.dart';
25 import 'type_graph_dump.dart';
26 import 'type_graph_nodes.dart'; 20 import 'type_graph_nodes.dart';
27 import 'type_system.dart'; 21 import 'type_system.dart';
28 22
29 class AstInferrerEngine extends InferrerEngineImpl<ast.Node> { 23 class AstInferrerEngine extends InferrerEngineImpl<ast.Node> {
30 AstInferrerEngine(Compiler compiler, ClosedWorld closedWorld, 24 AstInferrerEngine(Compiler compiler, ClosedWorld closedWorld,
31 ClosedWorldRefiner closedWorldRefiner, FunctionEntity mainElement) 25 ClosedWorldRefiner closedWorldRefiner, FunctionEntity mainElement)
32 : super(compiler, closedWorld, closedWorldRefiner, mainElement, 26 : super(compiler, closedWorld, closedWorldRefiner, mainElement,
33 const TypeSystemStrategyImpl()); 27 const TypeSystemStrategyImpl());
34 28
35 GlobalTypeInferenceElementData<ast.Node> createElementData() => 29 GlobalTypeInferenceElementData<ast.Node> createElementData() =>
36 new AstGlobalTypeInferenceElementData(); 30 new AstGlobalTypeInferenceElementData();
37 31
38 void runOverAllElements() { 32 void analyzeAllElements() {
39 if (compiler.disableTypeInference) return;
40 if (compiler.options.verbose) {
41 compiler.progress.reset();
42 }
43 sortResolvedAsts().forEach((ResolvedAst resolvedAst) { 33 sortResolvedAsts().forEach((ResolvedAst resolvedAst) {
44 if (compiler.shouldPrintProgress) { 34 if (compiler.shouldPrintProgress) {
45 reporter.log('Added $addedInGraph elements in inferencing graph.'); 35 reporter.log('Added $addedInGraph elements in inferencing graph.');
46 compiler.progress.reset(); 36 compiler.progress.reset();
47 } 37 }
48 // This also forces the creation of the [ElementTypeInformation] to ensure 38 // This also forces the creation of the [ElementTypeInformation] to ensure
49 // it is in the graph. 39 // it is in the graph.
50 MemberElement member = resolvedAst.element; 40 MemberElement member = resolvedAst.element;
51 ast.Node body; 41 ast.Node body;
52 if (resolvedAst.kind == ResolvedAstKind.PARSED) { 42 if (resolvedAst.kind == ResolvedAstKind.PARSED) {
53 body = resolvedAst.body; 43 body = resolvedAst.body;
54 } 44 }
55 types.withMember(member, () => analyze(member, body, null)); 45 types.withMember(member, () => analyze(member, body, null));
56 }); 46 });
57 reporter.log('Added $addedInGraph elements in inferencing graph.'); 47 reporter.log('Added $addedInGraph elements in inferencing graph.');
58
59 TypeGraphDump dump = debug.PRINT_GRAPH ? new TypeGraphDump(this) : null;
60
61 dump?.beforeAnalysis();
62 buildWorkQueue();
63 refine();
64
65 // Try to infer element types of lists and compute their escape information.
66 types.allocatedLists.values.forEach((TypeInformation info) {
67 analyzeListAndEnqueue(info);
68 });
69
70 // Try to infer the key and value types for maps and compute the values'
71 // escape information.
72 types.allocatedMaps.values.forEach((TypeInformation info) {
73 analyzeMapAndEnqueue(info);
74 });
75
76 Set<FunctionEntity> bailedOutOn = new Set<FunctionEntity>();
77
78 // Trace closures to potentially infer argument types.
79 types.allocatedClosures.forEach((dynamic info) {
80 void trace(
81 Iterable<FunctionEntity> elements, ClosureTracerVisitor tracer) {
82 tracer.run();
83 if (!tracer.continueAnalyzing) {
84 elements.forEach((FunctionEntity _element) {
85 MethodElement element = _element;
86 MethodElement implementation = element.implementation;
87 closedWorldRefiner.registerMightBePassedToApply(element);
88 if (debug.VERBOSE) {
89 print("traced closure $element as ${true} (bail)");
90 }
91 implementation.functionSignature
92 .forEachParameter((FormalElement _parameter) {
93 ParameterElement parameter = _parameter;
94 types
95 .getInferredTypeOfParameter(parameter)
96 .giveUp(this, clearAssignments: false);
97 });
98 });
99 bailedOutOn.addAll(elements);
100 return;
101 }
102 elements
103 .where((e) => !bailedOutOn.contains(e))
104 .forEach((FunctionEntity _element) {
105 MethodElement element = _element;
106 MethodElement implementation = element.implementation;
107 implementation.functionSignature
108 .forEachParameter((FormalElement _parameter) {
109 ParameterElement parameter = _parameter;
110 ParameterTypeInformation info =
111 types.getInferredTypeOfParameter(parameter);
112 info.maybeResume();
113 workQueue.add(info);
114 });
115 if (tracer.tracedType.mightBePassedToFunctionApply) {
116 closedWorldRefiner.registerMightBePassedToApply(element);
117 }
118 if (debug.VERBOSE) {
119 print("traced closure $element as "
120 "${closedWorldRefiner
121 .getCurrentlyKnownMightBePassedToApply(element)}");
122 }
123 });
124 }
125
126 if (info is ClosureTypeInformation) {
127 Iterable<FunctionEntity> elements = [info.closure];
128 trace(elements, new ClosureTracerVisitor(elements, info, this));
129 } else if (info is CallSiteTypeInformation) {
130 if (info is StaticCallSiteTypeInformation &&
131 info.selector != null &&
132 info.selector.isCall) {
133 // This is a constructor call to a class with a call method. So we
134 // need to trace the call method here.
135 MethodElement calledElement = info.calledElement;
136 assert(calledElement.isGenerativeConstructor);
137 ClassElement cls = calledElement.enclosingClass;
138 MethodElement callMethod = cls.lookupMember(Identifiers.call);
139 if (callMethod == null) {
140 callMethod = cls.lookupMember(Identifiers.noSuchMethod_);
141 }
142 assert(callMethod != null, failedAt(cls));
143 Iterable<FunctionEntity> elements = [callMethod];
144 trace(elements, new ClosureTracerVisitor(elements, info, this));
145 } else {
146 // We only are interested in functions here, as other targets
147 // of this closure call are not a root to trace but an intermediate
148 // for some other function.
149 Iterable<FunctionEntity> elements = new List<FunctionEntity>.from(
150 info.callees.where((e) => e.isFunction));
151 trace(elements, new ClosureTracerVisitor(elements, info, this));
152 }
153 } else if (info is MemberTypeInformation) {
154 trace(<FunctionEntity>[info.member],
155 new StaticTearOffClosureTracerVisitor(info.member, info, this));
156 } else if (info is ParameterTypeInformation) {
157 failedAt(
158 NO_LOCATION_SPANNABLE, 'Unexpected closure allocation info $info');
159 }
160 });
161
162 dump?.beforeTracing();
163
164 // Reset all nodes that use lists/maps that have been inferred, as well
165 // as nodes that use elements fetched from these lists/maps. The
166 // workset for a new run of the analysis will be these nodes.
167 Set<TypeInformation> seenTypes = new Set<TypeInformation>();
168 while (!workQueue.isEmpty) {
169 TypeInformation info = workQueue.remove();
170 if (seenTypes.contains(info)) continue;
171 // If the node cannot be reset, we do not need to update its users either.
172 if (!info.reset(this)) continue;
173 seenTypes.add(info);
174 workQueue.addAll(info.users);
175 }
176
177 workQueue.addAll(seenTypes);
178 refine();
179
180 if (debug.PRINT_SUMMARY) {
181 types.allocatedLists.values.forEach((_info) {
182 ListTypeInformation info = _info;
183 print('${info.type} '
184 'for ${info.originalType.allocationNode} '
185 'at ${info.originalType.allocationElement} '
186 'after ${info.refineCount}');
187 });
188 types.allocatedMaps.values.forEach((_info) {
189 MapTypeInformation info = _info;
190 print('${info.type} '
191 'for ${info.originalType.allocationNode} '
192 'at ${info.originalType.allocationElement} '
193 'after ${info.refineCount}');
194 });
195 types.allocatedClosures.forEach((TypeInformation info) {
196 if (info is ElementTypeInformation) {
197 print('${info.getInferredSignature(types)} for '
198 '${info.debugName}');
199 } else if (info is ClosureTypeInformation) {
200 print('${info.getInferredSignature(types)} for '
201 '${info.debugName}');
202 } else if (info is DynamicCallSiteTypeInformation) {
203 for (MemberEntity target in info.targets) {
204 if (target is FunctionEntity) {
205 print(
206 '${types.getInferredSignatureOfMethod(target)} for ${target}') ;
207 } else {
208 print(
209 '${types.getInferredTypeOfMember(target).type} for ${target}') ;
210 }
211 }
212 } else if (info is StaticCallSiteTypeInformation) {
213 ClassElement cls = info.calledElement.enclosingClass;
214 MethodElement callMethod = cls.lookupMember(Identifiers.call);
215 print('${types.getInferredSignatureOfMethod(callMethod)} for ${cls}');
216 } else {
217 print('${info.type} for some unknown kind of closure');
218 }
219 });
220 analyzedElements.forEach((MemberEntity elem) {
221 TypeInformation type = types.getInferredTypeOfMember(elem);
222 print('${elem} :: ${type} from ${type.assignments} ');
223 });
224 }
225 dump?.afterAnalysis();
226
227 reporter.log('Inferred $overallRefineCount types.');
228
229 processLoopInformation();
230 } 48 }
231 49
232 void analyze(MemberEntity element, ast.Node body, ArgumentsTypes arguments) { 50 void forEachParameter(
233 assert(!(element is MemberElement && !element.isDeclaration)); 51 covariant MethodElement method, void f(Local parameter)) {
234 if (analyzedElements.contains(element)) return; 52 MethodElement implementation = method.implementation;
235 analyzedElements.add(element); 53 implementation.functionSignature
236 54 .forEachParameter((FormalElement _parameter) {
237 dynamic visitor = compiler.options.kernelGlobalInference 55 ParameterElement parameter = _parameter;
238 ? new KernelTypeGraphBuilder(element, compiler, this) 56 f(parameter);
239 : new ElementGraphBuilder(element, compiler, this);
240 TypeInformation type;
241 reporter.withCurrentElement(element, () {
242 // ignore: UNDEFINED_METHOD
243 type = visitor.run();
244 }); 57 });
245 addedInGraph++;
246
247 if (element.isField) {
248 FieldElement field = element;
249 if (field.isFinal || field.isConst) {
250 // If [element] is final and has an initializer, we record
251 // the inferred type.
252 if (body != null) {
253 if (type is! ListTypeInformation && type is! MapTypeInformation) {
254 // For non-container types, the constant handler does
255 // constant folding that could give more precise results.
256 ConstantExpression constant = field.constant;
257 if (constant != null) {
258 ConstantValue value =
259 compiler.backend.constants.getConstantValue(constant);
260 if (value != null) {
261 if (value.isFunction) {
262 FunctionConstantValue functionConstant = value;
263 MethodElement function = functionConstant.element;
264 type = types.allocateClosure(function);
265 } else {
266 // Although we might find a better type, we have to keep
267 // the old type around to ensure that we get a complete view
268 // of the type graph and do not drop any flow edges.
269 TypeMask refinedType = computeTypeMask(closedWorld, value);
270 assert(TypeMask.assertIsNormalized(refinedType, closedWorld));
271 type = new NarrowTypeInformation(type, refinedType);
272 types.allocatedTypes.add(type);
273 }
274 } else {
275 assert(
276 field.isInstanceMember ||
277 constant.isImplicit ||
278 constant.isPotential,
279 failedAt(
280 field,
281 "Constant expression without value: "
282 "${constant.toStructuredText()}."));
283 }
284 }
285 }
286 recordTypeOfField(field, type);
287 } else if (!element.isInstanceMember) {
288 recordTypeOfField(field, types.nullType);
289 }
290 } else if (body == null) {
291 // Only update types of static fields if there is no
292 // assignment. Instance fields are dealt with in the constructor.
293 if (element.isStatic || element.isTopLevel) {
294 recordTypeOfField(field, type);
295 }
296 } else {
297 recordTypeOfField(field, type);
298 }
299 if ((element.isStatic || element.isTopLevel) &&
300 body != null &&
301 !element.isConst) {
302 dynamic argument = body;
303 // TODO(13429): We could do better here by using the
304 // constant handler to figure out if it's a lazy field or not.
305 if (argument.asSend() != null ||
306 (argument.asNewExpression() != null && !argument.isConst)) {
307 recordTypeOfField(field, types.nullType);
308 }
309 }
310 } else {
311 FunctionEntity method = element;
312 recordReturnType(method, type);
313 }
314 } 58 }
315 59
316 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, 60 FunctionEntity lookupCallMethod(covariant ClassElement cls) {
317 ArgumentsTypes arguments, Selector selector, TypeMask mask, 61 MethodElement callMethod = cls.lookupMember(Identifiers.call);
318 {bool remove, bool addToQueue: true}) { 62 if (callMethod == null) {
319 if (callee.name == Identifiers.noSuchMethod_) return; 63 callMethod = cls.lookupMember(Identifiers.noSuchMethod_);
320 if (callee.isField) { 64 }
321 if (selector.isSetter) { 65 return callMethod;
322 ElementTypeInformation info = types.getInferredTypeOfMember(callee); 66 }
323 if (remove) { 67
324 info.removeAssignment(arguments.positional[0]); 68 TypeInformation computeMemberTypeInformation(
325 } else { 69 MemberEntity member, ast.Node body) {
326 info.addAssignment(arguments.positional[0]); 70 dynamic visitor = compiler.options.kernelGlobalInference
327 } 71 ? new KernelTypeGraphBuilder(member, compiler, this)
328 if (addToQueue) workQueue.add(info); 72 : new ElementGraphBuilder(member, compiler, this);
73 // ignore: UNDEFINED_METHOD
74 return visitor.run();
75 }
76
77 bool isFieldInitializerPotentiallyNull(
78 FieldEntity field, ast.Node initializer) {
79 dynamic argument = initializer;
80 // TODO(13429): We could do better here by using the
81 // constant handler to figure out if it's a lazy field or not.
82 return argument.asSend() != null ||
83 (argument.asNewExpression() != null && !argument.isConst);
84 }
85
86 ConstantValue getFieldConstant(covariant FieldElement field) {
87 ConstantExpression constant = field.constant;
88 if (constant != null) {
89 ConstantValue value =
90 compiler.backend.constants.getConstantValue(constant);
91 if (value == null) {
92 assert(
93 field.isInstanceMember ||
94 constant.isImplicit ||
95 constant.isPotential,
96 failedAt(
97 field,
98 "Constant expression without value: "
99 "${constant.toStructuredText()}."));
329 } 100 }
330 } else if (callee.isGetter) { 101 return value;
331 return;
332 } else if (selector != null && selector.isGetter) {
333 // We are tearing a function off and thus create a closure.
334 assert(callee.isFunction);
335 MethodElement method = callee;
336 MemberTypeInformation info = types.getInferredTypeOfMember(method);
337 if (remove) {
338 info.closurizedCount--;
339 } else {
340 info.closurizedCount++;
341 if (Elements.isStaticOrTopLevel(method)) {
342 types.allocatedClosures.add(info);
343 } else {
344 // We add the call-site type information here so that we
345 // can benefit from further refinement of the selector.
346 types.allocatedClosures.add(caller);
347 }
348 FunctionElement function = method.implementation;
349 FunctionSignature signature = function.functionSignature;
350 signature.forEachParameter((FormalElement _parameter) {
351 ParameterElement parameter = _parameter;
352 ParameterTypeInformation info =
353 types.getInferredTypeOfParameter(parameter);
354 info.tagAsTearOffClosureParameter(this);
355 if (addToQueue) workQueue.add(info);
356 });
357 }
358 } else {
359 MethodElement method = callee;
360 FunctionElement function = method.implementation;
361 FunctionSignature signature = function.functionSignature;
362 int parameterIndex = 0;
363 bool visitingRequiredParameter = true;
364 signature.forEachParameter((FormalElement _parameter) {
365 ParameterElement parameter = _parameter;
366 if (signature.hasOptionalParameters &&
367 parameter == signature.optionalParameters.first) {
368 visitingRequiredParameter = false;
369 }
370 TypeInformation type = visitingRequiredParameter
371 ? arguments.positional[parameterIndex]
372 : signature.optionalParametersAreNamed
373 ? arguments.named[parameter.name]
374 : parameterIndex < arguments.positional.length
375 ? arguments.positional[parameterIndex]
376 : null;
377 if (type == null) type = getDefaultTypeOfParameter(parameter);
378 TypeInformation info = types.getInferredTypeOfParameter(parameter);
379 if (remove) {
380 info.removeAssignment(type);
381 } else {
382 info.addAssignment(type);
383 }
384 parameterIndex++;
385 if (addToQueue) workQueue.add(info);
386 });
387 } 102 }
103 return null;
388 } 104 }
389 105
390 // Sorts the resolved elements by size. We do this for this inferrer 106 // Sorts the resolved elements by size. We do this for this inferrer
391 // to get the same results for [ListTracer] compared to the 107 // to get the same results for [ListTracer] compared to the
392 // [SimpleTypesInferrer]. 108 // [SimpleTypesInferrer].
393 Iterable<ResolvedAst> sortResolvedAsts() { 109 Iterable<ResolvedAst> sortResolvedAsts() {
394 int max = 0; 110 int max = 0;
395 Map<int, Setlet<ResolvedAst>> methodSizes = <int, Setlet<ResolvedAst>>{}; 111 Map<int, Setlet<ResolvedAst>> methodSizes = <int, Setlet<ResolvedAst>>{};
396 compiler.enqueuer.resolution.processedEntities.forEach((_element) { 112 compiler.enqueuer.resolution.processedEntities.forEach((_element) {
397 MemberElement element = _element; 113 MemberElement element = _element;
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
521 @override 237 @override
522 bool checkPhiNode(ast.Node node) { 238 bool checkPhiNode(ast.Node node) {
523 return true; 239 return true;
524 } 240 }
525 241
526 @override 242 @override
527 bool checkClassEntity(covariant ClassElement cls) { 243 bool checkClassEntity(covariant ClassElement cls) {
528 return cls.isDeclaration; 244 return cls.isDeclaration;
529 } 245 }
530 } 246 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/inferrer/inferrer_engine.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698