Index: pkg/compiler/lib/src/cps_ir/type_propagation.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
index 2e2da582d2a10fcb850cac6e2716f41d6258305f..3fed74f20d2da26fde512c1d26b5e69968aba7c9 100644 |
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
@@ -4,8 +4,10 @@ |
import 'optimizers.dart'; |
+import '../closure.dart' show |
+ ClosureClassElement, Identifiers; |
import '../common/names.dart' show |
- Selectors; |
+ Selectors, Identifiers; |
import '../compiler.dart' as dart2js show |
Compiler; |
import '../constants/constant_system.dart'; |
@@ -27,6 +29,7 @@ import '../universe/universe.dart'; |
import '../world.dart' show World; |
import 'cps_fragment.dart'; |
import 'cps_ir_nodes.dart'; |
+import 'cps_ir_nodes_sexpr.dart' show SExpressionStringifier; |
enum AbstractBool { |
True, False, Maybe, Nothing |
@@ -1574,6 +1577,60 @@ class TransformingVisitor extends LeafVisitor { |
return false; |
} |
+ /// Inlines a single-use closure if it leaves the closure object with only |
+ /// field accesses. This is optimized later by [ScalarReplacer]. |
+ bool specializeSingleUseClosureCall(InvokeMethod node) { |
+ Selector call = node.selector; |
+ if (!call.isClosureCall) return false; |
+ |
+ assert(!isInterceptedSelector(call)); |
+ assert(call.argumentCount == node.arguments.length); |
+ |
+ Primitive receiver = node.receiver.definition; |
+ if (receiver is !CreateInstance) return false; |
+ if (!receiver.hasExactlyOneUse) return false; |
+ |
+ ClosureClassElement closureClassElement = receiver.classElement; |
+ Element element = closureClassElement.localLookup(Identifiers.call); |
+ |
+ if (element == null || !element.isFunction) return false; |
+ FunctionElement functionElement = element; |
+ |
+ if (!call.signatureApplies(functionElement)) return false; |
+ // Inline only for exact match. |
+ // TODO(sra): Handle call with defaulted arguments. |
+ Selector targetSelector = new Selector.fromElement(functionElement); |
+ if (call.callStructure != targetSelector.callStructure) return false; |
+ |
+ FunctionDefinition target = |
+ functionCompiler.compileToCpsIR(functionElement); |
+ |
+ // Accesses to closed-over values are field access primitives. We we don't |
+ // inline if there are other uses of 'this' since that could be an escape or |
+ // a recursive call. |
+ for (Reference ref = target.thisParameter.firstRef; |
+ ref != null; |
+ ref = ref.next) { |
+ Node use = ref.parent; |
+ if (use is GetField) continue; |
+ if (use is SetField && ref == use.object) continue; |
+ return false; |
+ } |
+ |
+ // Don't inline if [target] contains try-catch or try-finally. |
+ if (ContainsTry.analyze(target)) return false; |
+ |
+ node.receiver.definition.substituteFor(target.thisParameter); |
+ for (int i = 0; i < node.arguments.length; ++i) { |
+ node.arguments[i].definition.substituteFor(target.parameters[i]); |
+ } |
+ node.continuation.definition.substituteFor(target.returnContinuation); |
+ |
+ replaceSubtree(node, target.body); |
+ push(target.body); |
+ return true; |
+ } |
+ |
/// Side-effect free expressions with constant results are be replaced by: |
/// |
/// (LetPrim p = constant (InvokeContinuation k p)). |
@@ -1598,6 +1655,7 @@ class TransformingVisitor extends LeafVisitor { |
if (specializeFieldAccess(node)) return; |
if (specializeIndexableAccess(node)) return; |
if (specializeArrayAccess(node)) return; |
+ if (specializeSingleUseClosureCall(node)) return; |
if (specializeClosureCall(node)) return; |
AbstractValue receiver = getValue(node.receiver.definition); |
@@ -2751,3 +2809,25 @@ class ResetAnalysisInfo extends RecursiveVisitor { |
values.remove(node.variable); |
} |
} |
+ |
+ |
+class ContainsTry extends RecursiveVisitor { |
+ bool _found = false; |
+ ContainsTry._(); |
+ |
+ /// Scans [root] for evidence of try-catch and try-finally. |
+ static bool analyze(Node root) { |
+ ContainsTry visitor = new ContainsTry._(); |
+ visitor.visit(root); |
+ return visitor._found; |
+ } |
+ |
+ visit(Node node) { |
+ if (_found) return; // Early exit if we know the answer. |
+ super.visit(node); |
+ } |
+ |
+ processLetHandler(LetHandler node) { |
+ _found = true; |
+ } |
+} |