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

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: Status file change 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;
933 static const MAX_INLINING_NODES = 46;
934
935 List<InliningState> inliningStack; 932 List<InliningState> inliningStack;
936 933
937 Element returnElement; 934 Element returnElement;
938 DartType returnType; 935 DartType returnType;
939 936
940 bool inTryStatement = false; 937 bool inTryStatement = false;
941 int loopNesting = 0; 938 int loopNesting = 0;
942 939
943 HBasicBlock get current => _current; 940 HBasicBlock get current => _current;
944 void set current(c) { 941 void set current(c) {
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
1218 bool tryInlineMethod(Element element, 1215 bool tryInlineMethod(Element element,
1219 Selector selector, 1216 Selector selector,
1220 List<HInstruction> providedArguments, 1217 List<HInstruction> providedArguments,
1221 Node currentNode) { 1218 Node currentNode) {
1222 backend.registerStaticUse(element, compiler.enqueuer.codegen); 1219 backend.registerStaticUse(element, compiler.enqueuer.codegen);
1223 1220
1224 // Ensure that [element] is an implementation element. 1221 // Ensure that [element] is an implementation element.
1225 element = element.implementation; 1222 element = element.implementation;
1226 FunctionElement function = element; 1223 FunctionElement function = element;
1227 1224
1228 bool cachedCanBeInlined = backend.canBeInlined[function]; 1225 bool insideLoop = loopNesting > 0 || graph.calledInLoop;
1226
1227 // Bail out early if the inlining decision is in the cache and we can't
1228 // inline (no need to check the hard constraints).
1229 bool cachedCanBeInlined =
1230 backend.inlineCache.canInline(function, insideLoop: insideLoop);
1229 if (cachedCanBeInlined == false) return false; 1231 if (cachedCanBeInlined == false) return false;
1230 1232
1231 bool meetsHardConstraints() { 1233 bool meetsHardConstraints() {
1232 // We cannot inline a method from a deferred library into a method 1234 // We cannot inline a method from a deferred library into a method
1233 // which isn't deferred. 1235 // which isn't deferred.
1234 // TODO(ahe): But we should still inline into the same 1236 // TODO(ahe): But we should still inline into the same
1235 // connected-component of the deferred library. 1237 // connected-component of the deferred library.
1236 if (compiler.deferredLoadTask.isDeferred(element)) return false; 1238 if (compiler.deferredLoadTask.isDeferred(element)) return false;
1237 if (compiler.disableInlining) return false; 1239 if (compiler.disableInlining) return false;
1238 1240
1239 assert(selector != null 1241 assert(selector != null
1240 || Elements.isStaticOrTopLevel(element) 1242 || Elements.isStaticOrTopLevel(element)
1241 || element.isGenerativeConstructorBody()); 1243 || element.isGenerativeConstructorBody());
1242 if (selector != null && !selector.applies(function, compiler)) 1244 if (selector != null && !selector.applies(function, compiler)) {
1243 return false; 1245 return false;
1246 }
1244 1247
1245 // Don't inline operator== methods if the parameter can be null. 1248 // Don't inline operator== methods if the parameter can be null.
1246 if (element.name == const SourceString('==')) { 1249 if (element.name == const SourceString('==')) {
1247 if (element.getEnclosingClass() != compiler.objectClass 1250 if (element.getEnclosingClass() != compiler.objectClass
1248 && providedArguments[1].canBeNull()) { 1251 && providedArguments[1].canBeNull()) {
1249 return false; 1252 return false;
1250 } 1253 }
1251 } 1254 }
1252 1255
1253 // Don't inline if the return type was inferred to be non-null empty. This 1256 // Don't inline if the return type was inferred to be non-null empty. This
1254 // means that the function always throws an exception. 1257 // means that the function always throws an exception.
1255 TypeMask returnType = 1258 TypeMask returnType =
1256 compiler.typesTask.getGuaranteedReturnTypeOfElement(element); 1259 compiler.typesTask.getGuaranteedReturnTypeOfElement(element);
1257 if (returnType != null && returnType.isEmpty && !returnType.isNullable) { 1260 if (returnType != null && returnType.isEmpty && !returnType.isNullable) {
1258 isReachable = false; 1261 isReachable = false;
1259 return false; 1262 return false;
1260 } 1263 }
1261 1264
1262 return true; 1265 return true;
1263 } 1266 }
1264 1267
1265 bool heuristicsSayGoodToGo(FunctionExpression functionExpression, 1268 bool heuristicSayGoodToGo(FunctionExpression functionExpression) {
1266 TreeElements newElements) { 1269 // Don't inline recursivly
1267 if (loopNesting == 0 && !graph.calledInLoop) return false; 1270 if (inliningStack.any((entry) => entry.function == function)) {
1271 return false;
1272 }
1268 1273
1269 int maxDepth = (loopNesting > 0) ? MAX_INLINING_DEPTH : 1; 1274 if (cachedCanBeInlined == true) return cachedCanBeInlined;
1270 if (inliningStack.length >= maxDepth) return false;
1271 1275
1272 if (cachedCanBeInlined == null) { 1276 int numParameters = function.functionSignature.parameterCount;
1273 var canBeInlined = 1277 int maxInliningNodes;
1274 InlineWeeder.canBeInlined(functionExpression, newElements); 1278 if (insideLoop) {
1275 backend.canBeInlined[function] = canBeInlined; 1279 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP +
1276 return canBeInlined; 1280 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters;
1281 } else {
1282 maxInliningNodes = InlineWeeder.INLINING_NODES_OUTSIDE_LOOP +
1283 InlineWeeder.INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR * numParameters;
1277 } 1284 }
1278 return cachedCanBeInlined; 1285 bool canBeInlined = InlineWeeder.canBeInlined(
1286 functionExpression, maxInliningNodes);
1287 if (canBeInlined) {
1288 backend.inlineCache.markAsInlinable(element, insideLoop: insideLoop);
1289 } else {
1290 backend.inlineCache.markAsNonInlinable(element, insideLoop: insideLoop);
1291 }
1292 return canBeInlined;
1279 } 1293 }
1280 1294
1281 void doInlining(FunctionExpression functionExpression) { 1295 void doInlining(FunctionExpression functionExpression) {
1282 // Add an explicit null check on the receiver before doing the 1296 // Add an explicit null check on the receiver before doing the
1283 // inlining. We use [element] to get the same name in the 1297 // inlining. We use [element] to get the same name in the
1284 // NoSuchMethodError message as if we had called it. 1298 // NoSuchMethodError message as if we had called it.
1285 if (element.isInstanceMember() 1299 if (element.isInstanceMember()
1286 && !element.isGenerativeConstructorBody() 1300 && !element.isGenerativeConstructorBody()
1287 && (selector.mask == null || selector.mask.isNullable)) { 1301 && (selector.mask == null || selector.mask.isNullable)) {
1288 addWithPosition( 1302 addWithPosition(
(...skipping 11 matching lines...) Expand all
1300 }); 1314 });
1301 element.isGenerativeConstructor() 1315 element.isGenerativeConstructor()
1302 ? buildFactory(element) 1316 ? buildFactory(element)
1303 : functionExpression.body.accept(this); 1317 : functionExpression.body.accept(this);
1304 }); 1318 });
1305 leaveInlinedMethod(state); 1319 leaveInlinedMethod(state);
1306 } 1320 }
1307 1321
1308 if (meetsHardConstraints()) { 1322 if (meetsHardConstraints()) {
1309 FunctionExpression functionExpression = function.parseNode(compiler); 1323 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 1324
1316 if (heuristicsSayGoodToGo(functionExpression, newElements)) { 1325 if (heuristicSayGoodToGo(functionExpression)) {
1317 doInlining(functionExpression); 1326 doInlining(functionExpression);
1318 return true; 1327 return true;
1319 } 1328 }
1320 } 1329 }
1321 1330
1322 return false; 1331 return false;
1323 } 1332 }
1324 1333
1325 inlinedFrom(Element element, f()) { 1334 inlinedFrom(Element element, f()) {
1326 assert(element is FunctionElement || element is VariableElement); 1335 assert(element is FunctionElement || element is VariableElement);
(...skipping 3791 matching lines...) Expand 10 before | Expand all | Expand 10 after
5118 builder.add(instruction); 5127 builder.add(instruction);
5119 return instruction; 5128 return instruction;
5120 } 5129 }
5121 } 5130 }
5122 5131
5123 /** 5132 /**
5124 * This class visits the method that is a candidate for inlining and 5133 * This class visits the method that is a candidate for inlining and
5125 * finds whether it is too difficult to inline. 5134 * finds whether it is too difficult to inline.
5126 */ 5135 */
5127 class InlineWeeder extends Visitor { 5136 class InlineWeeder extends Visitor {
5128 final TreeElements elements; 5137 // Invariant: *INSIDE_LOOP* > *OUTSIDE_LOOP*
5138 static const INLINING_NODES_OUTSIDE_LOOP = 18;
5139 static const INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR = 3;
5140 static const INLINING_NODES_INSIDE_LOOP = 42;
5141 static const INLINING_NODES_INSIDE_LOOP_ARG_FACTOR = 4;
5129 5142
5130 bool seenReturn = false; 5143 bool seenReturn = false;
5131 bool tooDifficult = false; 5144 bool tooDifficult = false;
5132 int nodeCount = 0; 5145 int nodeCount = 0;
5146 final int maxInliningNodes;
5133 5147
5134 InlineWeeder(this.elements); 5148 InlineWeeder(this.maxInliningNodes);
5135 5149
5136 static bool canBeInlined(FunctionExpression functionExpression, 5150 static bool canBeInlined(FunctionExpression functionExpression,
5137 TreeElements elements) { 5151 int maxInliningNodes) {
5138 InlineWeeder weeder = new InlineWeeder(elements); 5152 InlineWeeder weeder = new InlineWeeder(maxInliningNodes);
5139 weeder.visit(functionExpression.initializers); 5153 weeder.visit(functionExpression.initializers);
5140 weeder.visit(functionExpression.body); 5154 weeder.visit(functionExpression.body);
5141 if (weeder.tooDifficult) return false; 5155 return !weeder.tooDifficult;
5142 return true;
5143 } 5156 }
5144 5157
5145 bool registerNode() { 5158 bool registerNode() {
5146 if (nodeCount++ > SsaBuilder.MAX_INLINING_NODES) { 5159 if (nodeCount++ > maxInliningNodes) {
5147 tooDifficult = true; 5160 tooDifficult = true;
5148 return false; 5161 return false;
5149 } else { 5162 } else {
5150 return true; 5163 return true;
5151 } 5164 }
5152 } 5165 }
5153 5166
5154 void visit(Node node) { 5167 void visit(Node node) {
5155 if (node != null) node.accept(this); 5168 if (node != null) node.accept(this);
5156 } 5169 }
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
5467 new HSubGraphBlockInformation(elseBranch.graph)); 5480 new HSubGraphBlockInformation(elseBranch.graph));
5468 5481
5469 HBasicBlock conditionStartBlock = conditionBranch.block; 5482 HBasicBlock conditionStartBlock = conditionBranch.block;
5470 conditionStartBlock.setBlockFlow(info, joinBlock); 5483 conditionStartBlock.setBlockFlow(info, joinBlock);
5471 SubGraph conditionGraph = conditionBranch.graph; 5484 SubGraph conditionGraph = conditionBranch.graph;
5472 HIf branch = conditionGraph.end.last; 5485 HIf branch = conditionGraph.end.last;
5473 assert(branch is HIf); 5486 assert(branch is HIf);
5474 branch.blockInformation = conditionStartBlock.blockFlow; 5487 branch.blockInformation = conditionStartBlock.blockFlow;
5475 } 5488 }
5476 } 5489 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/compiler/implementation/js_backend/backend.dart ('k') | tests/co19/co19-dart2js.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698