| 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 final SsaCodeGeneratorTask generator; | 8 final SsaCodeGeneratorTask generator; |
| 9 final SsaBuilderTask builder; | 9 final SsaBuilderTask builder; |
| 10 final SsaOptimizerTask optimizer; | 10 final SsaOptimizerTask optimizer; |
| (...skipping 1345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1356 isReachable = false; | 1356 isReachable = false; |
| 1357 return false; | 1357 return false; |
| 1358 } | 1358 } |
| 1359 } | 1359 } |
| 1360 | 1360 |
| 1361 return true; | 1361 return true; |
| 1362 } | 1362 } |
| 1363 | 1363 |
| 1364 bool doesNotContainCode() { | 1364 bool doesNotContainCode() { |
| 1365 // A function with size 1 does not contain any code. | 1365 // A function with size 1 does not contain any code. |
| 1366 return InlineWeeder.canBeInlined(function, 1, true); | 1366 return InlineWeeder.canBeInlined(function, 1, true, |
| 1367 enableUserAssertions: compiler.enableUserAssertions); |
| 1367 } | 1368 } |
| 1368 | 1369 |
| 1369 bool reductiveHeuristic() { | 1370 bool reductiveHeuristic() { |
| 1370 // The call is on a path which is executed rarely, so inline only if it | 1371 // The call is on a path which is executed rarely, so inline only if it |
| 1371 // does not make the program larger. | 1372 // does not make the program larger. |
| 1372 if (isCalledOnce(element)) { | 1373 if (isCalledOnce(element)) { |
| 1373 return InlineWeeder.canBeInlined(function, -1, false); | 1374 return InlineWeeder.canBeInlined(function, -1, false, |
| 1375 enableUserAssertions: compiler.enableUserAssertions); |
| 1374 } | 1376 } |
| 1375 // TODO(sra): Measure if inlining would 'reduce' the size. One desirable | 1377 // TODO(sra): Measure if inlining would 'reduce' the size. One desirable |
| 1376 // case we miss by doing nothing is inlining very simple constructors | 1378 // case we miss by doing nothing is inlining very simple constructors |
| 1377 // where all fields are initialized with values from the arguments at this | 1379 // where all fields are initialized with values from the arguments at this |
| 1378 // call site. The code is slightly larger (`new Foo(1)` vs `Foo$(1)`) but | 1380 // call site. The code is slightly larger (`new Foo(1)` vs `Foo$(1)`) but |
| 1379 // that usually means the factory constructor is left unused and not | 1381 // that usually means the factory constructor is left unused and not |
| 1380 // emitted. | 1382 // emitted. |
| 1381 // We at least inline bodies that are empty (and thus have a size of 1). | 1383 // We at least inline bodies that are empty (and thus have a size of 1). |
| 1382 return doesNotContainCode(); | 1384 return doesNotContainCode(); |
| 1383 } | 1385 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1401 | 1403 |
| 1402 // Do not inline code that is rarely executed unless it reduces size. | 1404 // Do not inline code that is rarely executed unless it reduces size. |
| 1403 if (inExpressionOfThrow || inLazyInitializerExpression) { | 1405 if (inExpressionOfThrow || inLazyInitializerExpression) { |
| 1404 return reductiveHeuristic(); | 1406 return reductiveHeuristic(); |
| 1405 } | 1407 } |
| 1406 | 1408 |
| 1407 if (cachedCanBeInlined == true) { | 1409 if (cachedCanBeInlined == true) { |
| 1408 // We may have forced the inlining of some methods. Therefore check | 1410 // We may have forced the inlining of some methods. Therefore check |
| 1409 // if we can inline this method regardless of size. | 1411 // if we can inline this method regardless of size. |
| 1410 assert(InlineWeeder.canBeInlined(function, -1, false, | 1412 assert(InlineWeeder.canBeInlined(function, -1, false, |
| 1411 allowLoops: true)); | 1413 allowLoops: true, |
| 1414 enableUserAssertions: compiler.enableUserAssertions)); |
| 1412 return true; | 1415 return true; |
| 1413 } | 1416 } |
| 1414 | 1417 |
| 1415 int numParameters = function.functionSignature.parameterCount; | 1418 int numParameters = function.functionSignature.parameterCount; |
| 1416 int maxInliningNodes; | 1419 int maxInliningNodes; |
| 1417 bool useMaxInliningNodes = true; | 1420 bool useMaxInliningNodes = true; |
| 1418 if (insideLoop) { | 1421 if (insideLoop) { |
| 1419 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP + | 1422 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP + |
| 1420 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; | 1423 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; |
| 1421 } else { | 1424 } else { |
| 1422 maxInliningNodes = InlineWeeder.INLINING_NODES_OUTSIDE_LOOP + | 1425 maxInliningNodes = InlineWeeder.INLINING_NODES_OUTSIDE_LOOP + |
| 1423 InlineWeeder.INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR * numParameters; | 1426 InlineWeeder.INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR * numParameters; |
| 1424 } | 1427 } |
| 1425 | 1428 |
| 1426 // If a method is called only once, and all the methods in the | 1429 // If a method is called only once, and all the methods in the |
| 1427 // inlining stack are called only once as well, we know we will | 1430 // inlining stack are called only once as well, we know we will |
| 1428 // save on output size by inlining this method. | 1431 // save on output size by inlining this method. |
| 1429 if (isCalledOnce(element)) { | 1432 if (isCalledOnce(element)) { |
| 1430 useMaxInliningNodes = false; | 1433 useMaxInliningNodes = false; |
| 1431 } | 1434 } |
| 1432 bool canInline; | 1435 bool canInline; |
| 1433 canInline = InlineWeeder.canBeInlined( | 1436 canInline = InlineWeeder.canBeInlined( |
| 1434 function, maxInliningNodes, useMaxInliningNodes); | 1437 function, maxInliningNodes, useMaxInliningNodes, |
| 1438 enableUserAssertions: compiler.enableUserAssertions); |
| 1435 if (canInline) { | 1439 if (canInline) { |
| 1436 backend.inlineCache.markAsInlinable(element, insideLoop: insideLoop); | 1440 backend.inlineCache.markAsInlinable(element, insideLoop: insideLoop); |
| 1437 } else { | 1441 } else { |
| 1438 backend.inlineCache.markAsNonInlinable(element, insideLoop: insideLoop); | 1442 backend.inlineCache.markAsNonInlinable(element, insideLoop: insideLoop); |
| 1439 } | 1443 } |
| 1440 return canInline; | 1444 return canInline; |
| 1441 } | 1445 } |
| 1442 | 1446 |
| 1443 void doInlining() { | 1447 void doInlining() { |
| 1444 // Add an explicit null check on the receiver before doing the | 1448 // Add an explicit null check on the receiver before doing the |
| (...skipping 7016 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8461 static const INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR = 3; | 8465 static const INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR = 3; |
| 8462 static const INLINING_NODES_INSIDE_LOOP = 42; | 8466 static const INLINING_NODES_INSIDE_LOOP = 42; |
| 8463 static const INLINING_NODES_INSIDE_LOOP_ARG_FACTOR = 4; | 8467 static const INLINING_NODES_INSIDE_LOOP_ARG_FACTOR = 4; |
| 8464 | 8468 |
| 8465 bool seenReturn = false; | 8469 bool seenReturn = false; |
| 8466 bool tooDifficult = false; | 8470 bool tooDifficult = false; |
| 8467 int nodeCount = 0; | 8471 int nodeCount = 0; |
| 8468 final int maxInliningNodes; | 8472 final int maxInliningNodes; |
| 8469 final bool useMaxInliningNodes; | 8473 final bool useMaxInliningNodes; |
| 8470 final bool allowLoops; | 8474 final bool allowLoops; |
| 8475 final bool enableUserAssertions; |
| 8471 | 8476 |
| 8472 InlineWeeder(this.maxInliningNodes, | 8477 InlineWeeder(this.maxInliningNodes, |
| 8473 this.useMaxInliningNodes, | 8478 this.useMaxInliningNodes, |
| 8474 this.allowLoops); | 8479 this.allowLoops, |
| 8480 this.enableUserAssertions); |
| 8475 | 8481 |
| 8476 static bool canBeInlined(FunctionElement function, | 8482 static bool canBeInlined(FunctionElement function, |
| 8477 int maxInliningNodes, | 8483 int maxInliningNodes, |
| 8478 bool useMaxInliningNodes, | 8484 bool useMaxInliningNodes, |
| 8479 {bool allowLoops: false}) { | 8485 {bool allowLoops: false, |
| 8486 bool enableUserAssertions: null}) { |
| 8487 assert(enableUserAssertions is bool); // Ensure we passed it. |
| 8480 if (function.resolvedAst.elements.containsTryStatement) return false; | 8488 if (function.resolvedAst.elements.containsTryStatement) return false; |
| 8481 | 8489 |
| 8482 InlineWeeder weeder = | 8490 InlineWeeder weeder = |
| 8483 new InlineWeeder(maxInliningNodes, useMaxInliningNodes, allowLoops); | 8491 new InlineWeeder(maxInliningNodes, useMaxInliningNodes, allowLoops, |
| 8492 enableUserAssertions); |
| 8484 ast.FunctionExpression functionExpression = function.node; | 8493 ast.FunctionExpression functionExpression = function.node; |
| 8485 weeder.visit(functionExpression.initializers); | 8494 weeder.visit(functionExpression.initializers); |
| 8486 weeder.visit(functionExpression.body); | 8495 weeder.visit(functionExpression.body); |
| 8487 weeder.visit(functionExpression.asyncModifier); | 8496 weeder.visit(functionExpression.asyncModifier); |
| 8488 return !weeder.tooDifficult; | 8497 return !weeder.tooDifficult; |
| 8489 } | 8498 } |
| 8490 | 8499 |
| 8491 bool registerNode() { | 8500 bool registerNode() { |
| 8492 if (!useMaxInliningNodes) return true; | 8501 if (!useMaxInliningNodes) return true; |
| 8493 if (nodeCount++ > maxInliningNodes) { | 8502 if (nodeCount++ > maxInliningNodes) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 8505 void visitNode(ast.Node node) { | 8514 void visitNode(ast.Node node) { |
| 8506 if (!registerNode()) return; | 8515 if (!registerNode()) return; |
| 8507 if (seenReturn) { | 8516 if (seenReturn) { |
| 8508 tooDifficult = true; | 8517 tooDifficult = true; |
| 8509 } else { | 8518 } else { |
| 8510 node.visitChildren(this); | 8519 node.visitChildren(this); |
| 8511 } | 8520 } |
| 8512 } | 8521 } |
| 8513 | 8522 |
| 8514 @override | 8523 @override |
| 8524 void visitAssert(ast.Assert node) { |
| 8525 if (enableUserAssertions) { |
| 8526 visitNode(node); |
| 8527 } |
| 8528 } |
| 8529 |
| 8530 @override |
| 8515 void visitAsyncModifier(ast.AsyncModifier node) { | 8531 void visitAsyncModifier(ast.AsyncModifier node) { |
| 8516 if (node.isYielding || node.isAsynchronous) { | 8532 if (node.isYielding || node.isAsynchronous) { |
| 8517 tooDifficult = true; | 8533 tooDifficult = true; |
| 8518 } | 8534 } |
| 8519 } | 8535 } |
| 8520 | 8536 |
| 8521 void visitFunctionExpression(ast.Node node) { | 8537 void visitFunctionExpression(ast.Node node) { |
| 8522 if (!registerNode()) return; | 8538 if (!registerNode()) return; |
| 8523 tooDifficult = true; | 8539 tooDifficult = true; |
| 8524 } | 8540 } |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8951 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 8967 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
| 8952 unaliased.accept(this, builder); | 8968 unaliased.accept(this, builder); |
| 8953 } | 8969 } |
| 8954 | 8970 |
| 8955 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 8971 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
| 8956 JavaScriptBackend backend = builder.compiler.backend; | 8972 JavaScriptBackend backend = builder.compiler.backend; |
| 8957 ClassElement cls = backend.findHelper('DynamicRuntimeType'); | 8973 ClassElement cls = backend.findHelper('DynamicRuntimeType'); |
| 8958 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); | 8974 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); |
| 8959 } | 8975 } |
| 8960 } | 8976 } |
| OLD | NEW |