| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 'dart:collection'; | 5 import 'dart:collection'; |
| 6 | 6 |
| 7 import 'package:js_runtime/shared/embedded_names.dart'; | 7 import 'package:js_runtime/shared/embedded_names.dart'; |
| 8 | 8 |
| 9 import '../closure.dart'; | 9 import '../closure.dart'; |
| 10 import '../common.dart'; | 10 import '../common.dart'; |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 232 this.registry, | 232 this.registry, |
| 233 JavaScriptBackend backend, | 233 JavaScriptBackend backend, |
| 234 this.closedWorld, | 234 this.closedWorld, |
| 235 this.nativeEmitter, | 235 this.nativeEmitter, |
| 236 SourceInformationStrategy sourceInformationFactory) | 236 SourceInformationStrategy sourceInformationFactory) |
| 237 : this.infoReporter = backend.compiler.dumpInfoTask, | 237 : this.infoReporter = backend.compiler.dumpInfoTask, |
| 238 this.backend = backend, | 238 this.backend = backend, |
| 239 this.constantSystem = backend.constantSystem, | 239 this.constantSystem = backend.constantSystem, |
| 240 this.rtiSubstitutions = backend.rtiSubstitutions { | 240 this.rtiSubstitutions = backend.rtiSubstitutions { |
| 241 assert(target.isImplementation); | 241 assert(target.isImplementation); |
| 242 elementInferenceResults = _resultOf(target); | 242 elementInferenceResults = _resultOf(target.declaration); |
| 243 assert(elementInferenceResults != null); | 243 assert(elementInferenceResults != null); |
| 244 graph.element = target; | 244 graph.element = target; |
| 245 sourceElementStack.add(target); | 245 sourceElementStack.add(target.declaration); |
| 246 sourceInformationBuilder = | 246 sourceInformationBuilder = |
| 247 sourceInformationFactory.createBuilderForContext(target); | 247 sourceInformationFactory.createBuilderForContext(target); |
| 248 graph.sourceInformation = | 248 graph.sourceInformation = |
| 249 sourceInformationBuilder.buildVariableDeclaration(); | 249 sourceInformationBuilder.buildVariableDeclaration(); |
| 250 localsHandler = new LocalsHandler( | 250 localsHandler = new LocalsHandler( |
| 251 this, | 251 this, |
| 252 target, | 252 target, |
| 253 target.memberContext, | 253 target.memberContext, |
| 254 target.contextClass, | 254 target.contextClass, |
| 255 null, | 255 null, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 285 @override | 285 @override |
| 286 MemberElement get sourceElement => sourceElementStack.last; | 286 MemberElement get sourceElement => sourceElementStack.last; |
| 287 | 287 |
| 288 /// Helper to retrieve global inference results for [element] with special | 288 /// Helper to retrieve global inference results for [element] with special |
| 289 /// care for `ConstructorBodyElement`s which don't exist at the time the | 289 /// care for `ConstructorBodyElement`s which don't exist at the time the |
| 290 /// global analysis run. | 290 /// global analysis run. |
| 291 /// | 291 /// |
| 292 /// Note: this helper is used selectively. When we know that we are in a | 292 /// Note: this helper is used selectively. When we know that we are in a |
| 293 /// context were we don't expect to see a constructor body element, we | 293 /// context were we don't expect to see a constructor body element, we |
| 294 /// directly fetch the data from the global inference results. | 294 /// directly fetch the data from the global inference results. |
| 295 GlobalTypeInferenceElementResult _resultOf(MemberElement element) => | 295 GlobalTypeInferenceElementResult _resultOf(MemberElement element) { |
| 296 globalInferenceResults.resultOfMember( | 296 assert(element.isDeclaration); |
| 297 element is ConstructorBodyElementX ? element.constructor : element); | 297 return globalInferenceResults.resultOfMember( |
| 298 element is ConstructorBodyElementX ? element.constructor : element); |
| 299 } |
| 298 | 300 |
| 299 /// Build the graph for [target]. | 301 /// Build the graph for [target]. |
| 300 HGraph build() { | 302 HGraph build() { |
| 301 assert(target.isImplementation, failedAt(target)); | 303 assert(target.isImplementation, failedAt(target)); |
| 302 HInstruction.idCounter = 0; | 304 HInstruction.idCounter = 0; |
| 303 // TODO(sigmund): remove `result` and return graph directly, need to ensure | 305 // TODO(sigmund): remove `result` and return graph directly, need to ensure |
| 304 // that it can never be null (see result in buildFactory for instance). | 306 // that it can never be null (see result in buildFactory for instance). |
| 305 var result; | 307 var result; |
| 306 if (target.isGenerativeConstructor) { | 308 if (target.isGenerativeConstructor) { |
| 307 result = buildFactory(resolvedAst); | 309 result = buildFactory(resolvedAst); |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 482 // Generative constructors of native classes should not be called directly | 484 // Generative constructors of native classes should not be called directly |
| 483 // and have an extra argument that causes problems with inlining. | 485 // and have an extra argument that causes problems with inlining. |
| 484 if (function.isGenerativeConstructor && | 486 if (function.isGenerativeConstructor && |
| 485 nativeData.isNativeOrExtendsNative(function.enclosingClass)) { | 487 nativeData.isNativeOrExtendsNative(function.enclosingClass)) { |
| 486 return false; | 488 return false; |
| 487 } | 489 } |
| 488 | 490 |
| 489 // A generative constructor body is not seen by global analysis, | 491 // A generative constructor body is not seen by global analysis, |
| 490 // so we should not query for its type. | 492 // so we should not query for its type. |
| 491 if (!function.isGenerativeConstructorBody) { | 493 if (!function.isGenerativeConstructorBody) { |
| 492 if (globalInferenceResults.resultOfMember(function).throwsAlways) { | 494 if (globalInferenceResults.resultOfMember(declaration).throwsAlways) { |
| 493 isReachable = false; | 495 isReachable = false; |
| 494 return false; | 496 return false; |
| 495 } | 497 } |
| 496 } | 498 } |
| 497 | 499 |
| 498 return true; | 500 return true; |
| 499 } | 501 } |
| 500 | 502 |
| 501 bool doesNotContainCode() { | 503 bool doesNotContainCode() { |
| 502 // A function with size 1 does not contain any code. | 504 // A function with size 1 does not contain any code. |
| 503 return InlineWeeder.canBeInlined(functionResolvedAst, 1, | 505 return InlineWeeder.canBeInlined(functionResolvedAst, 1, |
| 504 enableUserAssertions: options.enableUserAssertions); | 506 enableUserAssertions: options.enableUserAssertions); |
| 505 } | 507 } |
| 506 | 508 |
| 507 bool reductiveHeuristic() { | 509 bool reductiveHeuristic() { |
| 508 // The call is on a path which is executed rarely, so inline only if it | 510 // The call is on a path which is executed rarely, so inline only if it |
| 509 // does not make the program larger. | 511 // does not make the program larger. |
| 510 if (isCalledOnce(function)) { | 512 if (isCalledOnce(declaration)) { |
| 511 return InlineWeeder.canBeInlined(functionResolvedAst, null, | 513 return InlineWeeder.canBeInlined(functionResolvedAst, null, |
| 512 enableUserAssertions: options.enableUserAssertions); | 514 enableUserAssertions: options.enableUserAssertions); |
| 513 } | 515 } |
| 514 // TODO(sra): Measure if inlining would 'reduce' the size. One desirable | 516 // TODO(sra): Measure if inlining would 'reduce' the size. One desirable |
| 515 // case we miss by doing nothing is inlining very simple constructors | 517 // case we miss by doing nothing is inlining very simple constructors |
| 516 // where all fields are initialized with values from the arguments at this | 518 // where all fields are initialized with values from the arguments at this |
| 517 // call site. The code is slightly larger (`new Foo(1)` vs `Foo$(1)`) but | 519 // call site. The code is slightly larger (`new Foo(1)` vs `Foo$(1)`) but |
| 518 // that usually means the factory constructor is left unused and not | 520 // that usually means the factory constructor is left unused and not |
| 519 // emitted. | 521 // emitted. |
| 520 // We at least inline bodies that are empty (and thus have a size of 1). | 522 // We at least inline bodies that are empty (and thus have a size of 1). |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 558 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP + | 560 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP + |
| 559 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; | 561 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; |
| 560 } else { | 562 } else { |
| 561 maxInliningNodes = InlineWeeder.INLINING_NODES_OUTSIDE_LOOP + | 563 maxInliningNodes = InlineWeeder.INLINING_NODES_OUTSIDE_LOOP + |
| 562 InlineWeeder.INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR * numParameters; | 564 InlineWeeder.INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR * numParameters; |
| 563 } | 565 } |
| 564 | 566 |
| 565 // If a method is called only once, and all the methods in the | 567 // If a method is called only once, and all the methods in the |
| 566 // inlining stack are called only once as well, we know we will | 568 // inlining stack are called only once as well, we know we will |
| 567 // save on output size by inlining this method. | 569 // save on output size by inlining this method. |
| 568 if (isCalledOnce(function)) { | 570 if (isCalledOnce(declaration)) { |
| 569 maxInliningNodes = null; | 571 maxInliningNodes = null; |
| 570 } | 572 } |
| 571 bool canInline = InlineWeeder.canBeInlined( | 573 bool canInline = InlineWeeder.canBeInlined( |
| 572 functionResolvedAst, maxInliningNodes, | 574 functionResolvedAst, maxInliningNodes, |
| 573 enableUserAssertions: options.enableUserAssertions); | 575 enableUserAssertions: options.enableUserAssertions); |
| 574 if (canInline) { | 576 if (canInline) { |
| 575 inlineCache.markAsInlinable(declaration, insideLoop: insideLoop); | 577 inlineCache.markAsInlinable(declaration, insideLoop: insideLoop); |
| 576 } else { | 578 } else { |
| 577 inlineCache.markAsNonInlinable(declaration, insideLoop: insideLoop); | 579 inlineCache.markAsNonInlinable(declaration, insideLoop: insideLoop); |
| 578 } | 580 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 621 return inliningStack.isEmpty || inliningStack.last.allFunctionsCalledOnce; | 623 return inliningStack.isEmpty || inliningStack.last.allFunctionsCalledOnce; |
| 622 } | 624 } |
| 623 | 625 |
| 624 bool isFunctionCalledOnce(MethodElement element) { | 626 bool isFunctionCalledOnce(MethodElement element) { |
| 625 // ConstructorBodyElements are not in the type inference graph. | 627 // ConstructorBodyElements are not in the type inference graph. |
| 626 if (element is ConstructorBodyElement) return false; | 628 if (element is ConstructorBodyElement) return false; |
| 627 return globalInferenceResults.resultOfMember(element).isCalledOnce; | 629 return globalInferenceResults.resultOfMember(element).isCalledOnce; |
| 628 } | 630 } |
| 629 | 631 |
| 630 bool isCalledOnce(MethodElement element) { | 632 bool isCalledOnce(MethodElement element) { |
| 633 assert(element.isDeclaration); |
| 631 return allInlinedFunctionsCalledOnce && isFunctionCalledOnce(element); | 634 return allInlinedFunctionsCalledOnce && isFunctionCalledOnce(element); |
| 632 } | 635 } |
| 633 | 636 |
| 634 inlinedFrom(ResolvedAst resolvedAst, f()) { | 637 inlinedFrom(ResolvedAst resolvedAst, f()) { |
| 635 MemberElement element = resolvedAst.element; | 638 MemberElement element = resolvedAst.element; |
| 636 assert(element is FunctionElement || element is VariableElement); | 639 assert(element is FunctionElement || element is VariableElement); |
| 637 return reporter.withCurrentElement(element.implementation, () { | 640 return reporter.withCurrentElement(element.implementation, () { |
| 638 // The [sourceElementStack] contains declaration elements. | 641 // The [sourceElementStack] contains declaration elements. |
| 639 SourceInformationBuilder oldSourceInformationBuilder = | 642 SourceInformationBuilder oldSourceInformationBuilder = |
| 640 sourceInformationBuilder; | 643 sourceInformationBuilder; |
| 641 sourceInformationBuilder = sourceInformationBuilder.forContext(element); | 644 sourceInformationBuilder = sourceInformationBuilder.forContext(element); |
| 642 sourceElementStack.add(element.declaration); | 645 sourceElementStack.add(element); |
| 643 var result = f(); | 646 var result = f(); |
| 644 sourceInformationBuilder = oldSourceInformationBuilder; | 647 sourceInformationBuilder = oldSourceInformationBuilder; |
| 645 sourceElementStack.removeLast(); | 648 sourceElementStack.removeLast(); |
| 646 return result; | 649 return result; |
| 647 }); | 650 }); |
| 648 } | 651 } |
| 649 | 652 |
| 650 /** | 653 /** |
| 651 * Return null so it is simple to remove the optional parameters completely | 654 * Return null so it is simple to remove the optional parameters completely |
| 652 * from interop methods to match JavaScript semantics for omitted arguments. | 655 * from interop methods to match JavaScript semantics for omitted arguments. |
| (...skipping 3023 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3676 void visitTopLevelFieldInvoke(ast.Send node, FieldElement field, | 3679 void visitTopLevelFieldInvoke(ast.Send node, FieldElement field, |
| 3677 ast.NodeList arguments, CallStructure callStructure, _) { | 3680 ast.NodeList arguments, CallStructure callStructure, _) { |
| 3678 generateStaticFieldGet(node, field); | 3681 generateStaticFieldGet(node, field); |
| 3679 generateCallInvoke(node, pop(), | 3682 generateCallInvoke(node, pop(), |
| 3680 sourceInformationBuilder.buildCall(node, node.argumentsNode)); | 3683 sourceInformationBuilder.buildCall(node, node.argumentsNode)); |
| 3681 } | 3684 } |
| 3682 | 3685 |
| 3683 @override | 3686 @override |
| 3684 void visitTopLevelFunctionInvoke(ast.Send node, MethodElement function, | 3687 void visitTopLevelFunctionInvoke(ast.Send node, MethodElement function, |
| 3685 ast.NodeList arguments, CallStructure callStructure, _) { | 3688 ast.NodeList arguments, CallStructure callStructure, _) { |
| 3686 if (backend.isForeign(closedWorld.commonElements, function)) { | 3689 if (closedWorld.commonElements.isForeign(function)) { |
| 3687 handleForeignSend(node, function); | 3690 handleForeignSend(node, function); |
| 3688 } else { | 3691 } else { |
| 3689 generateStaticFunctionInvoke(node, function, callStructure); | 3692 generateStaticFunctionInvoke(node, function, callStructure); |
| 3690 } | 3693 } |
| 3691 } | 3694 } |
| 3692 | 3695 |
| 3693 @override | 3696 @override |
| 3694 void visitTopLevelFunctionIncompatibleInvoke( | 3697 void visitTopLevelFunctionIncompatibleInvoke( |
| 3695 ast.Send node, | 3698 ast.Send node, |
| 3696 MethodElement function, | 3699 MethodElement function, |
| (...skipping 2774 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6471 ResolvedAst functionResolvedAst, List<HInstruction> compiledArguments, | 6474 ResolvedAst functionResolvedAst, List<HInstruction> compiledArguments, |
| 6472 {ResolutionInterfaceType instanceType}) { | 6475 {ResolutionInterfaceType instanceType}) { |
| 6473 AstInliningState state = new AstInliningState( | 6476 AstInliningState state = new AstInliningState( |
| 6474 function, | 6477 function, |
| 6475 returnLocal, | 6478 returnLocal, |
| 6476 returnType, | 6479 returnType, |
| 6477 resolvedAst, | 6480 resolvedAst, |
| 6478 stack, | 6481 stack, |
| 6479 localsHandler, | 6482 localsHandler, |
| 6480 inTryStatement, | 6483 inTryStatement, |
| 6481 isCalledOnce(function), | 6484 isCalledOnce(functionResolvedAst.element), |
| 6482 elementInferenceResults); | 6485 elementInferenceResults); |
| 6483 resolvedAst = functionResolvedAst; | 6486 resolvedAst = functionResolvedAst; |
| 6484 elementInferenceResults = _resultOf(function); | 6487 elementInferenceResults = _resultOf(functionResolvedAst.element); |
| 6485 inliningStack.add(state); | 6488 inliningStack.add(state); |
| 6486 | 6489 |
| 6487 // Setting up the state of the (AST) builder is performed even when the | 6490 // Setting up the state of the (AST) builder is performed even when the |
| 6488 // inlined function is in IR, because the irInliner uses the [returnElement] | 6491 // inlined function is in IR, because the irInliner uses the [returnElement] |
| 6489 // of the AST builder. | 6492 // of the AST builder. |
| 6490 setupStateForInlining(function, compiledArguments, | 6493 setupStateForInlining(function, compiledArguments, |
| 6491 instanceType: instanceType); | 6494 instanceType: instanceType); |
| 6492 } | 6495 } |
| 6493 | 6496 |
| 6494 void leaveInlinedMethod() { | 6497 void leaveInlinedMethod() { |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6844 this.oldReturnLocal, | 6847 this.oldReturnLocal, |
| 6845 this.oldReturnType, | 6848 this.oldReturnType, |
| 6846 this.oldResolvedAst, | 6849 this.oldResolvedAst, |
| 6847 this.oldStack, | 6850 this.oldStack, |
| 6848 this.oldLocalsHandler, | 6851 this.oldLocalsHandler, |
| 6849 this.inTryStatement, | 6852 this.inTryStatement, |
| 6850 this.allFunctionsCalledOnce, | 6853 this.allFunctionsCalledOnce, |
| 6851 this.oldElementInferenceResults) | 6854 this.oldElementInferenceResults) |
| 6852 : super(function); | 6855 : super(function); |
| 6853 } | 6856 } |
| OLD | NEW |