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

Unified Diff: pkg/compiler/lib/src/cps_ir/let_sinking.dart

Issue 1238163003: dart2js cps: Share interceptors by default and propagate to use later. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Renamed to let_sinking.dart Created 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart ('k') | pkg/compiler/lib/src/cps_ir/optimizers.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/cps_ir/let_sinking.dart
diff --git a/pkg/compiler/lib/src/cps_ir/let_sinking.dart b/pkg/compiler/lib/src/cps_ir/let_sinking.dart
new file mode 100644
index 0000000000000000000000000000000000000000..c7f2c214d48c14cf6d16fe68e769c0ca124c8179
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/let_sinking.dart
@@ -0,0 +1,243 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.cps_ir.let_sinking;
+
+import 'cps_ir_nodes.dart';
+import 'optimizers.dart';
+
+/// Sinks single-use primitives to the use when this is safe and profitable.
+///
+/// To avoid sinking non-constant primitives into loops, this pass performs a
+/// control-flow analysis to determine the effective nesting of loops.
+///
+/// In the example below, the value 'p' can be sunk to its use site in the
+/// 'else' branch because that branch is not effectively part of a loop,
+/// despite being lexically nested in a recursive continuation.
+///
+/// let prim p = getInterceptor(<something>)
+/// let rec kont x =
+/// if (<loop condition>)
+/// <loop body>
+/// InvokeContinuation kont x'
+/// else
+/// <after loop>
+/// return p.foo()
+///
+class LetSinker extends RecursiveVisitor implements Pass {
+ String get passName => 'Let sinking';
+
+ LoopHierarchy loopHierarchy;
+ List<Continuation> stack = <Continuation>[];
+ Set<LetPrim> sunkNodes = new Set<LetPrim>();
+
+ void rewrite(FunctionDefinition node) {
+ new ParentVisitor().visit(node);
+ loopHierarchy = new LoopHierarchy(node);
+ visit(node.body);
+ }
+
+ void visitLetPrim(LetPrim node) {
+ // Visit the body, wherein this primitive may be sunk to its use site.
+ visit(node.body);
+
+ if (node.primitive != null) {
+ // The primitive could not be sunk. Sink dependencies to this location.
+ visit(node.primitive);
+ } else {
+ // The primitive was sunk. Destroy the old LetPrim.
+ InteriorNode parent = node.parent;
+ parent.body = node.body;
+ node.body.parent = parent;
+ }
+ }
+
+ void processReference(Reference ref) {
+ Definition definition = ref.definition;
+ if (definition is Primitive &&
+ definition is! Parameter &&
+ definition.hasExactlyOneUse &&
+ definition.isSafeForReordering) {
+ // Check if use is in the same loop.
+ LetPrim binding = definition.parent;
+ Continuation bindingLoop = loopHierarchy.getLoopHeader(binding);
+ Expression use = getEnclosingExpression(ref.parent);
+ Continuation useLoop = loopHierarchy.getLoopHeader(use);
+ if (bindingLoop == useLoop || definition is Constant) {
+ // Sink the definition.
+
+ binding.primitive = null; // Mark old binding for deletion.
+ LetPrim newBinding = new LetPrim(definition);
+ definition.parent = newBinding;
+ InteriorNode useParent = use.parent;
+ useParent.body = newBinding;
+ newBinding.body = use;
+ use.parent = newBinding;
+ newBinding.parent = useParent;
+
+ // Now that the final binding location has been found, sink the
+ // dependencies of the definition down here as well.
+ visit(definition);
+ }
+ }
+ }
+
+ Expression getEnclosingExpression(Node node) {
+ while (node is! Expression) {
+ node = node.parent;
+ }
+ return node;
+ }
+}
+
+/// Determines the effective nesting of loops.
+///
+/// The effective nesting of loops is different from the lexical nesting, since
+/// recursive continuations can generally contain all the code following
+/// after the loop in addition to the looping code itself.
+///
+/// For example, the 'else' branch below is not effectively part of the loop:
+///
+/// let rec kont x =
+/// if (<loop condition>)
+/// <loop body>
+/// InvokeContinuation kont x'
+/// else
+/// <after loop>
+/// return p.foo()
+///
+/// We use the term "loop" to mean recursive continuation.
+/// The `null` value is used to represent a context not part of any loop.
+class LoopHierarchy {
+ /// Nesting depth of the given loop.
+ Map<Continuation, int> loopDepth = <Continuation, int>{};
+
+ /// The innermost loop (other than itself) that may be invoked recursively
+ /// as a result of invoking the given continuation.
+ Map<Continuation, Continuation> loopTarget = <Continuation, Continuation>{};
+
+ /// Current nesting depth.
+ int currentDepth = 0;
+
+ /// Computes the loop hierarchy for the given function.
+ ///
+ /// Parent pointers must be computed for [node].
+ LoopHierarchy(FunctionDefinition node) {
+ _processBlock(node.body, null);
+ }
+
+ /// Returns the innermost loop which [node] is effectively part of.
+ Continuation getLoopHeader(Expression exp) {
+ Node node = exp.parent;
+ while (node != null && node is! Continuation) {
+ node = node.parent;
+ }
+ if (node is Continuation) {
+ if (node.isRecursive) {
+ return node;
+ } else {
+ return loopTarget[node];
+ }
+ }
+ return null;
+ }
+
+ /// Marks the innermost loop as a subloop of the other loop.
+ ///
+ /// Returns the innermost loop.
+ ///
+ /// Both continuations, [c1] and [c2] may be null (i.e. no loop).
+ ///
+ /// A loop is said to be a subloop of an enclosing loop if it can invoke
+ /// that loop recursively. This information is stored in [loopTarget].
+ ///
+ /// This method is only invoked with two distinct loops if there is a
+ /// point that can reach a recursive invocation of both loops.
+ /// This implies that one loop is nested in the other, because they must
+ /// both be in scope at that point.
+ Continuation _markInnerLoop(Continuation c1, Continuation c2) {
+ assert(c1 == null || c1.isRecursive);
+ assert(c2 == null || c2.isRecursive);
+ if (c1 == null) return c2;
+ if (c2 == null) return c1;
+ if (c1 == c2) return c1;
+ if (loopDepth[c1] > loopDepth[c2]) {
+ loopTarget[c1] = _markInnerLoop(loopTarget[c1], c2);
+ return c1;
+ } else {
+ loopTarget[c2] = _markInnerLoop(loopTarget[c2], c1);
+ return c2;
+ }
+ }
+
+ /// Analyzes the body of [cont] and returns the innermost loop
+ /// that can be invoked recursively from [cont] (other than [cont] itself).
+ ///
+ /// [catchLoop] is the innermost loop that can be invoked recursively
+ /// from the current exception handler.
+ Continuation _processContinuation(Continuation cont, Continuation catchLoop) {
+ if (cont.isRecursive) {
+ ++currentDepth;
+ loopDepth[cont] = currentDepth;
+ Continuation target = _processBlock(cont.body, catchLoop);
+ _markInnerLoop(loopTarget[cont], target);
+ --currentDepth;
+ } else {
+ loopTarget[cont] = _processBlock(cont.body, catchLoop);
+ }
+ return loopTarget[cont];
+ }
+
+ bool _isCallContinuation(Continuation cont) {
+ return cont.hasExactlyOneUse && cont.firstRef.parent is CallExpression;
+ }
+
+ /// Analyzes a basic block and returns the innermost loop that
+ /// can be invoked recursively from that block.
+ Continuation _processBlock(Expression node, Continuation catchLoop) {
+ List<Continuation> callContinuations = <Continuation>[];
+ for (; node is! TailExpression; node = node.next) {
+ if (node is LetCont) {
+ for (Continuation cont in node.continuations) {
+ if (!_isCallContinuation(cont)) {
+ // Process non-call continuations at the binding site, so they
+ // their loop target is known at all use sites.
+ _processContinuation(cont, catchLoop);
+ } else {
+ // To avoid deep recursion, do not analyze call continuations
+ // recursively. This basic block traversal steps into the
+ // call contiunation after visiting its use site. We store the
+ // continuations in a list so we can set the loop target once
+ // it is known.
+ callContinuations.add(cont);
+ }
+ }
+ } else if (node is LetHandler) {
+ catchLoop = _processContinuation(node.handler, catchLoop);
+ }
+ }
+ Continuation target;
+ if (node is InvokeContinuation) {
+ if (node.isRecursive) {
+ target = node.continuation.definition;
+ } else {
+ target = loopTarget[node.continuation.definition];
+ }
+ } else if (node is Branch) {
+ target = _markInnerLoop(
+ loopTarget[node.trueContinuation.definition],
+ loopTarget[node.falseContinuation.definition]);
+ } else {
+ assert(node is Unreachable || node is Throw);
+ }
+ target = _markInnerLoop(target, catchLoop);
+ for (Continuation cont in callContinuations) {
+ // Store the loop target on each call continuation in the basic block.
+ // Because we walk over call continuations as part of the basic block
+ // traversal, these do not get their loop target set otherwise.
+ loopTarget[cont] = target;
+ }
+ return target;
+ }
+}
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart ('k') | pkg/compiler/lib/src/cps_ir/optimizers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698