| 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 |