| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library cps_ir.optimization.inline; | 5 library cps_ir.optimization.inline; |
| 6 | 6 |
| 7 import 'cps_fragment.dart'; | 7 import 'cps_fragment.dart'; |
| 8 import 'cps_ir_builder.dart' show ThisParameterLocal; | 8 import 'cps_ir_builder.dart' show ThisParameterLocal; |
| 9 import 'cps_ir_nodes.dart'; | 9 import 'cps_ir_nodes.dart'; |
| 10 import 'optimizers.dart'; | 10 import 'optimizers.dart'; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 /// During inlining a cache is used to remember inlining decisions for shared | 79 /// During inlining a cache is used to remember inlining decisions for shared |
| 80 /// parts of the call graph, to avoid exploring them more than once. | 80 /// parts of the call graph, to avoid exploring them more than once. |
| 81 /// | 81 /// |
| 82 /// The cache maps a tuple of (function element, call structure, | 82 /// The cache maps a tuple of (function element, call structure, |
| 83 /// abstract receiver, abstract arguments) to a boolean inlining decision and | 83 /// abstract receiver, abstract arguments) to a boolean inlining decision and |
| 84 /// an IR function definition if the decision is positive. | 84 /// an IR function definition if the decision is positive. |
| 85 class InliningCache { | 85 class InliningCache { |
| 86 static const int ABSENT = -1; | 86 static const int ABSENT = -1; |
| 87 static const int NO_INLINE = 0; | 87 static const int NO_INLINE = 0; |
| 88 | 88 |
| 89 final Map<ExecutableElement, FunctionDefinition> unoptimized = |
| 90 <ExecutableElement, FunctionDefinition>{}; |
| 91 |
| 89 final Map<ExecutableElement, List<CacheEntry>> map = | 92 final Map<ExecutableElement, List<CacheEntry>> map = |
| 90 <ExecutableElement, List<CacheEntry>>{}; | 93 <ExecutableElement, List<CacheEntry>>{}; |
| 91 | 94 |
| 92 // When function definitions are put into or removed from the cache, they are | 95 // When function definitions are put into or removed from the cache, they are |
| 93 // copied because the compiler passes will mutate them. | 96 // copied because the compiler passes will mutate them. |
| 94 final CopyingVisitor copier = new CopyingVisitor(); | 97 final CopyingVisitor copier = new CopyingVisitor(); |
| 95 | 98 |
| 96 void _putInternal(ExecutableElement element, CallStructure callStructure, | 99 void _putInternal(ExecutableElement element, CallStructure callStructure, |
| 97 TypeMask receiver, | 100 TypeMask receiver, |
| 98 List<TypeMask> arguments, | 101 List<TypeMask> arguments, |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 FunctionDefinition function = copier.copy(entry.function); | 140 FunctionDefinition function = copier.copy(entry.function); |
| 138 ParentVisitor.setParents(function); | 141 ParentVisitor.setParents(function); |
| 139 return function; | 142 return function; |
| 140 } | 143 } |
| 141 return NO_INLINE; | 144 return NO_INLINE; |
| 142 } | 145 } |
| 143 } | 146 } |
| 144 } | 147 } |
| 145 return ABSENT; | 148 return ABSENT; |
| 146 } | 149 } |
| 150 |
| 151 /// Cache the unoptimized CPS term for a function. |
| 152 /// |
| 153 /// The unoptimized term should not have any inlining-context-specific |
| 154 /// optimizations applied to it. It will be used to compile the |
| 155 /// non-specialized version of the function. |
| 156 void putUnoptimized(ExecutableElement element, FunctionDefinition function) { |
| 157 unoptimized.putIfAbsent(element, () => copier.copy(function)); |
| 158 } |
| 159 |
| 160 /// Look up the unoptimized CPS term for a function. |
| 161 /// |
| 162 /// The unoptimized term will not have any inlining-context-specific |
| 163 /// optimizations applied to it. It can be used to compile the |
| 164 /// non-specialized version of the function. |
| 165 FunctionDefinition getUnoptimized(ExecutableElement element) { |
| 166 FunctionDefinition function = unoptimized[element]; |
| 167 if (function != null) { |
| 168 function = copier.copy(function); |
| 169 ParentVisitor.setParents(function); |
| 170 } |
| 171 return function; |
| 172 } |
| 147 } | 173 } |
| 148 | 174 |
| 149 class Inliner implements Pass { | 175 class Inliner implements Pass { |
| 150 get passName => 'Inline calls'; | 176 get passName => 'Inline calls'; |
| 151 | 177 |
| 152 final CpsFunctionCompiler functionCompiler; | 178 final CpsFunctionCompiler functionCompiler; |
| 153 | 179 |
| 154 final InliningCache cache = new InliningCache(); | 180 final InliningCache cache = new InliningCache(); |
| 155 | 181 |
| 156 final List<StackEntry> stack = <StackEntry>[]; | 182 final List<StackEntry> stack = <StackEntry>[]; |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 436 | 462 |
| 437 FunctionDefinition function; | 463 FunctionDefinition function; |
| 438 if (callStructure != null && | 464 if (callStructure != null && |
| 439 target.functionSignature.parameterCount != | 465 target.functionSignature.parameterCount != |
| 440 callStructure.argumentCount) { | 466 callStructure.argumentCount) { |
| 441 // The argument count at the call site does not match the target's | 467 // The argument count at the call site does not match the target's |
| 442 // formal parameter count. Build the IR term for an adapter function | 468 // formal parameter count. Build the IR term for an adapter function |
| 443 // body. | 469 // body. |
| 444 function = buildAdapter(invoke, target); | 470 function = buildAdapter(invoke, target); |
| 445 } else { | 471 } else { |
| 446 function = _inliner.functionCompiler.compileToCpsIr(target); | 472 function = compileToCpsIr(target); |
| 447 void setValue(Variable variable, Reference<Primitive> value) { | 473 void setValue(Variable variable, Reference<Primitive> value) { |
| 448 variable.type = value.definition.type; | 474 variable.type = value.definition.type; |
| 449 } | 475 } |
| 450 if (invoke.callingConvention == CallingConvention.Intercepted) { | 476 if (invoke.callingConvention == CallingConvention.Intercepted) { |
| 451 setValue(function.thisParameter, invoke.receiver); | 477 setValue(function.thisParameter, invoke.receiver); |
| 452 function.parameters[0].type = abstractReceiverInMethod; | 478 function.parameters[0].type = abstractReceiverInMethod; |
| 453 for (int i = 1; i < invoke.arguments.length; ++i) { | 479 for (int i = 1; i < invoke.arguments.length; ++i) { |
| 454 setValue(function.parameters[i], invoke.arguments[i]); | 480 setValue(function.parameters[i], invoke.arguments[i]); |
| 455 } | 481 } |
| 456 } else { | 482 } else { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 534 // We cannot inline a constructor invocation containing type arguments | 560 // We cannot inline a constructor invocation containing type arguments |
| 535 // because CreateInstance in the body does not know the type arguments. | 561 // because CreateInstance in the body does not know the type arguments. |
| 536 // We would incorrectly instantiate a class like A instead of A<B>. | 562 // We would incorrectly instantiate a class like A instead of A<B>. |
| 537 // TODO(kmillikin): try to fix this. | 563 // TODO(kmillikin): try to fix this. |
| 538 GenericType generic = node.dartType; | 564 GenericType generic = node.dartType; |
| 539 if (generic.typeArguments.any((DartType t) => !t.isDynamic)) return null; | 565 if (generic.typeArguments.any((DartType t) => !t.isDynamic)) return null; |
| 540 } | 566 } |
| 541 return tryInlining(node, node.target, null); | 567 return tryInlining(node, node.target, null); |
| 542 } | 568 } |
| 543 } | 569 } |
| OLD | NEW |