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

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
« 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 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 254
272 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) { 255 void visitClosureCallSiteTypeInformation(
273 bailout('Passed to a closure'); 256 ClosureCallSiteTypeInformation info) {}
274 }
275 257
276 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { 258 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
277 Element called = info.calledElement; 259 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) { 260 if (inferrer.types.getInferredTypeOf(called) == currentUser) {
282 addNewEscapeInformation(info); 261 addNewEscapeInformation(info);
283 } 262 }
284 } 263 }
285 264
286 void analyzeStoredIntoContainer(ListTypeInformation container) { 265 void analyzeStoredIntoContainer(ListTypeInformation container) {
287 inferrer.analyzeContainer(container); 266 inferrer.analyzeContainer(container);
288 if (container.bailedOut) { 267 if (container.bailedOut) {
289 bailout('Stored in a container that bailed out'); 268 bailout('Stored in a container that bailed out');
290 } else { 269 } else {
291 container.flowsInto.forEach((flow) { 270 container.flowsInto.forEach((flow) {
292 flow.users.forEach((user) { 271 flow.users.forEach((user) {
293 if (user is !DynamicCallSiteTypeInformation) return; 272 if (user is !DynamicCallSiteTypeInformation) return;
294 if (user.receiver != flow) return; 273 if (user.receiver != flow) return;
295 if (returnsElementTypeSet.contains(user.selector)) { 274 if (returnsElementTypeSet.contains(user.selector)) {
296 addNewEscapeInformation(user); 275 addNewEscapeInformation(user);
297 } else if (!doesNotEscapeElementSet.contains(user.selector.name)) { 276 } else if (!doesNotEscapeElementSet.contains(user.selector.name)) {
298 bailout('Escape from a container'); 277 bailout('Escape from a container');
299 } 278 }
300 }); 279 });
301 }); 280 });
302 } 281 }
303 } 282 }
304 283
305 bool isAddedToContainer(DynamicCallSiteTypeInformation info) { 284 bool isAddedToContainer(DynamicCallSiteTypeInformation info) {
285 if (info.arguments == null) return false;
306 var receiverType = info.receiver.type; 286 var receiverType = info.receiver.type;
307 if (!receiverType.isContainer) return false; 287 if (!receiverType.isContainer) return false;
308 String selectorName = info.selector.name; 288 String selectorName = info.selector.name;
309 List<TypeInformation> arguments = info.arguments.positional; 289 List<TypeInformation> arguments = info.arguments.positional;
310 return (selectorName == '[]=' && currentUser == arguments[1]) 290 return (selectorName == '[]=' && currentUser == arguments[1])
311 || (selectorName == 'insert' && currentUser == arguments[0]) 291 || (selectorName == 'insert' && currentUser == arguments[0])
312 || (selectorName == 'add' && currentUser == arguments[0]); 292 || (selectorName == 'add' && currentUser == arguments[0]);
313 } 293 }
314 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 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
315 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) { 378 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
379 super.visitDynamicCallSiteTypeInformation(info);
316 Selector selector = info.selector; 380 Selector selector = info.selector;
317 String selectorName = selector.name; 381 String selectorName = selector.name;
318 if (currentUser == info.receiver) { 382 if (currentUser == info.receiver) {
319 if (!okSelectorsSet.contains(selectorName)) { 383 if (!okSelectorsSet.contains(selectorName)) {
320 if (selector.isCall()) { 384 if (selector.isCall()) {
321 int positionalLength = info.arguments.positional.length; 385 int positionalLength = info.arguments.positional.length;
322 if (selectorName == 'add') { 386 if (selectorName == 'add') {
323 if (positionalLength == 1) { 387 if (positionalLength == 1) {
324 assignments.add(info.arguments.positional[0]); 388 assignments.add(info.arguments.positional[0]);
325 } 389 }
(...skipping 16 matching lines...) Expand all
342 callsGrowableMethod = true; 406 callsGrowableMethod = true;
343 } 407 }
344 if (selectorName == 'length' && selector.isSetter()) { 408 if (selectorName == 'length' && selector.isSetter()) {
345 callsGrowableMethod = true; 409 callsGrowableMethod = true;
346 assignments.add(inferrer.types.nullType); 410 assignments.add(inferrer.types.nullType);
347 } 411 }
348 } else if (selector.isCall() 412 } else if (selector.isCall()
349 && !info.targets.every((element) => element.isFunction())) { 413 && !info.targets.every((element) => element.isFunction())) {
350 bailout('Passed to a closure'); 414 bailout('Passed to a closure');
351 return; 415 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);
370 } 416 }
371 } 417 }
372 418
373 bool isClosure(Element element) { 419 bool isClosure(Element element) {
374 if (!element.isFunction()) return false; 420 if (!element.isFunction()) return false;
375 Element outermost = element.getOutermostEnclosingMemberOrTopLevel(); 421 Element outermost = element.getOutermostEnclosingMemberOrTopLevel();
376 return outermost.declaration != element.declaration; 422 return outermost.declaration != element.declaration;
377 } 423 }
378 424
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
390 visitElementTypeInformation(ElementTypeInformation info) { 425 visitElementTypeInformation(ElementTypeInformation info) {
426 super.visitElementTypeInformation(info);
391 if (isClosure(info.element)) { 427 if (isClosure(info.element)) {
392 bailout('Returned from a closure'); 428 bailout('Returned from a closure');
393 } 429 }
394 if (compiler.backend.isNeededForReflection(info.element)) { 430 if (compiler.backend.isNeededForReflection(info.element)) {
395 bailout('Escape in reflection'); 431 bailout('Escape in reflection');
396 } 432 }
397 if (isParameterOfListAddingMethod(info.element)) {
398 // These elements are being handled in
399 // [visitDynamicCallSiteTypeInformation].
400 return;
401 }
402 addNewEscapeInformation(info);
403 } 433 }
404 } 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) {
505 if (!element.isFunction()) return false;
506 Element outermost = element.getOutermostEnclosingMemberOrTopLevel();
507 return outermost.declaration != element.declaration;
508 }
509
510 visitElementTypeInformation(ElementTypeInformation info) {
511 super.visitElementTypeInformation(info);
512 if (isClosure(info.element)) {
513 bailout('Returned from a closure');
514 }
515 if (compiler.backend.isNeededForReflection(info.element)) {
516 bailout('Escape in reflection');
517 }
518 }
519 }
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