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

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

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

Powered by Google App Engine
This is Rietveld 408576698