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

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

Issue 116443002: Revert "Implement tracing for function expressions and statements, and infer types of parameters of… (Closed) Base URL: https://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 | sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.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) 2013, the Dart project authors. Please see the AUTHORS file 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 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 part of type_graph_inferrer; 5 part of type_graph_inferrer;
6 6
7 /** 7 /**
8 * A set of selector names that [List] implements, that we know do not 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 9 * change the element type of the list, or let the list escape to code
10 * that might change the element type. 10 * that might change the element type.
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 'shuffle', 162 'shuffle',
163 '[]=', 163 '[]=',
164 164
165 // From JSArray. 165 // From JSArray.
166 'checkMutable', 166 'checkMutable',
167 'checkGrowable', 167 'checkGrowable',
168 ]); 168 ]);
169 169
170 bool _VERBOSE = false; 170 bool _VERBOSE = false;
171 171
172 abstract class TracerVisitor implements TypeInformationVisitor { 172 class ContainerTracerVisitor implements TypeInformationVisitor {
173 final TypeInformation tracedType; 173 final ListTypeInformation container;
174 final TypeGraphInferrerEngine inferrer; 174 final TypeGraphInferrerEngine inferrer;
175 final Compiler compiler; 175 final Compiler compiler;
176 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 177
183 // Work list that gets populated with [TypeInformation] that could 178 // Work list that gets populated with [TypeInformation] that could
184 // contain the container. 179 // contain the container.
185 final List<TypeInformation> workList = <TypeInformation>[]; 180 final List<TypeInformation> workList = <TypeInformation>[];
186 181
187 // Work list of containers to analyze after analyzing the users of a 182 // Work list of containers to analyze after analyzing the users of a
188 // [TypeInformation] that may be [container]. We know [container] 183 // [TypeInformation] that may be [container]. We know [container]
189 // has been stored in these containers and we must check how 184 // has been stored in these containers and we must check how
190 // [container] escapes from these containers. 185 // [container] escapes from these containers.
191 final List<ListTypeInformation> containersToAnalyze = 186 final List<ListTypeInformation> containersToAnalyze =
192 <ListTypeInformation>[]; 187 <ListTypeInformation>[];
193 188
194 final Setlet<TypeInformation> flowsInto = new Setlet<TypeInformation>();
195
196 // The current [TypeInformation] in the analysis. 189 // The current [TypeInformation] in the analysis.
197 TypeInformation currentUser; 190 TypeInformation currentUser;
191
192 // The list of found assignments to the container.
193 final List<TypeInformation> assignments = <TypeInformation>[];
194
195 bool callsGrowableMethod = false;
198 bool continueAnalyzing = true; 196 bool continueAnalyzing = true;
197
198 static const int MAX_ANALYSIS_COUNT = 16;
199 final Setlet<Element> analyzedElements = new Setlet<Element>();
200
201 ContainerTracerVisitor(this.container, inferrer)
202 : this.inferrer = inferrer, this.compiler = inferrer.compiler;
199 203
200 void addNewEscapeInformation(TypeInformation info) { 204 void addNewEscapeInformation(TypeInformation info) {
201 if (flowsInto.contains(info)) return; 205 if (container.flowsInto.contains(info)) return;
202 flowsInto.add(info); 206 container.flowsInto.add(info);
203 workList.add(info); 207 workList.add(info);
204 } 208 }
205 209
206 void analyze() { 210 List<TypeInformation> run() {
207 // Collect the [TypeInformation] where the container can flow in, 211 // Collect the [TypeInformation] where the container can flow in,
208 // as well as the operations done on all these [TypeInformation]s. 212 // as well as the operations done on all these [TypeInformation]s.
209 addNewEscapeInformation(tracedType); 213 addNewEscapeInformation(container);
210 while (!workList.isEmpty) { 214 while (!workList.isEmpty) {
211 currentUser = workList.removeLast(); 215 currentUser = workList.removeLast();
212 currentUser.users.forEach((TypeInformation info) { 216 currentUser.users.forEach((TypeInformation info) {
213 analyzedElements.add(info.owner); 217 analyzedElements.add(info.owner);
214 info.accept(this); 218 info.accept(this);
215 }); 219 });
216 while (!containersToAnalyze.isEmpty) { 220 while (!containersToAnalyze.isEmpty) {
217 analyzeStoredIntoContainer(containersToAnalyze.removeLast()); 221 analyzeStoredIntoContainer(containersToAnalyze.removeLast());
218 } 222 }
219 if (!continueAnalyzing) break; 223 if (!continueAnalyzing) break;
220 if (analyzedElements.length > MAX_ANALYSIS_COUNT) { 224 if (analyzedElements.length > MAX_ANALYSIS_COUNT) {
221 bailout('Too many users'); 225 bailout('Too many users');
222 break; 226 break;
223 } 227 }
224 } 228 }
229
230 if (continueAnalyzing) {
231 if (!callsGrowableMethod && container.inferredLength == null) {
232 container.inferredLength = container.originalLength;
233 }
234 return assignments;
235 }
236 return null;
225 } 237 }
226 238
227 void bailout(String reason) { 239 void bailout(String reason) {
228 if (_VERBOSE) { 240 if (_VERBOSE) {
229 print('Bailing out on $tracedType because: $reason'); 241 ContainerTypeMask mask = container.type;
242 print('Bailing out on ${mask.allocationNode} ${mask.allocationElement} '
243 'because: $reason');
230 } 244 }
231 continueAnalyzing = false; 245 continueAnalyzing = false;
246 callsGrowableMethod = true;
232 } 247 }
233 248
234 void visitNarrowTypeInformation(NarrowTypeInformation info) { 249 visitNarrowTypeInformation(NarrowTypeInformation info) {
235 addNewEscapeInformation(info); 250 addNewEscapeInformation(info);
236 } 251 }
237 252
238 void visitPhiElementTypeInformation(PhiElementTypeInformation info) { 253 visitPhiElementTypeInformation(PhiElementTypeInformation info) {
239 addNewEscapeInformation(info); 254 addNewEscapeInformation(info);
240 } 255 }
241 256
242 void visitElementInContainerTypeInformation( 257 visitElementInContainerTypeInformation(
243 ElementInContainerTypeInformation info) { 258 ElementInContainerTypeInformation info) {
244 addNewEscapeInformation(info); 259 addNewEscapeInformation(info);
245 } 260 }
246 261
247 visitListTypeInformation(ListTypeInformation info) { 262 visitListTypeInformation(ListTypeInformation info) {
248 containersToAnalyze.add(info); 263 containersToAnalyze.add(info);
249 } 264 }
250 265
251 void visitConcreteTypeInformation(ConcreteTypeInformation info) {} 266 visitMapTypeInformation(MapTypeInformation info) {
267 bailout('Stored in a map');
268 }
252 269
253 void visitClosureTypeInformation(ConcreteTypeInformation info) {} 270 visitConcreteTypeInformation(ConcreteTypeInformation info) {}
254 271
255 void visitClosureCallSiteTypeInformation( 272 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
256 ClosureCallSiteTypeInformation info) {} 273 bailout('Passed to a closure');
274 }
257 275
258 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { 276 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
259 Element called = info.calledElement; 277 Element called = info.calledElement;
278 if (called.isForeign(compiler) && called.name == 'JS') {
279 bailout('Used in JS ${info.call}');
280 }
260 if (inferrer.types.getInferredTypeOf(called) == currentUser) { 281 if (inferrer.types.getInferredTypeOf(called) == currentUser) {
261 addNewEscapeInformation(info); 282 addNewEscapeInformation(info);
262 } 283 }
263 } 284 }
264 285
265 void analyzeStoredIntoContainer(ListTypeInformation container) { 286 void analyzeStoredIntoContainer(ListTypeInformation container) {
266 inferrer.analyzeContainer(container); 287 inferrer.analyzeContainer(container);
267 if (container.bailedOut) { 288 if (container.bailedOut) {
268 bailout('Stored in a container that bailed out'); 289 bailout('Stored in a container that bailed out');
269 } else { 290 } else {
270 container.flowsInto.forEach((flow) { 291 container.flowsInto.forEach((flow) {
271 flow.users.forEach((user) { 292 flow.users.forEach((user) {
272 if (user is !DynamicCallSiteTypeInformation) return; 293 if (user is !DynamicCallSiteTypeInformation) return;
273 if (user.receiver != flow) return; 294 if (user.receiver != flow) return;
274 if (returnsElementTypeSet.contains(user.selector)) { 295 if (returnsElementTypeSet.contains(user.selector)) {
275 addNewEscapeInformation(user); 296 addNewEscapeInformation(user);
276 } else if (!doesNotEscapeElementSet.contains(user.selector.name)) { 297 } else if (!doesNotEscapeElementSet.contains(user.selector.name)) {
277 bailout('Escape from a container'); 298 bailout('Escape from a container');
278 } 299 }
279 }); 300 });
280 }); 301 });
281 } 302 }
282 } 303 }
283 304
284 bool isAddedToContainer(DynamicCallSiteTypeInformation info) { 305 bool isAddedToContainer(DynamicCallSiteTypeInformation info) {
285 if (info.arguments == null) return false;
286 var receiverType = info.receiver.type; 306 var receiverType = info.receiver.type;
287 if (!receiverType.isContainer) return false; 307 if (!receiverType.isContainer) return false;
288 String selectorName = info.selector.name; 308 String selectorName = info.selector.name;
289 List<TypeInformation> arguments = info.arguments.positional; 309 List<TypeInformation> arguments = info.arguments.positional;
290 return (selectorName == '[]=' && currentUser == arguments[1]) 310 return (selectorName == '[]=' && currentUser == arguments[1])
291 || (selectorName == 'insert' && currentUser == arguments[0]) 311 || (selectorName == 'insert' && currentUser == arguments[0])
292 || (selectorName == 'add' && currentUser == arguments[0]); 312 || (selectorName == 'add' && currentUser == arguments[0]);
293 } 313 }
294 314
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 void visitElementTypeInformation(ElementTypeInformation info) {
331 if (isParameterOfListAddingMethod(info.element)) {
332 // These elements are being handled in
333 // [visitDynamicCallSiteTypeInformation].
334 return;
335 }
336 addNewEscapeInformation(info);
337 }
338 }
339
340 class ContainerTracerVisitor extends TracerVisitor {
341 // The list of found assignments to the container.
342 final List<TypeInformation> assignments = <TypeInformation>[];
343 bool callsGrowableMethod = false;
344
345 ContainerTracerVisitor(tracedType, inferrer) : super(tracedType, inferrer);
346
347 List<TypeInformation> run() {
348 analyze();
349 ListTypeInformation container = tracedType;
350 if (continueAnalyzing) {
351 if (!callsGrowableMethod && container.inferredLength == null) {
352 container.inferredLength = container.originalLength;
353 }
354 container.flowsInto.addAll(flowsInto);
355 return assignments;
356 } else {
357 callsGrowableMethod = true;
358 return null;
359 }
360 }
361
362 visitMapTypeInformation(MapTypeInformation info) {
363 bailout('Stored in a map');
364 }
365
366 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
367 bailout('Passed to a closure');
368 }
369
370 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
371 super.visitStaticCallSiteTypeInformation(info);
372 Element called = info.calledElement;
373 if (called.isForeign(compiler) && called.name == 'JS') {
374 bailout('Used in JS ${info.call}');
375 }
376 }
377
378 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) { 315 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
379 super.visitDynamicCallSiteTypeInformation(info);
380 Selector selector = info.selector; 316 Selector selector = info.selector;
381 String selectorName = selector.name; 317 String selectorName = selector.name;
382 if (currentUser == info.receiver) { 318 if (currentUser == info.receiver) {
383 if (!okSelectorsSet.contains(selectorName)) { 319 if (!okSelectorsSet.contains(selectorName)) {
384 if (selector.isCall()) { 320 if (selector.isCall()) {
385 int positionalLength = info.arguments.positional.length; 321 int positionalLength = info.arguments.positional.length;
386 if (selectorName == 'add') { 322 if (selectorName == 'add') {
387 if (positionalLength == 1) { 323 if (positionalLength == 1) {
388 assignments.add(info.arguments.positional[0]); 324 assignments.add(info.arguments.positional[0]);
389 } 325 }
(...skipping 16 matching lines...) Expand all
406 callsGrowableMethod = true; 342 callsGrowableMethod = true;
407 } 343 }
408 if (selectorName == 'length' && selector.isSetter()) { 344 if (selectorName == 'length' && selector.isSetter()) {
409 callsGrowableMethod = true; 345 callsGrowableMethod = true;
410 assignments.add(inferrer.types.nullType); 346 assignments.add(inferrer.types.nullType);
411 } 347 }
412 } else if (selector.isCall() 348 } else if (selector.isCall()
413 && !info.targets.every((element) => element.isFunction())) { 349 && !info.targets.every((element) => element.isFunction())) {
414 bailout('Passed to a closure'); 350 bailout('Passed to a closure');
415 return; 351 return;
352 } else if (isAddedToContainer(info)) {
353 ContainerTypeMask mask = info.receiver.type;
354 if (mask.allocationNode != null) {
355 ListTypeInformation container =
356 inferrer.types.allocatedLists[mask.allocationNode];
357 containersToAnalyze.add(container);
358 } else {
359 // The [ContainerTypeMask] is a union of two containers, and
360 // we lose track of where these containers have been allocated
361 // at this point.
362 bailout('Stored in too many containers');
363 }
364 }
365
366 if (info.targets
367 .map((element) => inferrer.types.getInferredTypeOf(element))
368 .any((other) => other == currentUser)) {
369 addNewEscapeInformation(info);
416 } 370 }
417 } 371 }
418 372
419 bool isClosure(Element element) {
420 if (!element.isFunction()) return false;
421 Element outermost = element.getOutermostEnclosingMemberOrTopLevel();
422 return outermost.declaration != element.declaration;
423 }
424
425 visitElementTypeInformation(ElementTypeInformation info) {
426 super.visitElementTypeInformation(info);
427 if (isClosure(info.element)) {
428 bailout('Returned from a closure');
429 }
430 if (compiler.backend.isNeededForReflection(info.element)) {
431 bailout('Escape in reflection');
432 }
433 }
434 }
435
436 class ClosureTracerVisitor extends TracerVisitor {
437 ClosureTracerVisitor(tracedType, inferrer) : super(tracedType, inferrer);
438
439 void run() {
440 ClosureTypeInformation closure = tracedType;
441 FunctionElement element = closure.element;
442 element.functionSignature.forEachParameter((Element parameter) {
443 ElementTypeInformation info = inferrer.types.getInferredTypeOf(parameter);
444 info.abandonInferencing = false;
445 });
446 analyze();
447 element.functionSignature.forEachParameter((Element parameter) {
448 ElementTypeInformation info = inferrer.types.getInferredTypeOf(parameter);
449 if (continueAnalyzing) {
450 info.disableHandleSpecialCases = true;
451 } else {
452 info.giveUp(inferrer);
453 }
454 });
455 }
456
457 visitMapTypeInformation(MapTypeInformation info) {
458 bailout('Stored in a map');
459 }
460
461 void analyzeCall(CallSiteTypeInformation info) {
462 ClosureTypeInformation closure = tracedType;
463 FunctionElement element = closure.element;
464 Selector selector = info.selector;
465 if (!selector.signatureApplies(element, compiler)) return;
466 inferrer.updateParameterAssignments(
467 info, element, info.arguments, selector, remove: false,
468 addToQueue: false);
469 }
470
471 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
472 super.visitClosureCallSiteTypeInformation(info);
473 if (info.closure == currentUser) {
474 analyzeCall(info);
475 } else {
476 bailout('Passed to a closure');
477 }
478 }
479
480 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
481 super.visitStaticCallSiteTypeInformation(info);
482 Element called = info.calledElement;
483 if (called.isForeign(compiler) && called.name == 'JS') {
484 bailout('Used in JS ${info.call}');
485 }
486 }
487
488 bool checkIfCurrentUser(element) {
489 return inferrer.types.getInferredTypeOf(element) == currentUser;
490 }
491
492 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
493 super.visitDynamicCallSiteTypeInformation(info);
494 if (info.selector.isCall()) {
495 if (info.arguments.contains(currentUser)
496 && !info.targets.every((element) => element.isFunction())) {
497 bailout('Passed to a closure');
498 } else if (info.targets.any((element) => checkIfCurrentUser(element))) {
499 analyzeCall(info);
500 }
501 }
502 }
503
504 bool isClosure(Element element) { 373 bool isClosure(Element element) {
505 if (!element.isFunction()) return false; 374 if (!element.isFunction()) return false;
506 Element outermost = element.getOutermostEnclosingMemberOrTopLevel(); 375 Element outermost = element.getOutermostEnclosingMemberOrTopLevel();
507 return outermost.declaration != element.declaration; 376 return outermost.declaration != element.declaration;
508 } 377 }
509 378
379 bool isParameterOfListAddingMethod(Element element) {
380 if (!element.isParameter()) return false;
381 if (element.getEnclosingClass() != compiler.backend.listImplementation) {
382 return false;
383 }
384 Element method = element.enclosingElement;
385 return (method.name == '[]=')
386 || (method.name == 'add')
387 || (method.name == 'insert');
388 }
389
510 visitElementTypeInformation(ElementTypeInformation info) { 390 visitElementTypeInformation(ElementTypeInformation info) {
511 super.visitElementTypeInformation(info);
512 if (isClosure(info.element)) { 391 if (isClosure(info.element)) {
513 bailout('Returned from a closure'); 392 bailout('Returned from a closure');
514 } 393 }
515 if (compiler.backend.isNeededForReflection(info.element)) { 394 if (compiler.backend.isNeededForReflection(info.element)) {
516 bailout('Escape in reflection'); 395 bailout('Escape in reflection');
517 } 396 }
397 if (isParameterOfListAddingMethod(info.element)) {
398 // These elements are being handled in
399 // [visitDynamicCallSiteTypeInformation].
400 return;
401 }
402 addNewEscapeInformation(info);
518 } 403 }
519 } 404 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698