Chromium Code Reviews| 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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A special element for the extra parameter taken by intercepted | 8 * A special element for the extra parameter taken by intercepted |
| 9 * methods. We need to override [Element.computeType] because our | 9 * methods. We need to override [Element.computeType] because our |
| 10 * optimizers may look at its declared type. | 10 * optimizers may look at its declared type. |
| (...skipping 911 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 922 activationVariables = new Map<Element, HLocalValue>(), | 922 activationVariables = new Map<Element, HLocalValue>(), |
| 923 jumpTargets = new Map<TargetElement, JumpHandler>(), | 923 jumpTargets = new Map<TargetElement, JumpHandler>(), |
| 924 parameters = new Map<Element, HInstruction>(), | 924 parameters = new Map<Element, HInstruction>(), |
| 925 sourceElementStack = <Element>[work.element], | 925 sourceElementStack = <Element>[work.element], |
| 926 inliningStack = <InliningState>[], | 926 inliningStack = <InliningState>[], |
| 927 rti = builder.backend.rti, | 927 rti = builder.backend.rti, |
| 928 super(work.resolutionTree) { | 928 super(work.resolutionTree) { |
| 929 localsHandler = new LocalsHandler(this); | 929 localsHandler = new LocalsHandler(this); |
| 930 } | 930 } |
| 931 | 931 |
| 932 static const MAX_INLINING_DEPTH = 3; | 932 static const MAX_INLINING_DEPTH = 5; |
|
ngeoffray
2013/07/16 08:04:45
Consider moving inlining considerations into its o
kustermann
2013/07/16 13:27:50
Moved it now to InlineWeeder.
| |
| 933 static const MAX_INLINING_NODES = 46; | 933 // Invariant: *INSIDE_LOOP* > *OUTSIDE_LOOP* |
| 934 static const INLINING_NODES_OUTSIDE_LOOP = 10; | |
| 935 static const INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR = 10; | |
| 936 static const INLINING_NODES_INSIDE_LOOP = 35; | |
| 937 static const INLINING_NODES_INSIDE_LOOP_ARG_FACTOR = 15; | |
| 934 | 938 |
| 935 List<InliningState> inliningStack; | 939 List<InliningState> inliningStack; |
| 936 | 940 |
| 937 Element returnElement; | 941 Element returnElement; |
| 938 DartType returnType; | 942 DartType returnType; |
| 939 | 943 |
| 940 bool inTryStatement = false; | 944 bool inTryStatement = false; |
| 941 int loopNesting = 0; | 945 int loopNesting = 0; |
| 942 | 946 |
| 943 HBasicBlock get current => _current; | 947 HBasicBlock get current => _current; |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1218 bool tryInlineMethod(Element element, | 1222 bool tryInlineMethod(Element element, |
| 1219 Selector selector, | 1223 Selector selector, |
| 1220 List<HInstruction> providedArguments, | 1224 List<HInstruction> providedArguments, |
| 1221 Node currentNode) { | 1225 Node currentNode) { |
| 1222 backend.registerStaticUse(element, compiler.enqueuer.codegen); | 1226 backend.registerStaticUse(element, compiler.enqueuer.codegen); |
| 1223 | 1227 |
| 1224 // Ensure that [element] is an implementation element. | 1228 // Ensure that [element] is an implementation element. |
| 1225 element = element.implementation; | 1229 element = element.implementation; |
| 1226 FunctionElement function = element; | 1230 FunctionElement function = element; |
| 1227 | 1231 |
| 1228 bool cachedCanBeInlined = backend.canBeInlined[function]; | 1232 var insideLoop = loopNesting > 0 || graph.calledInLoop; |
|
ngeoffray
2013/07/16 08:04:45
var -> bool
kustermann
2013/07/16 13:27:50
Done.
| |
| 1233 | |
| 1234 // Bail out early if the inlining decision is in the cache and we can't | |
| 1235 // inline (no need to check the hard constraints). | |
| 1236 bool cachedCanBeInlined = | |
| 1237 backend.inlineCache.canInline(function, insideLoop: insideLoop); | |
| 1229 if (cachedCanBeInlined == false) return false; | 1238 if (cachedCanBeInlined == false) return false; |
| 1230 | 1239 |
| 1231 bool meetsHardConstraints() { | 1240 bool meetsHardConstraints() { |
| 1232 // We cannot inline a method from a deferred library into a method | 1241 // We cannot inline a method from a deferred library into a method |
| 1233 // which isn't deferred. | 1242 // which isn't deferred. |
| 1234 // TODO(ahe): But we should still inline into the same | 1243 // TODO(ahe): But we should still inline into the same |
| 1235 // connected-component of the deferred library. | 1244 // connected-component of the deferred library. |
| 1236 if (compiler.deferredLoadTask.isDeferred(element)) return false; | 1245 if (compiler.deferredLoadTask.isDeferred(element)) return false; |
| 1237 if (compiler.disableInlining) return false; | 1246 if (compiler.disableInlining) return false; |
| 1238 | 1247 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1252 | 1261 |
| 1253 // Don't inline if the return type was inferred to be non-null empty. This | 1262 // Don't inline if the return type was inferred to be non-null empty. This |
| 1254 // means that the function always throws an exception. | 1263 // means that the function always throws an exception. |
| 1255 TypeMask returnType = | 1264 TypeMask returnType = |
| 1256 compiler.typesTask.getGuaranteedReturnTypeOfElement(element); | 1265 compiler.typesTask.getGuaranteedReturnTypeOfElement(element); |
| 1257 if (returnType != null && returnType.isEmpty && !returnType.isNullable) { | 1266 if (returnType != null && returnType.isEmpty && !returnType.isNullable) { |
| 1258 isReachable = false; | 1267 isReachable = false; |
| 1259 return false; | 1268 return false; |
| 1260 } | 1269 } |
| 1261 | 1270 |
| 1271 // Don't inline recursivly | |
|
ngeoffray
2013/07/16 08:04:45
Shouldn't that be part of the heuristics?
kustermann
2013/07/16 13:27:50
Why should this be part of a heuristic? We require
| |
| 1272 if (inliningStack.any((entry) => entry.function == function)) | |
|
kustermann
2013/07/15 17:40:27
I'll add a test to make sure this guard against re
ngeoffray
2013/07/16 08:04:45
Nit: add braces with a newline on an if.
kustermann
2013/07/16 13:27:50
I saw this style
if (cond)
return x;
quite a
| |
| 1273 return false; | |
| 1274 | |
| 1262 return true; | 1275 return true; |
| 1263 } | 1276 } |
| 1264 | 1277 |
| 1265 bool heuristicsSayGoodToGo(FunctionExpression functionExpression, | 1278 bool heuristicSayGoodToGo(FunctionExpression functionExpression) { |
| 1266 TreeElements newElements) { | 1279 //if (inliningStack.length >= MAX_INLINING_DEPTH) { |
|
kustermann
2013/07/15 17:40:27
Don't know if we should limit the inlining depth h
ngeoffray
2013/07/16 08:04:45
Should we have a canBeInlined cache for methods th
kustermann
2013/07/16 13:27:50
I think we should not make our inlining decisions
| |
| 1267 if (loopNesting == 0 && !graph.calledInLoop) return false; | 1280 // return false; |
| 1281 //} | |
| 1268 | 1282 |
| 1269 int maxDepth = (loopNesting > 0) ? MAX_INLINING_DEPTH : 1; | 1283 if (cachedCanBeInlined == true) |
| 1270 if (inliningStack.length >= maxDepth) return false; | 1284 return cachedCanBeInlined; |
|
ngeoffray
2013/07/16 08:04:45
One line, or braces.
kustermann
2013/07/16 13:27:50
Done.
| |
| 1271 | 1285 |
| 1272 if (cachedCanBeInlined == null) { | 1286 var numParameters = function.functionSignature.parameterCount; |
|
ngeoffray
2013/07/16 08:04:45
var -> int
kustermann
2013/07/16 13:27:50
Done.
| |
| 1273 var canBeInlined = | 1287 var maxInliningNodes; |
|
ngeoffray
2013/07/16 08:04:45
var -> int.
kustermann
2013/07/16 13:27:50
Done.
| |
| 1274 InlineWeeder.canBeInlined(functionExpression, newElements); | 1288 if (insideLoop) { |
| 1275 backend.canBeInlined[function] = canBeInlined; | 1289 maxInliningNodes = SsaBuilder.INLINING_NODES_INSIDE_LOOP + |
| 1276 return canBeInlined; | 1290 SsaBuilder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; |
| 1291 } else { | |
| 1292 maxInliningNodes = SsaBuilder.INLINING_NODES_OUTSIDE_LOOP + | |
| 1293 SsaBuilder.INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR * numParameters; | |
| 1277 } | 1294 } |
| 1278 return cachedCanBeInlined; | 1295 var canBeInlined = InlineWeeder.canBeInlined( |
|
ngeoffray
2013/07/16 08:04:45
var -> bool
kustermann
2013/07/16 13:27:50
Done.
| |
| 1296 functionExpression, maxInliningNodes); | |
| 1297 if (canBeInlined) { | |
| 1298 backend.inlineCache.markAsInlinable(element, insideLoop: insideLoop); | |
| 1299 } else { | |
| 1300 backend.inlineCache.markAsNonInlinable(element, insideLoop: insideLoop); | |
| 1301 } | |
| 1302 return canBeInlined; | |
| 1279 } | 1303 } |
| 1280 | 1304 |
| 1281 void doInlining(FunctionExpression functionExpression) { | 1305 void doInlining(FunctionExpression functionExpression) { |
| 1282 // Add an explicit null check on the receiver before doing the | 1306 // Add an explicit null check on the receiver before doing the |
| 1283 // inlining. We use [element] to get the same name in the | 1307 // inlining. We use [element] to get the same name in the |
| 1284 // NoSuchMethodError message as if we had called it. | 1308 // NoSuchMethodError message as if we had called it. |
| 1285 if (element.isInstanceMember() | 1309 if (element.isInstanceMember() |
| 1286 && !element.isGenerativeConstructorBody() | 1310 && !element.isGenerativeConstructorBody() |
| 1287 && (selector.mask == null || selector.mask.isNullable)) { | 1311 && (selector.mask == null || selector.mask.isNullable)) { |
| 1288 addWithPosition( | 1312 addWithPosition( |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1300 }); | 1324 }); |
| 1301 element.isGenerativeConstructor() | 1325 element.isGenerativeConstructor() |
| 1302 ? buildFactory(element) | 1326 ? buildFactory(element) |
| 1303 : functionExpression.body.accept(this); | 1327 : functionExpression.body.accept(this); |
| 1304 }); | 1328 }); |
| 1305 leaveInlinedMethod(state); | 1329 leaveInlinedMethod(state); |
| 1306 } | 1330 } |
| 1307 | 1331 |
| 1308 if (meetsHardConstraints()) { | 1332 if (meetsHardConstraints()) { |
| 1309 FunctionExpression functionExpression = function.parseNode(compiler); | 1333 FunctionExpression functionExpression = function.parseNode(compiler); |
| 1310 TreeElements newElements = | |
| 1311 compiler.enqueuer.resolution.getCachedElements(function); | |
| 1312 if (newElements == null) { | |
| 1313 compiler.internalError("Element not resolved: $function"); | |
| 1314 } | |
| 1315 | 1334 |
| 1316 if (heuristicsSayGoodToGo(functionExpression, newElements)) { | 1335 if (heuristicSayGoodToGo(functionExpression)) { |
| 1317 doInlining(functionExpression); | 1336 doInlining(functionExpression); |
| 1318 return true; | 1337 return true; |
| 1319 } | 1338 } |
| 1320 } | 1339 } |
| 1321 | 1340 |
| 1322 return false; | 1341 return false; |
| 1323 } | 1342 } |
| 1324 | 1343 |
| 1325 inlinedFrom(Element element, f()) { | 1344 inlinedFrom(Element element, f()) { |
| 1326 assert(element is FunctionElement || element is VariableElement); | 1345 assert(element is FunctionElement || element is VariableElement); |
| (...skipping 3791 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5118 builder.add(instruction); | 5137 builder.add(instruction); |
| 5119 return instruction; | 5138 return instruction; |
| 5120 } | 5139 } |
| 5121 } | 5140 } |
| 5122 | 5141 |
| 5123 /** | 5142 /** |
| 5124 * This class visits the method that is a candidate for inlining and | 5143 * This class visits the method that is a candidate for inlining and |
| 5125 * finds whether it is too difficult to inline. | 5144 * finds whether it is too difficult to inline. |
| 5126 */ | 5145 */ |
| 5127 class InlineWeeder extends Visitor { | 5146 class InlineWeeder extends Visitor { |
| 5128 final TreeElements elements; | |
| 5129 | |
| 5130 bool seenReturn = false; | 5147 bool seenReturn = false; |
| 5131 bool tooDifficult = false; | 5148 bool tooDifficult = false; |
| 5132 int nodeCount = 0; | 5149 int nodeCount = 0; |
| 5150 int maxInliningNodes; | |
|
ngeoffray
2013/07/16 08:04:45
final
kustermann
2013/07/16 13:27:50
Done.
| |
| 5133 | 5151 |
| 5134 InlineWeeder(this.elements); | 5152 InlineWeeder(this.maxInliningNodes); |
| 5135 | 5153 |
| 5136 static bool canBeInlined(FunctionExpression functionExpression, | 5154 static bool canBeInlined(FunctionExpression functionExpression, |
| 5137 TreeElements elements) { | 5155 int maxInliningNodes) { |
| 5138 InlineWeeder weeder = new InlineWeeder(elements); | 5156 InlineWeeder weeder = new InlineWeeder(maxInliningNodes); |
| 5139 weeder.visit(functionExpression.initializers); | 5157 weeder.visit(functionExpression.initializers); |
| 5140 weeder.visit(functionExpression.body); | 5158 weeder.visit(functionExpression.body); |
| 5141 if (weeder.tooDifficult) return false; | 5159 return !weeder.tooDifficult; |
| 5142 return true; | |
| 5143 } | 5160 } |
| 5144 | 5161 |
| 5145 bool registerNode() { | 5162 bool registerNode() { |
| 5146 if (nodeCount++ > SsaBuilder.MAX_INLINING_NODES) { | 5163 if (nodeCount++ > maxInliningNodes) { |
| 5147 tooDifficult = true; | 5164 tooDifficult = true; |
| 5148 return false; | 5165 return false; |
| 5149 } else { | 5166 } else { |
| 5150 return true; | 5167 return true; |
| 5151 } | 5168 } |
| 5152 } | 5169 } |
| 5153 | 5170 |
| 5154 void visit(Node node) { | 5171 void visit(Node node) { |
| 5155 if (node != null) node.accept(this); | 5172 if (node != null) node.accept(this); |
| 5156 } | 5173 } |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5467 new HSubGraphBlockInformation(elseBranch.graph)); | 5484 new HSubGraphBlockInformation(elseBranch.graph)); |
| 5468 | 5485 |
| 5469 HBasicBlock conditionStartBlock = conditionBranch.block; | 5486 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 5470 conditionStartBlock.setBlockFlow(info, joinBlock); | 5487 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 5471 SubGraph conditionGraph = conditionBranch.graph; | 5488 SubGraph conditionGraph = conditionBranch.graph; |
| 5472 HIf branch = conditionGraph.end.last; | 5489 HIf branch = conditionGraph.end.last; |
| 5473 assert(branch is HIf); | 5490 assert(branch is HIf); |
| 5474 branch.blockInformation = conditionStartBlock.blockFlow; | 5491 branch.blockInformation = conditionStartBlock.blockFlow; |
| 5475 } | 5492 } |
| 5476 } | 5493 } |
| OLD | NEW |