OLD | NEW |
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 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
6 | 6 |
7 import '../common.dart'; | 7 import '../common.dart'; |
8 import '../common/names.dart'; | 8 import '../common/names.dart'; |
9 import '../compiler.dart'; | 9 import '../compiler.dart'; |
10 import '../constants/expressions.dart'; | 10 import '../constants/expressions.dart'; |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 if (compiler.options.verbose) { | 305 if (compiler.options.verbose) { |
306 compiler.progress.reset(); | 306 compiler.progress.reset(); |
307 } | 307 } |
308 sortResolvedAsts().forEach((ResolvedAst resolvedAst) { | 308 sortResolvedAsts().forEach((ResolvedAst resolvedAst) { |
309 if (compiler.shouldPrintProgress) { | 309 if (compiler.shouldPrintProgress) { |
310 reporter.log('Added $addedInGraph elements in inferencing graph.'); | 310 reporter.log('Added $addedInGraph elements in inferencing graph.'); |
311 compiler.progress.reset(); | 311 compiler.progress.reset(); |
312 } | 312 } |
313 // This also forces the creation of the [ElementTypeInformation] to ensure | 313 // This also forces the creation of the [ElementTypeInformation] to ensure |
314 // it is in the graph. | 314 // it is in the graph. |
315 types.withMember( | 315 types.withMember(resolvedAst.element, () => analyze(resolvedAst, null)); |
316 resolvedAst.element.implementation, () => analyze(resolvedAst, null)); | |
317 }); | 316 }); |
318 reporter.log('Added $addedInGraph elements in inferencing graph.'); | 317 reporter.log('Added $addedInGraph elements in inferencing graph.'); |
319 | 318 |
320 TypeGraphDump dump = debug.PRINT_GRAPH ? new TypeGraphDump(this) : null; | 319 TypeGraphDump dump = debug.PRINT_GRAPH ? new TypeGraphDump(this) : null; |
321 | 320 |
322 dump?.beforeAnalysis(); | 321 dump?.beforeAnalysis(); |
323 buildWorkQueue(); | 322 buildWorkQueue(); |
324 refine(); | 323 refine(); |
325 | 324 |
326 // Try to infer element types of lists and compute their escape information. | 325 // Try to infer element types of lists and compute their escape information. |
327 types.allocatedLists.values.forEach((TypeInformation info) { | 326 types.allocatedLists.values.forEach((TypeInformation info) { |
328 analyzeListAndEnqueue(info); | 327 analyzeListAndEnqueue(info); |
329 }); | 328 }); |
330 | 329 |
331 // Try to infer the key and value types for maps and compute the values' | 330 // Try to infer the key and value types for maps and compute the values' |
332 // escape information. | 331 // escape information. |
333 types.allocatedMaps.values.forEach((TypeInformation info) { | 332 types.allocatedMaps.values.forEach((TypeInformation info) { |
334 analyzeMapAndEnqueue(info); | 333 analyzeMapAndEnqueue(info); |
335 }); | 334 }); |
336 | 335 |
337 Set<MethodElement> bailedOutOn = new Set<MethodElement>(); | 336 Set<FunctionEntity> bailedOutOn = new Set<FunctionEntity>(); |
338 | 337 |
339 // Trace closures to potentially infer argument types. | 338 // Trace closures to potentially infer argument types. |
340 types.allocatedClosures.forEach((dynamic info) { | 339 types.allocatedClosures.forEach((dynamic info) { |
341 void trace( | 340 void trace( |
342 Iterable<MethodElement> elements, ClosureTracerVisitor tracer) { | 341 Iterable<FunctionEntity> elements, ClosureTracerVisitor tracer) { |
343 tracer.run(); | 342 tracer.run(); |
344 if (!tracer.continueAnalyzing) { | 343 if (!tracer.continueAnalyzing) { |
345 elements.forEach((MethodElement e) { | 344 elements.forEach((FunctionEntity _element) { |
346 closedWorldRefiner.registerMightBePassedToApply(e); | 345 MethodElement element = _element; |
347 if (debug.VERBOSE) print("traced closure $e as ${true} (bail)"); | 346 MethodElement implementation = element.implementation; |
348 e.functionSignature.forEachParameter((parameter) { | 347 closedWorldRefiner.registerMightBePassedToApply(element); |
| 348 if (debug.VERBOSE) { |
| 349 print("traced closure $element as ${true} (bail)"); |
| 350 } |
| 351 implementation.functionSignature.forEachParameter((parameter) { |
349 types | 352 types |
350 .getInferredTypeOfParameter(parameter) | 353 .getInferredTypeOfParameter(parameter) |
351 .giveUp(this, clearAssignments: false); | 354 .giveUp(this, clearAssignments: false); |
352 }); | 355 }); |
353 }); | 356 }); |
354 bailedOutOn.addAll(elements); | 357 bailedOutOn.addAll(elements); |
355 return; | 358 return; |
356 } | 359 } |
357 elements | 360 elements |
358 .where((e) => !bailedOutOn.contains(e)) | 361 .where((e) => !bailedOutOn.contains(e)) |
359 .forEach((MethodElement e) { | 362 .forEach((FunctionEntity _element) { |
360 e.functionSignature.forEachParameter((parameter) { | 363 MethodElement element = _element; |
| 364 MethodElement implementation = element.implementation; |
| 365 implementation.functionSignature.forEachParameter((parameter) { |
361 var info = types.getInferredTypeOfParameter(parameter); | 366 var info = types.getInferredTypeOfParameter(parameter); |
362 info.maybeResume(); | 367 info.maybeResume(); |
363 workQueue.add(info); | 368 workQueue.add(info); |
364 }); | 369 }); |
365 if (tracer.tracedType.mightBePassedToFunctionApply) { | 370 if (tracer.tracedType.mightBePassedToFunctionApply) { |
366 closedWorldRefiner.registerMightBePassedToApply(e); | 371 closedWorldRefiner.registerMightBePassedToApply(element); |
367 } | 372 } |
368 if (debug.VERBOSE) { | 373 if (debug.VERBOSE) { |
369 print("traced closure $e as " | 374 print("traced closure $element as " |
370 "${closedWorldRefiner | 375 "${closedWorldRefiner |
371 .getCurrentlyKnownMightBePassedToApply(e)}"); | 376 .getCurrentlyKnownMightBePassedToApply(element)}"); |
372 } | 377 } |
373 }); | 378 }); |
374 } | 379 } |
375 | 380 |
376 if (info is ClosureTypeInformation) { | 381 if (info is ClosureTypeInformation) { |
377 Iterable<MethodElement> elements = [info.closure]; | 382 Iterable<MethodElement> elements = [info.closure]; |
378 trace(elements, new ClosureTracerVisitor(elements, info, this)); | 383 trace(elements, new ClosureTracerVisitor(elements, info, this)); |
379 } else if (info is CallSiteTypeInformation) { | 384 } else if (info is CallSiteTypeInformation) { |
380 if (info is StaticCallSiteTypeInformation && | 385 if (info is StaticCallSiteTypeInformation && |
381 info.selector != null && | 386 info.selector != null && |
382 info.selector.isCall) { | 387 info.selector.isCall) { |
383 // This is a constructor call to a class with a call method. So we | 388 // This is a constructor call to a class with a call method. So we |
384 // need to trace the call method here. | 389 // need to trace the call method here. |
385 assert(info.calledElement.isGenerativeConstructor); | 390 MethodElement calledElement = info.calledElement; |
386 ClassElement cls = info.calledElement.enclosingClass; | 391 assert(calledElement.isGenerativeConstructor); |
| 392 ClassElement cls = calledElement.enclosingClass; |
387 MethodElement callMethod = cls.lookupMember(Identifiers.call); | 393 MethodElement callMethod = cls.lookupMember(Identifiers.call); |
388 assert(callMethod != null, failedAt(cls)); | 394 assert(callMethod != null, failedAt(cls)); |
389 Iterable<MethodElement> elements = [callMethod]; | 395 Iterable<FunctionEntity> elements = [callMethod]; |
390 trace(elements, new ClosureTracerVisitor(elements, info, this)); | 396 trace(elements, new ClosureTracerVisitor(elements, info, this)); |
391 } else { | 397 } else { |
392 // We only are interested in functions here, as other targets | 398 // We only are interested in functions here, as other targets |
393 // of this closure call are not a root to trace but an intermediate | 399 // of this closure call are not a root to trace but an intermediate |
394 // for some other function. | 400 // for some other function. |
395 Iterable<MethodElement> elements = new List<MethodElement>.from( | 401 Iterable<FunctionEntity> elements = new List<FunctionEntity>.from( |
396 info.callees.where((e) => e.isFunction)); | 402 info.callees.where((e) => e.isFunction)); |
397 trace(elements, new ClosureTracerVisitor(elements, info, this)); | 403 trace(elements, new ClosureTracerVisitor(elements, info, this)); |
398 } | 404 } |
399 } else if (info is MemberTypeInformation) { | 405 } else if (info is MemberTypeInformation) { |
400 trace([info.member], | 406 trace(<FunctionEntity>[info.member], |
401 new StaticTearOffClosureTracerVisitor(info.member, info, this)); | 407 new StaticTearOffClosureTracerVisitor(info.member, info, this)); |
402 } else if (info is ParameterTypeInformation) { | 408 } else if (info is ParameterTypeInformation) { |
403 throw new SpannableAssertionFailure( | 409 throw new SpannableAssertionFailure( |
404 NO_LOCATION_SPANNABLE, 'Unexpected closure allocation info $info'); | 410 NO_LOCATION_SPANNABLE, 'Unexpected closure allocation info $info'); |
405 } | 411 } |
406 }); | 412 }); |
407 | 413 |
408 dump?.beforeTracing(); | 414 dump?.beforeTracing(); |
409 | 415 |
410 // Reset all nodes that use lists/maps that have been inferred, as well | 416 // Reset all nodes that use lists/maps that have been inferred, as well |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 }); | 475 }); |
470 } | 476 } |
471 dump?.afterAnalysis(); | 477 dump?.afterAnalysis(); |
472 | 478 |
473 reporter.log('Inferred $overallRefineCount types.'); | 479 reporter.log('Inferred $overallRefineCount types.'); |
474 | 480 |
475 processLoopInformation(); | 481 processLoopInformation(); |
476 } | 482 } |
477 | 483 |
478 void analyze(ResolvedAst resolvedAst, ArgumentsTypes arguments) { | 484 void analyze(ResolvedAst resolvedAst, ArgumentsTypes arguments) { |
479 MemberElement element = resolvedAst.element.implementation; | 485 MemberElement element = resolvedAst.element; |
480 if (analyzedElements.contains(element)) return; | 486 if (analyzedElements.contains(element)) return; |
481 analyzedElements.add(element); | 487 analyzedElements.add(element); |
482 | 488 |
483 dynamic visitor = compiler.options.kernelGlobalInference | 489 dynamic visitor = compiler.options.kernelGlobalInference |
484 ? new KernelTypeGraphBuilder(element, resolvedAst, compiler, this) | 490 ? new KernelTypeGraphBuilder(element, resolvedAst, compiler, this) |
485 : new ElementGraphBuilder(element, resolvedAst, compiler, this); | 491 : new ElementGraphBuilder(element, resolvedAst, compiler, this); |
486 TypeInformation type; | 492 TypeInformation type; |
487 reporter.withCurrentElement(element, () { | 493 reporter.withCurrentElement(element, () { |
488 // ignore: UNDEFINED_METHOD | 494 // ignore: UNDEFINED_METHOD |
489 type = visitor.run(); | 495 type = visitor.run(); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
557 } | 563 } |
558 } else { | 564 } else { |
559 recordReturnType(element, type); | 565 recordReturnType(element, type); |
560 } | 566 } |
561 } | 567 } |
562 | 568 |
563 void processLoopInformation() { | 569 void processLoopInformation() { |
564 types.allocatedCalls.forEach((dynamic info) { | 570 types.allocatedCalls.forEach((dynamic info) { |
565 if (!info.inLoop) return; | 571 if (!info.inLoop) return; |
566 if (info is StaticCallSiteTypeInformation) { | 572 if (info is StaticCallSiteTypeInformation) { |
567 MemberElement member = info.calledElement.declaration; | 573 MemberEntity member = info.calledElement; |
568 closedWorldRefiner.addFunctionCalledInLoop(member); | 574 closedWorldRefiner.addFunctionCalledInLoop(member); |
569 } else if (info.mask != null && !info.mask.containsAll(closedWorld)) { | 575 } else if (info.mask != null && !info.mask.containsAll(closedWorld)) { |
570 // For instance methods, we only register a selector called in a | 576 // For instance methods, we only register a selector called in a |
571 // loop if it is a typed selector, to avoid marking too many | 577 // loop if it is a typed selector, to avoid marking too many |
572 // methods as being called from within a loop. This cuts down | 578 // methods as being called from within a loop. This cuts down |
573 // on the code bloat. | 579 // on the code bloat. |
574 info.targets.forEach((MemberElement element) { | 580 info.targets.forEach((MemberElement element) { |
575 closedWorldRefiner.addFunctionCalledInLoop(element); | 581 closedWorldRefiner.addFunctionCalledInLoop(element); |
576 }); | 582 }); |
577 } | 583 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
614 workQueue.addAll(types.allocatedTypes); | 620 workQueue.addAll(types.allocatedTypes); |
615 workQueue.addAll(types.allocatedClosures); | 621 workQueue.addAll(types.allocatedClosures); |
616 workQueue.addAll(types.allocatedCalls); | 622 workQueue.addAll(types.allocatedCalls); |
617 } | 623 } |
618 | 624 |
619 /** | 625 /** |
620 * Update the assignments to parameters in the graph. [remove] tells | 626 * Update the assignments to parameters in the graph. [remove] tells |
621 * wheter assignments must be added or removed. If [init] is false, | 627 * wheter assignments must be added or removed. If [init] is false, |
622 * parameters are added to the work queue. | 628 * parameters are added to the work queue. |
623 */ | 629 */ |
624 void updateParameterAssignments(TypeInformation caller, Element callee, | 630 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, |
625 ArgumentsTypes arguments, Selector selector, TypeMask mask, | 631 ArgumentsTypes arguments, Selector selector, TypeMask mask, |
626 {bool remove, bool addToQueue: true}) { | 632 {bool remove, bool addToQueue: true}) { |
627 if (callee.name == Identifiers.noSuchMethod_) return; | 633 if (callee.name == Identifiers.noSuchMethod_) return; |
628 if (callee.isField) { | 634 if (callee.isField) { |
629 if (selector.isSetter) { | 635 if (selector.isSetter) { |
630 ElementTypeInformation info = types.getInferredTypeOfMember(callee); | 636 ElementTypeInformation info = types.getInferredTypeOfMember(callee); |
631 if (remove) { | 637 if (remove) { |
632 info.removeAssignment(arguments.positional[0]); | 638 info.removeAssignment(arguments.positional[0]); |
633 } else { | 639 } else { |
634 info.addAssignment(arguments.positional[0]); | 640 info.addAssignment(arguments.positional[0]); |
635 } | 641 } |
636 if (addToQueue) workQueue.add(info); | 642 if (addToQueue) workQueue.add(info); |
637 } | 643 } |
638 } else if (callee.isGetter) { | 644 } else if (callee.isGetter) { |
639 return; | 645 return; |
640 } else if (selector != null && selector.isGetter) { | 646 } else if (selector != null && selector.isGetter) { |
641 // We are tearing a function off and thus create a closure. | 647 // We are tearing a function off and thus create a closure. |
642 assert(callee.isFunction); | 648 assert(callee.isFunction); |
643 MemberTypeInformation info = types.getInferredTypeOfMember(callee); | 649 MethodElement method = callee; |
| 650 MemberTypeInformation info = types.getInferredTypeOfMember(method); |
644 if (remove) { | 651 if (remove) { |
645 info.closurizedCount--; | 652 info.closurizedCount--; |
646 } else { | 653 } else { |
647 info.closurizedCount++; | 654 info.closurizedCount++; |
648 if (Elements.isStaticOrTopLevel(callee)) { | 655 if (Elements.isStaticOrTopLevel(method)) { |
649 types.allocatedClosures.add(info); | 656 types.allocatedClosures.add(info); |
650 } else { | 657 } else { |
651 // We add the call-site type information here so that we | 658 // We add the call-site type information here so that we |
652 // can benefit from further refinement of the selector. | 659 // can benefit from further refinement of the selector. |
653 types.allocatedClosures.add(caller); | 660 types.allocatedClosures.add(caller); |
654 } | 661 } |
655 FunctionElement function = callee.implementation; | 662 FunctionElement function = method.implementation; |
656 FunctionSignature signature = function.functionSignature; | 663 FunctionSignature signature = function.functionSignature; |
657 signature.forEachParameter((Element parameter) { | 664 signature.forEachParameter((Element parameter) { |
658 ParameterTypeInformation info = | 665 ParameterTypeInformation info = |
659 types.getInferredTypeOfParameter(parameter); | 666 types.getInferredTypeOfParameter(parameter); |
660 info.tagAsTearOffClosureParameter(this); | 667 info.tagAsTearOffClosureParameter(this); |
661 if (addToQueue) workQueue.add(info); | 668 if (addToQueue) workQueue.add(info); |
662 }); | 669 }); |
663 } | 670 } |
664 } else { | 671 } else { |
665 FunctionElement function = callee.implementation; | 672 MethodElement method = callee; |
| 673 FunctionElement function = method.implementation; |
666 FunctionSignature signature = function.functionSignature; | 674 FunctionSignature signature = function.functionSignature; |
667 int parameterIndex = 0; | 675 int parameterIndex = 0; |
668 bool visitingRequiredParameter = true; | 676 bool visitingRequiredParameter = true; |
669 signature.forEachParameter((Element parameter) { | 677 signature.forEachParameter((Element parameter) { |
670 if (signature.hasOptionalParameters && | 678 if (signature.hasOptionalParameters && |
671 parameter == signature.optionalParameters.first) { | 679 parameter == signature.optionalParameters.first) { |
672 visitingRequiredParameter = false; | 680 visitingRequiredParameter = false; |
673 } | 681 } |
674 TypeInformation type = visitingRequiredParameter | 682 TypeInformation type = visitingRequiredParameter |
675 ? arguments.positional[parameterIndex] | 683 ? arguments.positional[parameterIndex] |
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1096 /** | 1104 /** |
1097 * Records that the captured variable [local] is read. | 1105 * Records that the captured variable [local] is read. |
1098 */ | 1106 */ |
1099 void recordCapturedLocalRead(Local local) {} | 1107 void recordCapturedLocalRead(Local local) {} |
1100 | 1108 |
1101 /** | 1109 /** |
1102 * Records that the variable [local] is being updated. | 1110 * Records that the variable [local] is being updated. |
1103 */ | 1111 */ |
1104 void recordLocalUpdate(Local local, TypeInformation type) {} | 1112 void recordLocalUpdate(Local local, TypeInformation type) {} |
1105 } | 1113 } |
OLD | NEW |