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 |