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