Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1072)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/ssa/builder.dart

Issue 19250002: Support for inlining small methods (independent of they're called inside a loop or not) (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698