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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart

Issue 119013002: Remove unused file. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | 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
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
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.
4
5 part of type_graph_inferrer;
6
7 /**
8 * A set of selector names that [List] implements, that we know do not
9 * change the element type of the list, or let the list escape to code
10 * that might change the element type.
11 */
12 Set<String> okSelectorsSet = new Set<String>.from(
13 const <String>[
14 // From Object.
15 '==',
16 'hashCode',
17 'toString',
18 'noSuchMethod',
19 'runtimeType',
20
21 // From Iterable.
22 'iterator',
23 'map',
24 'where',
25 'expand',
26 'contains',
27 'forEach',
28 'reduce',
29 'fold',
30 'every',
31 'join',
32 'any',
33 'toList',
34 'toSet',
35 'length',
36 'isEmpty',
37 'isNotEmpty',
38 'take',
39 'takeWhile',
40 'skip',
41 'skipWhile',
42 'first',
43 'last',
44 'single',
45 'firstWhere',
46 'lastWhere',
47 'singleWhere',
48 'elementAt',
49
50 // From List.
51 '[]',
52 'length',
53 'reversed',
54 'sort',
55 'indexOf',
56 'lastIndexOf',
57 'clear',
58 'remove',
59 'removeAt',
60 'removeLast',
61 'removeWhere',
62 'retainWhere',
63 'sublist',
64 'getRange',
65 'removeRange',
66 'asMap',
67
68 // From JSArray.
69 'checkMutable',
70 'checkGrowable',
71 ]);
72
73 Set<String> doNotChangeLengthSelectorsSet = new Set<String>.from(
74 const <String>[
75 // From Object.
76 '==',
77 'hashCode',
78 'toString',
79 'noSuchMethod',
80 'runtimeType',
81
82 // From Iterable.
83 'iterator',
84 'map',
85 'where',
86 'expand',
87 'contains',
88 'forEach',
89 'reduce',
90 'fold',
91 'every',
92 'join',
93 'any',
94 'toList',
95 'toSet',
96 'length',
97 'isEmpty',
98 'isNotEmpty',
99 'take',
100 'takeWhile',
101 'skip',
102 'skipWhile',
103 'first',
104 'last',
105 'single',
106 'firstWhere',
107 'lastWhere',
108 'singleWhere',
109 'elementAt',
110
111 // From List.
112 '[]',
113 '[]=',
114 'length',
115 'reversed',
116 'sort',
117 'indexOf',
118 'lastIndexOf',
119 'sublist',
120 'getRange',
121 'asMap',
122
123 // From JSArray.
124 'checkMutable',
125 'checkGrowable',
126 ]);
127
128 // A set of selectors we know do not escape the elements inside the
129 // list.
130 Set<String> doesNotEscapeElementSet = new Set<String>.from(
131 const <String>[
132 // From Object.
133 '==',
134 'hashCode',
135 'toString',
136 'noSuchMethod',
137 'runtimeType',
138
139 // From Iterable.
140 'isEmpty',
141 'isNotEmpty',
142 'length',
143 'any',
144 'contains',
145 'every',
146 'join',
147
148 // From List.
149 'add',
150 'addAll',
151 'clear',
152 'fillRange',
153 'indexOf',
154 'insert',
155 'insertAll',
156 'lastIndexOf',
157 'remove',
158 'removeRange',
159 'replaceRange',
160 'setAll',
161 'setRange',
162 'shuffle',
163 '[]=',
164
165 // From JSArray.
166 'checkMutable',
167 'checkGrowable',
168 ]);
169
170 bool _VERBOSE = false;
171
172 abstract class TracerVisitor implements TypeInformationVisitor {
173 final TypeInformation tracedType;
174 final TypeGraphInferrerEngine inferrer;
175 final Compiler compiler;
176
177 static const int MAX_ANALYSIS_COUNT = 16;
178 final Setlet<Element> analyzedElements = new Setlet<Element>();
179
180 TracerVisitor(this.tracedType, inferrer)
181 : this.inferrer = inferrer, this.compiler = inferrer.compiler;
182
183 // Work list that gets populated with [TypeInformation] that could
184 // contain the container.
185 final List<TypeInformation> workList = <TypeInformation>[];
186
187 // Work list of containers to analyze after analyzing the users of a
188 // [TypeInformation] that may be [container]. We know [container]
189 // has been stored in these containers and we must check how
190 // [container] escapes from these containers.
191 final List<ListTypeInformation> containersToAnalyze =
192 <ListTypeInformation>[];
193
194 final Setlet<TypeInformation> flowsInto = new Setlet<TypeInformation>();
195
196 // The current [TypeInformation] in the analysis.
197 TypeInformation currentUser;
198 bool continueAnalyzing = true;
199
200 void addNewEscapeInformation(TypeInformation info) {
201 if (flowsInto.contains(info)) return;
202 flowsInto.add(info);
203 workList.add(info);
204 }
205
206 void analyze() {
207 // Collect the [TypeInformation] where the container can flow in,
208 // as well as the operations done on all these [TypeInformation]s.
209 addNewEscapeInformation(tracedType);
210 while (!workList.isEmpty) {
211 currentUser = workList.removeLast();
212 currentUser.users.forEach((TypeInformation info) {
213 analyzedElements.add(info.owner);
214 info.accept(this);
215 });
216 while (!containersToAnalyze.isEmpty) {
217 analyzeStoredIntoContainer(containersToAnalyze.removeLast());
218 }
219 if (!continueAnalyzing) break;
220 if (analyzedElements.length > MAX_ANALYSIS_COUNT) {
221 bailout('Too many users');
222 break;
223 }
224 }
225 }
226
227 void bailout(String reason) {
228 if (_VERBOSE) {
229 print('Bailing out on $tracedType because: $reason');
230 }
231 continueAnalyzing = false;
232 }
233
234 void visitNarrowTypeInformation(NarrowTypeInformation info) {
235 addNewEscapeInformation(info);
236 }
237
238 void visitPhiElementTypeInformation(PhiElementTypeInformation info) {
239 addNewEscapeInformation(info);
240 }
241
242 void visitElementInContainerTypeInformation(
243 ElementInContainerTypeInformation info) {
244 addNewEscapeInformation(info);
245 }
246
247 visitListTypeInformation(ListTypeInformation info) {
248 containersToAnalyze.add(info);
249 }
250
251 void visitConcreteTypeInformation(ConcreteTypeInformation info) {}
252
253 void visitClosureTypeInformation(ClosureTypeInformation info) {}
254
255 void visitClosureCallSiteTypeInformation(
256 ClosureCallSiteTypeInformation info) {}
257
258 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
259 Element called = info.calledElement;
260 if (inferrer.types.getInferredTypeOf(called) == currentUser) {
261 addNewEscapeInformation(info);
262 }
263 }
264
265 void analyzeStoredIntoContainer(ListTypeInformation container) {
266 inferrer.analyzeContainer(container);
267 if (container.bailedOut) {
268 bailout('Stored in a container that bailed out');
269 } else {
270 container.flowsInto.forEach((flow) {
271 flow.users.forEach((user) {
272 if (user is !DynamicCallSiteTypeInformation) return;
273 if (user.receiver != flow) return;
274 if (returnsElementTypeSet.contains(user.selector)) {
275 addNewEscapeInformation(user);
276 } else if (!doesNotEscapeElementSet.contains(user.selector.name)) {
277 bailout('Escape from a container');
278 }
279 });
280 });
281 }
282 }
283
284 bool isAddedToContainer(DynamicCallSiteTypeInformation info) {
285 if (info.arguments == null) return false;
286 var receiverType = info.receiver.type;
287 if (!receiverType.isContainer) return false;
288 String selectorName = info.selector.name;
289 List<TypeInformation> arguments = info.arguments.positional;
290 return (selectorName == '[]=' && currentUser == arguments[1])
291 || (selectorName == 'insert' && currentUser == arguments[0])
292 || (selectorName == 'add' && currentUser == arguments[0]);
293 }
294
295 void visitDynamicCallSiteTypeInformation(
296 DynamicCallSiteTypeInformation info) {
297 if (isAddedToContainer(info)) {
298 ContainerTypeMask mask = info.receiver.type;
299 if (mask.allocationNode != null) {
300 ListTypeInformation container =
301 inferrer.types.allocatedLists[mask.allocationNode];
302 containersToAnalyze.add(container);
303 } else {
304 // The [ContainerTypeMask] is a union of two containers, and
305 // we lose track of where these containers have been allocated
306 // at this point.
307 bailout('Stored in too many containers');
308 }
309 }
310
311 Iterable<Element> inferredTargetTypes = info.targets.map((element) {
312 return inferrer.types.getInferredTypeOf(element);
313 });
314 if (inferredTargetTypes.any((user) => user == currentUser)) {
315 addNewEscapeInformation(info);
316 }
317 }
318
319 bool isParameterOfListAddingMethod(Element element) {
320 if (!element.isParameter()) return false;
321 if (element.getEnclosingClass() != compiler.backend.listImplementation) {
322 return false;
323 }
324 Element method = element.enclosingElement;
325 return (method.name == '[]=')
326 || (method.name == 'add')
327 || (method.name == 'insert');
328 }
329
330 bool isClosure(Element element) {
331 if (!element.isFunction()) return false;
332 Element outermost = element.getOutermostEnclosingMemberOrTopLevel();
333 return outermost.declaration != element.declaration;
334 }
335
336 void visitElementTypeInformation(ElementTypeInformation info) {
337 Element element = info.element;
338 if (element.isParameter()
339 && inferrer.isNativeElement(element.enclosingElement)) {
340 bailout('Passed to a native method');
341 }
342 if (info.isClosurized()) {
343 bailout('Returned from a closurized method');
344 }
345 if (isClosure(info.element)) {
346 bailout('Returned from a closure');
347 }
348 if (compiler.backend.isNeededForReflection(info.element)) {
349 bailout('Escape in reflection');
350 }
351 if (isParameterOfListAddingMethod(info.element)) {
352 // These elements are being handled in
353 // [visitDynamicCallSiteTypeInformation].
354 return;
355 }
356 addNewEscapeInformation(info);
357 }
358 }
359
360 class ContainerTracerVisitor extends TracerVisitor {
361 // The list of found assignments to the container.
362 final List<TypeInformation> assignments = <TypeInformation>[];
363 bool callsGrowableMethod = false;
364
365 ContainerTracerVisitor(tracedType, inferrer) : super(tracedType, inferrer);
366
367 List<TypeInformation> run() {
368 analyze();
369 ListTypeInformation container = tracedType;
370 if (continueAnalyzing) {
371 if (!callsGrowableMethod && container.inferredLength == null) {
372 container.inferredLength = container.originalLength;
373 }
374 container.flowsInto.addAll(flowsInto);
375 return assignments;
376 } else {
377 callsGrowableMethod = true;
378 return null;
379 }
380 }
381
382 visitMapTypeInformation(MapTypeInformation info) {
383 bailout('Stored in a map');
384 }
385
386 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
387 bailout('Passed to a closure');
388 }
389
390 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
391 super.visitStaticCallSiteTypeInformation(info);
392 Element called = info.calledElement;
393 if (called.isForeign(compiler) && called.name == 'JS') {
394 bailout('Used in JS ${info.call}');
395 }
396 }
397
398 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
399 super.visitDynamicCallSiteTypeInformation(info);
400 Selector selector = info.selector;
401 String selectorName = selector.name;
402 if (currentUser == info.receiver) {
403 if (!okSelectorsSet.contains(selectorName)) {
404 if (selector.isCall()) {
405 int positionalLength = info.arguments.positional.length;
406 if (selectorName == 'add') {
407 if (positionalLength == 1) {
408 assignments.add(info.arguments.positional[0]);
409 }
410 } else if (selectorName == 'insert') {
411 if (positionalLength == 2) {
412 assignments.add(info.arguments.positional[1]);
413 }
414 } else {
415 bailout('Used in a not-ok selector');
416 return;
417 }
418 } else if (selector.isIndexSet()) {
419 assignments.add(info.arguments.positional[1]);
420 } else if (!selector.isIndex()) {
421 bailout('Used in a not-ok selector');
422 return;
423 }
424 }
425 if (!doNotChangeLengthSelectorsSet.contains(selectorName)) {
426 callsGrowableMethod = true;
427 }
428 if (selectorName == 'length' && selector.isSetter()) {
429 callsGrowableMethod = true;
430 assignments.add(inferrer.types.nullType);
431 }
432 } else if (selector.isCall()
433 && !info.targets.every((element) => element.isFunction())) {
434 bailout('Passed to a closure');
435 return;
436 }
437 }
438 }
439
440 class ClosureTracerVisitor extends TracerVisitor {
441 ClosureTracerVisitor(tracedType, inferrer) : super(tracedType, inferrer);
442
443 void run() {
444 ClosureTypeInformation closure = tracedType;
445 FunctionElement element = closure.element;
446 element.functionSignature.forEachParameter((Element parameter) {
447 ElementTypeInformation info = inferrer.types.getInferredTypeOf(parameter);
448 info.abandonInferencing = false;
449 });
450 analyze();
451 element.functionSignature.forEachParameter((Element parameter) {
452 ElementTypeInformation info = inferrer.types.getInferredTypeOf(parameter);
453 if (continueAnalyzing) {
454 info.disableHandleSpecialCases = true;
455 } else {
456 info.giveUp(inferrer);
457 }
458 });
459 }
460
461 visitMapTypeInformation(MapTypeInformation info) {
462 bailout('Stored in a map');
463 }
464
465 void analyzeCall(CallSiteTypeInformation info) {
466 ClosureTypeInformation closure = tracedType;
467 FunctionElement element = closure.element;
468 Selector selector = info.selector;
469 if (!selector.signatureApplies(element, compiler)) return;
470 inferrer.updateParameterAssignments(
471 info, element, info.arguments, selector, remove: false,
472 addToQueue: false);
473 }
474
475 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
476 super.visitClosureCallSiteTypeInformation(info);
477 if (info.closure == currentUser) {
478 analyzeCall(info);
479 } else {
480 bailout('Passed to a closure');
481 }
482 }
483
484 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
485 super.visitStaticCallSiteTypeInformation(info);
486 Element called = info.calledElement;
487 if (called.isForeign(compiler) && called.name == 'JS') {
488 bailout('Used in JS ${info.call}');
489 }
490 }
491
492 bool checkIfCurrentUser(element) {
493 return inferrer.types.getInferredTypeOf(element) == currentUser;
494 }
495
496 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
497 super.visitDynamicCallSiteTypeInformation(info);
498 if (info.selector.isCall()) {
499 if (info.arguments.contains(currentUser)
500 && !info.targets.every((element) => element.isFunction())) {
501 bailout('Passed to a closure');
502 } else if (info.targets.any((element) => checkIfCurrentUser(element))) {
503 analyzeCall(info);
504 }
505 }
506 }
507 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698