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 |