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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/letsinking.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: Minor fix 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
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.
4
5 library dart2js.cps_ir.let_sinking;
6
7 import 'cps_ir_nodes.dart';
8 import 'optimizers.dart';
9
10 /// Sinks single-use primitives to the use when this is safe and profitable.
11 ///
12 /// To avoid sinking non-constant primitives into loops, this pass performs a
13 /// control-flow analysis to determine the effective nesting of loops, see
14 /// [LoopHierarchy].
floitsch 2015/07/17 17:19:45 I think it's always nice to have an example. (does
asgerf 2015/07/20 09:10:56 Added an example based on the one from LoopHierarc
15 class LetSinker extends RecursiveVisitor implements Pass {
16 String get passName => 'Let sinking';
17
18 LoopHierarchy loopHierarchy;
19 List<Continuation> stack = <Continuation>[];
20 Set<LetPrim> sunkNodes = new Set<LetPrim>();
21
22 void rewrite(FunctionDefinition node) {
23 new ParentVisitor().visit(node);
24 loopHierarchy = new LoopHierarchy(node);
floitsch 2015/07/17 17:19:45 I'm ok this way, but have a *slight* preference to
asgerf 2015/07/20 09:10:56 Acknowledged. I usually do that if the class is c
25 visit(node.body);
26 }
27
28 void visitLetPrim(LetPrim node) {
29 // Visit the body, wherein this primitive may be sunk to its use site.
30 visit(node.body);
31
32 if (node.primitive != null) {
33 // The primitive could not be sunk. Sink dependencies to this location.
34 visit(node.primitive);
35 } else {
36 // The primitive was sunk. Destroy the old LetPrim.
37 InteriorNode parent = node.parent;
38 parent.body = node.body;
39 node.body.parent = parent;
40 }
41 }
42
43 void processReference(Reference ref) {
44 Definition definition = ref.definition;
45 if (definition is Primitive &&
46 definition is! Parameter &&
47 definition.hasExactlyOneUse &&
48 definition.isSafeForReordering) {
49 // Check if use is in the same loop.
50 LetPrim binding = definition.parent;
51 Continuation bindingLoop = loopHierarchy.getLoopHeader(binding);
52 Expression use = getEnclosingExpression(ref.parent);
53 Continuation useLoop = loopHierarchy.getLoopHeader(use);
54 if (bindingLoop == useLoop || definition is Constant) {
55 // Sink the definition.
56
57 binding.primitive = null; // Mark old binding for deletion.
58 LetPrim newBinding = new LetPrim(definition);
59 definition.parent = newBinding;
60 InteriorNode useParent = use.parent;
61 useParent.body = newBinding;
62 newBinding.body = use;
63 use.parent = newBinding;
64 newBinding.parent = useParent;
65
66 // Now that the final binding location has been found, sink the
67 // dependencies of the definition down here as well.
68 visit(definition);
69 }
70 }
71 }
72
73 Expression getEnclosingExpression(Node node) {
74 while (node is! Expression) {
75 node = node.parent;
76 }
77 return node;
78 }
79 }
80
81 /// Determines the effective nesting of loops.
82 ///
83 /// The effective nesting of loops is different from the lexical nesting, since
84 /// recursive continuations can generally contain all the code following
85 /// after the loop in addition to the looping code itself.
86 ///
87 /// For example, the 'else' branch below is not effectively part of the loop:
88 ///
89 /// let rec kont x =
90 /// if (<loop condition>)
91 /// <loop body>
92 /// InvokeContinuation kont x'
93 /// else
94 /// <after loop>
95 /// return p.foo()
96 ///
97 /// We use the term "loop" to mean recursive continuation.
98 /// The `null` value is used to represent a context not part of any loop.
99 class LoopHierarchy {
100 /// Nesting depth of the given loop.
101 Map<Continuation, int> loopDepth = <Continuation, int>{};
102
103 /// The innermost loop (other than itself) that may be invoked recursively
104 /// as a result of invoking the given continuation.
105 Map<Continuation, Continuation> loopTarget = <Continuation, Continuation>{};
106
107 /// Current nesting depth.
108 int currentDepth = 0;
109
110 /// Computes the loop loop hierarchy for the given function.
111 ///
112 /// Parent pointers must be computed for [node].
113 LoopHierarchy(FunctionDefinition node) {
114 _processBlock(node.body, null);
115 }
116
117 /// Returns the innermost loop which [node] is effectively part of.
118 Continuation getLoopHeader(Expression exp) {
119 Node node = exp.parent;
120 while (node != null && node is! Continuation) {
121 node = node.parent;
122 }
123 if (node is Continuation) {
124 if (node.isRecursive)
floitsch 2015/07/17 17:19:45 multi-line ifs should have {}
asgerf 2015/07/20 09:10:56 Done.
125 return node;
126 else
127 return loopTarget[node];
128 }
129 return null;
130 }
131
132 /// Returns the innermost of two loops and marks its as being
133 /// a subloop in the other loop.
134 ///
135 /// A loop is said to be a subloop of an enclosing loop if it can invoke
136 /// that loop recursively. This information is stored in [loopTarget].
137 ///
138 /// This method is only invoked with two distinct loops if there is a
139 /// point that can reach a recursive invocation of both loops.
140 /// This implies that one loop is nested in the other, because they must
141 /// both be in scope at that point.
142 Continuation _determineInnerLoop(Continuation c1, Continuation c2) {
floitsch 2015/07/17 17:19:45 The main-goal of this function is to mark nesting,
asgerf 2015/07/20 09:10:56 Done.
143 assert(c1 == null || c1.isRecursive);
144 assert(c2 == null || c2.isRecursive);
145 if (c1 == null) return c2;
146 if (c2 == null) return c1;
147 if (c1 == c2) return c1;
148 if (loopDepth[c1] > loopDepth[c2]) {
149 loopTarget[c1] = _determineInnerLoop(loopTarget[c1], c2);
150 return c1;
151 } else {
152 loopTarget[c2] = _determineInnerLoop(loopTarget[c2], c1);
153 return c2;
154 }
155 }
156
157 /// Analyzes the body of [cont] and returns the innermost loop
158 /// that can be invoked recursively can be invoked from [cont]
floitsch 2015/07/17 17:19:45 -can be invoked-
asgerf 2015/07/20 09:10:56 Done.
159 /// (other than [cont] itself).
160 ///
161 /// [catchLoop] is the innermost loop that can be invoked recursively
162 /// from the current exception handler.
163 Continuation _processContinuation(Continuation cont, Continuation catchLoop) {
164 if (cont.isRecursive) {
165 ++currentDepth;
166 loopDepth[cont] = currentDepth;
167 Continuation target = _processBlock(cont.body, catchLoop);
168 _determineInnerLoop(loopTarget[cont], target);
169 --currentDepth;
170 } else {
171 loopTarget[cont] = _processBlock(cont.body, catchLoop);
172 }
173 return loopTarget[cont];
174 }
175
176 bool _isCallContinuation(Continuation cont) {
177 return cont.hasExactlyOneUse && cont.firstRef.parent is CallExpression;
178 }
179
180 /// Analyzes a basic block and returns the innermost loop that
181 /// can be invoked recursively from that block.
182 Continuation _processBlock(Expression node, Continuation catchLoop) {
183 List<Continuation> callContinuations = <Continuation>[];
184 for (; node is! TailExpression; node = node.next) {
185 if (node is LetCont) {
186 for (Continuation cont in node.continuations) {
187 // Do not process call continuations at the binding site.
188 // We step into call continuations as part of the same basic block.
floitsch 2015/07/17 17:19:45 I don't understand this comment.
asgerf 2015/07/20 09:10:56 Refactored code and comment. The "is CallExpressi
189 if (!_isCallContinuation(cont)) {
190 _processContinuation(cont, catchLoop);
191 }
192 }
193 } else if (node is CallExpression) {
194 callContinuations.add(node.continuation.definition);
195 } else if (node is LetHandler) {
196 catchLoop = _processContinuation(node.handler, catchLoop);
197 }
198 }
199 Continuation target;
200 if (node is InvokeContinuation) {
201 if (node.isRecursive) {
202 target = node.continuation.definition;
203 } else {
204 target = loopTarget[node.continuation.definition];
205 }
206 } else if (node is Branch) {
207 target = _determineInnerLoop(
208 loopTarget[node.trueContinuation.definition],
209 loopTarget[node.falseContinuation.definition]);
210 } else {
211 assert(node is Unreachable || node is Throw);
212 }
213 target = _determineInnerLoop(target, catchLoop);
214 for (Continuation cont in callContinuations) {
215 // Store the loop target on each call continuation in the basic block.
216 // Because we walk over call continuations as part of the basic block
217 // traversal, these do not get their loop target set by otherwise.
floitsch 2015/07/17 17:19:45 -by-
asgerf 2015/07/20 09:10:56 Done.
218 loopTarget[cont] = target;
219 }
220 return target;
221 }
222 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698