| 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 class SsaFunctionCompiler implements FunctionCompiler { | 7 class SsaFunctionCompiler implements FunctionCompiler { |
| 8 SsaCodeGeneratorTask generator; | 8 SsaCodeGeneratorTask generator; |
| 9 SsaBuilderTask builder; | 9 SsaBuilderTask builder; |
| 10 SsaOptimizerTask optimizer; | 10 SsaOptimizerTask optimizer; |
| (...skipping 1319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1330 } | 1330 } |
| 1331 } | 1331 } |
| 1332 | 1332 |
| 1333 return true; | 1333 return true; |
| 1334 } | 1334 } |
| 1335 | 1335 |
| 1336 bool reductiveHeuristic() { | 1336 bool reductiveHeuristic() { |
| 1337 // The call is on a path which is executed rarely, so inline only if it | 1337 // The call is on a path which is executed rarely, so inline only if it |
| 1338 // does not make the program larger. | 1338 // does not make the program larger. |
| 1339 if (isCalledOnce(element)) { | 1339 if (isCalledOnce(element)) { |
| 1340 return InlineWeeder.canBeInlined(function.node, -1, false); | 1340 return InlineWeeder.canBeInlined(backend, function, -1, false); |
| 1341 } | 1341 } |
| 1342 // TODO(sra): Measure if inlining would 'reduce' the size. One desirable | 1342 // TODO(sra): Measure if inlining would 'reduce' the size. One desirable |
| 1343 // case we miss my doing nothing is inlining very simple constructors | 1343 // case we miss my doing nothing is inlining very simple constructors |
| 1344 // where all fields are initialized with values from the arguments at this | 1344 // where all fields are initialized with values from the arguments at this |
| 1345 // call site. The code is slightly larger (`new Foo(1)` vs `Foo$(1)`) but | 1345 // call site. The code is slightly larger (`new Foo(1)` vs `Foo$(1)`) but |
| 1346 // that usually means the factory constructor is left unused and not | 1346 // that usually means the factory constructor is left unused and not |
| 1347 // emitted. | 1347 // emitted. |
| 1348 return false; | 1348 return false; |
| 1349 } | 1349 } |
| 1350 | 1350 |
| 1351 bool heuristicSayGoodToGo() { | 1351 bool heuristicSayGoodToGo() { |
| 1352 // Don't inline recursively | 1352 // Don't inline recursively |
| 1353 if (inliningStack.any((entry) => entry.function == function)) { | 1353 if (inliningStack.any((entry) => entry.function == function)) { |
| 1354 return false; | 1354 return false; |
| 1355 } | 1355 } |
| 1356 | 1356 |
| 1357 if (element.isSynthesized) return true; | 1357 if (element.isSynthesized) return true; |
| 1358 | 1358 |
| 1359 if (inExpressionOfThrow || inLazyInitializerExpression) { | 1359 if (inExpressionOfThrow || inLazyInitializerExpression) { |
| 1360 return reductiveHeuristic(); | 1360 return reductiveHeuristic(); |
| 1361 } | 1361 } |
| 1362 | 1362 |
| 1363 if (cachedCanBeInlined == true) return cachedCanBeInlined; | 1363 if (cachedCanBeInlined == true) return cachedCanBeInlined; |
| 1364 | 1364 |
| 1365 if (backend.functionsToAlwaysInline.contains(function)) { | 1365 if (backend.functionsToAlwaysInline.contains(function)) { |
| 1366 // Inline this function regardless of it's size. | 1366 // Inline this function regardless of it's size. |
| 1367 assert(InlineWeeder.canBeInlined(function.node, -1, false, | 1367 assert(InlineWeeder.canBeInlined(backend, function, -1, false, |
| 1368 allowLoops: true)); | 1368 allowLoops: true)); |
| 1369 return true; | 1369 return true; |
| 1370 } | 1370 } |
| 1371 | 1371 |
| 1372 int numParameters = function.functionSignature.parameterCount; | 1372 int numParameters = function.functionSignature.parameterCount; |
| 1373 int maxInliningNodes; | 1373 int maxInliningNodes; |
| 1374 bool useMaxInliningNodes = true; | 1374 bool useMaxInliningNodes = true; |
| 1375 if (insideLoop) { | 1375 if (insideLoop) { |
| 1376 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP + | 1376 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP + |
| 1377 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; | 1377 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; |
| 1378 } else { | 1378 } else { |
| 1379 maxInliningNodes = InlineWeeder.INLINING_NODES_OUTSIDE_LOOP + | 1379 maxInliningNodes = InlineWeeder.INLINING_NODES_OUTSIDE_LOOP + |
| 1380 InlineWeeder.INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR * numParameters; | 1380 InlineWeeder.INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR * numParameters; |
| 1381 } | 1381 } |
| 1382 | 1382 |
| 1383 // If a method is called only once, and all the methods in the | 1383 // If a method is called only once, and all the methods in the |
| 1384 // inlining stack are called only once as well, we know we will | 1384 // inlining stack are called only once as well, we know we will |
| 1385 // save on output size by inlining this method. | 1385 // save on output size by inlining this method. |
| 1386 if (isCalledOnce(element)) { | 1386 if (isCalledOnce(element)) { |
| 1387 useMaxInliningNodes = false; | 1387 useMaxInliningNodes = false; |
| 1388 } | 1388 } |
| 1389 bool canInline; | 1389 bool canInline; |
| 1390 ast.FunctionExpression functionNode = function.node; | |
| 1391 canInline = InlineWeeder.canBeInlined( | 1390 canInline = InlineWeeder.canBeInlined( |
| 1392 functionNode, maxInliningNodes, useMaxInliningNodes); | 1391 backend, function, maxInliningNodes, useMaxInliningNodes); |
| 1393 if (canInline) { | 1392 if (canInline) { |
| 1394 backend.inlineCache.markAsInlinable(element, insideLoop: insideLoop); | 1393 backend.inlineCache.markAsInlinable(element, insideLoop: insideLoop); |
| 1395 } else { | 1394 } else { |
| 1396 backend.inlineCache.markAsNonInlinable(element, insideLoop: insideLoop); | 1395 backend.inlineCache.markAsNonInlinable(element, insideLoop: insideLoop); |
| 1397 } | 1396 } |
| 1398 return canInline; | 1397 return canInline; |
| 1399 } | 1398 } |
| 1400 | 1399 |
| 1401 void doInlining() { | 1400 void doInlining() { |
| 1402 // Add an explicit null check on the receiver before doing the | 1401 // Add an explicit null check on the receiver before doing the |
| (...skipping 5041 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6444 bool tooDifficult = false; | 6443 bool tooDifficult = false; |
| 6445 int nodeCount = 0; | 6444 int nodeCount = 0; |
| 6446 final int maxInliningNodes; | 6445 final int maxInliningNodes; |
| 6447 final bool useMaxInliningNodes; | 6446 final bool useMaxInliningNodes; |
| 6448 final bool allowLoops; | 6447 final bool allowLoops; |
| 6449 | 6448 |
| 6450 InlineWeeder(this.maxInliningNodes, | 6449 InlineWeeder(this.maxInliningNodes, |
| 6451 this.useMaxInliningNodes, | 6450 this.useMaxInliningNodes, |
| 6452 this.allowLoops); | 6451 this.allowLoops); |
| 6453 | 6452 |
| 6454 static bool canBeInlined(ast.FunctionExpression functionExpression, | 6453 static bool canBeInlined(JavaScriptBackend backend, |
| 6454 FunctionElement function, |
| 6455 int maxInliningNodes, | 6455 int maxInliningNodes, |
| 6456 bool useMaxInliningNodes, | 6456 bool useMaxInliningNodes, |
| 6457 {bool allowLoops: false}) { | 6457 {bool allowLoops: false}) { |
| 6458 if (backend.annotations.noInlining(function)) { |
| 6459 return false; |
| 6460 } |
| 6461 |
| 6458 InlineWeeder weeder = | 6462 InlineWeeder weeder = |
| 6459 new InlineWeeder(maxInliningNodes, useMaxInliningNodes, allowLoops); | 6463 new InlineWeeder(maxInliningNodes, useMaxInliningNodes, allowLoops); |
| 6464 ast.FunctionExpression functionExpression = function.node; |
| 6460 weeder.visit(functionExpression.initializers); | 6465 weeder.visit(functionExpression.initializers); |
| 6461 weeder.visit(functionExpression.body); | 6466 weeder.visit(functionExpression.body); |
| 6462 weeder.visit(functionExpression.asyncModifier); | 6467 weeder.visit(functionExpression.asyncModifier); |
| 6463 return !weeder.tooDifficult; | 6468 return !weeder.tooDifficult; |
| 6464 } | 6469 } |
| 6465 | 6470 |
| 6466 bool registerNode() { | 6471 bool registerNode() { |
| 6467 if (!useMaxInliningNodes) return true; | 6472 if (!useMaxInliningNodes) return true; |
| 6468 if (nodeCount++ > maxInliningNodes) { | 6473 if (nodeCount++ > maxInliningNodes) { |
| 6469 tooDifficult = true; | 6474 tooDifficult = true; |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6915 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 6920 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
| 6916 unaliased.accept(this, builder); | 6921 unaliased.accept(this, builder); |
| 6917 } | 6922 } |
| 6918 | 6923 |
| 6919 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 6924 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
| 6920 JavaScriptBackend backend = builder.compiler.backend; | 6925 JavaScriptBackend backend = builder.compiler.backend; |
| 6921 ClassElement cls = backend.findHelper('DynamicRuntimeType'); | 6926 ClassElement cls = backend.findHelper('DynamicRuntimeType'); |
| 6922 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); | 6927 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); |
| 6923 } | 6928 } |
| 6924 } | 6929 } |
| OLD | NEW |