OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
6 | 6 |
7 import '../closure.dart'; | 7 import '../closure.dart'; |
8 import 'closure.dart'; | 8 import 'closure.dart'; |
9 | 9 |
10 /// This builder walks the code to determine what variables are captured/free at | 10 /// This builder walks the code to determine what variables are captured/free at |
11 /// various points to build CapturedScope that can respond to queries | 11 /// various points to build CapturedScope that can respond to queries |
12 /// about how a particular variable is being used at any point in the code. | 12 /// about how a particular variable is being used at any point in the code. |
13 class CapturedScopeBuilder extends ir.Visitor { | 13 class CapturedScopeBuilder extends ir.Visitor { |
14 ir.TreeNode _currentLocalFunction; | |
15 | |
16 ScopeModel _model; | 14 ScopeModel _model; |
17 | 15 |
18 /// A map of each visited call node with the associated information about what | 16 /// A map of each visited call node with the associated information about what |
19 /// variables are captured/used. Each ir.Node key corresponds to a scope that | 17 /// variables are captured/used. Each ir.Node key corresponds to a scope that |
20 /// was encountered while visiting a closure (initially called through | 18 /// was encountered while visiting a closure (initially called through |
21 /// [translateLazyIntializer] or [translateConstructorOrProcedure]). | 19 /// [translateLazyIntializer] or [translateConstructorOrProcedure]). |
22 Map<ir.Node, KernelCapturedScope> get _scopesCapturedInClosureMap => | 20 Map<ir.Node, KernelCapturedScope> get _scopesCapturedInClosureMap => |
23 _model.capturedScopesMap; | 21 _model.capturedScopesMap; |
24 | 22 |
25 /// A map of the nodes that we have flagged as necessary to generate closure | 23 /// A map of the nodes that we have flagged as necessary to generate closure |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 | 61 |
64 /// Keeps track of the number of boxes that we've created so that they each | 62 /// Keeps track of the number of boxes that we've created so that they each |
65 /// have unique names. | 63 /// have unique names. |
66 int _boxCounter = 0; | 64 int _boxCounter = 0; |
67 | 65 |
68 CapturedScopeBuilder(this._model, {bool hasThisLocal}) | 66 CapturedScopeBuilder(this._model, {bool hasThisLocal}) |
69 : this._hasThisLocal = hasThisLocal; | 67 : this._hasThisLocal = hasThisLocal; |
70 | 68 |
71 /// Update the [CapturedScope] object corresponding to | 69 /// Update the [CapturedScope] object corresponding to |
72 /// this node if any variables are captured. | 70 /// this node if any variables are captured. |
73 void attachCapturedScopeVariables(ir.Node node) { | 71 void attachCapturedScopeVariables(ir.TreeNode node) { |
74 Set<ir.VariableDeclaration> capturedVariablesForScope = | 72 Set<ir.VariableDeclaration> capturedVariablesForScope = |
75 new Set<ir.VariableDeclaration>(); | 73 new Set<ir.VariableDeclaration>(); |
76 | 74 |
77 for (ir.VariableDeclaration variable in _scopeVariables) { | 75 for (ir.VariableDeclaration variable in _scopeVariables) { |
78 // No need to box non-assignable elements. | 76 // No need to box non-assignable elements. |
79 if (variable.isFinal || variable.isConst) continue; | 77 if (variable.isFinal || variable.isConst) continue; |
80 if (!_mutatedVariables.contains(variable)) continue; | 78 if (!_mutatedVariables.contains(variable)) continue; |
81 if (_capturedVariables.contains(variable)) { | 79 if (_capturedVariables.contains(variable)) { |
82 capturedVariablesForScope.add(variable); | 80 capturedVariablesForScope.add(variable); |
83 } | 81 } |
84 } | 82 } |
85 if (!capturedVariablesForScope.isEmpty) { | 83 if (!capturedVariablesForScope.isEmpty) { |
86 assert(_model.scopeInfo != null); | 84 assert(_model.scopeInfo != null); |
87 assert(_currentLocalFunction != null); | |
88 KernelScopeInfo from = _model.scopeInfo; | 85 KernelScopeInfo from = _model.scopeInfo; |
89 _scopesCapturedInClosureMap[node] = new KernelCapturedScope( | 86 var capturedScope = new KernelCapturedScope( |
90 capturedVariablesForScope, | 87 capturedVariablesForScope, |
91 new NodeBox(getBoxName(), _executableContext), | 88 new NodeBox(getBoxName(), _executableContext), |
92 _currentLocalFunction, | |
93 from.localsUsedInTryOrSync, | 89 from.localsUsedInTryOrSync, |
94 from.freeVariables, | 90 from.freeVariables, |
95 _hasThisLocal); | 91 _hasThisLocal); |
| 92 _model.scopeInfo = |
| 93 _scopesCapturedInClosureMap[node.parent] = capturedScope; |
| 94 _currentScopeInfo.capturedScopes.add(node.parent); |
| 95 print( |
| 96 'FUUUUUUUUUUUUUUUUUUU ${node.parent} ${_executableContext.parent} $_cu
rrentScopeInfo'); |
96 } | 97 } |
97 } | 98 } |
98 | 99 |
99 /// Generate a unique name for the [_boxCounter]th box field. | 100 /// Generate a unique name for the [_boxCounter]th box field. |
100 /// | 101 /// |
101 /// The result is used as the name of [NodeBox]s and [BoxLocal]s, and must | 102 /// The result is used as the name of [NodeBox]s and [BoxLocal]s, and must |
102 /// therefore be unique to avoid breaking an invariant in the element model | 103 /// therefore be unique to avoid breaking an invariant in the element model |
103 /// (classes cannot declare multiple fields with the same name). | 104 /// (classes cannot declare multiple fields with the same name). |
104 /// | 105 /// |
105 /// Also, the names should be distinct from real field names to prevent | 106 /// Also, the names should be distinct from real field names to prevent |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 _markVariableAsUsed(node.variable); | 148 _markVariableAsUsed(node.variable); |
148 } | 149 } |
149 | 150 |
150 @override | 151 @override |
151 visitVariableSet(ir.VariableSet node) { | 152 visitVariableSet(ir.VariableSet node) { |
152 _mutatedVariables.add(node.variable); | 153 _mutatedVariables.add(node.variable); |
153 _markVariableAsUsed(node.variable); | 154 _markVariableAsUsed(node.variable); |
154 node.visitChildren(this); | 155 node.visitChildren(this); |
155 } | 156 } |
156 | 157 |
| 158 @override |
| 159 visitVariableDeclaration(ir.VariableDeclaration declaration) { |
| 160 if (!declaration.isFieldFormal) { |
| 161 _scopeVariables.add(declaration); |
| 162 } |
| 163 |
| 164 if (declaration.initializer != null) { |
| 165 declaration.initializer.accept(this); |
| 166 } |
| 167 } |
| 168 |
157 /// Add this variable to the set of free variables if appropriate and add to | 169 /// Add this variable to the set of free variables if appropriate and add to |
158 /// the tally of variables used in try or sync blocks. | 170 /// the tally of variables used in try or sync blocks. |
159 void _markVariableAsUsed(ir.VariableDeclaration variable) { | 171 void _markVariableAsUsed(ir.VariableDeclaration variable) { |
160 if (_isInsideClosure && !_inCurrentContext(variable)) { | 172 if (_isInsideClosure && !_inCurrentContext(variable)) { |
161 // If the element is not declared in the current function and the element | 173 // If the element is not declared in the current function and the element |
162 // is not the closure itself we need to mark the element as free variable. | 174 // is not the closure itself we need to mark the element as free variable. |
163 // Note that the check on [insideClosure] is not just an | 175 // Note that the check on [insideClosure] is not just an |
164 // optimization: factories have type parameters as function | 176 // optimization: factories have type parameters as function |
165 // parameters, and type parameters are declared in the class, not | 177 // parameters, and type parameters are declared in the class, not |
166 // the factory. | 178 // the factory. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 boxedLoopVariables.add(variable); | 218 boxedLoopVariables.add(variable); |
207 } | 219 } |
208 } | 220 } |
209 }); | 221 }); |
210 KernelCapturedScope scope = _scopesCapturedInClosureMap[node]; | 222 KernelCapturedScope scope = _scopesCapturedInClosureMap[node]; |
211 if (scope == null) return; | 223 if (scope == null) return; |
212 _scopesCapturedInClosureMap[node] = new KernelCapturedLoopScope( | 224 _scopesCapturedInClosureMap[node] = new KernelCapturedLoopScope( |
213 scope.boxedVariables, | 225 scope.boxedVariables, |
214 scope.capturedVariablesAccessor, | 226 scope.capturedVariablesAccessor, |
215 boxedLoopVariables, | 227 boxedLoopVariables, |
216 scope.context, | |
217 scope.localsUsedInTryOrSync, | 228 scope.localsUsedInTryOrSync, |
218 scope.freeVariables, | 229 scope.freeVariables, |
219 scope.hasThisLocal); | 230 scope.hasThisLocal); |
220 } | 231 } |
221 | 232 |
222 void visitInvokable(ir.TreeNode node) { | 233 void visitInvokable(ir.TreeNode node) { |
223 bool oldIsInsideClosure = _isInsideClosure; | 234 bool oldIsInsideClosure = _isInsideClosure; |
224 ir.TreeNode oldExecutableContext = _executableContext; | 235 ir.TreeNode oldExecutableContext = _executableContext; |
225 KernelScopeInfo oldScopeInfo = _currentScopeInfo; | 236 KernelScopeInfo oldScopeInfo = _currentScopeInfo; |
226 ir.TreeNode oldLocalFunction = _currentLocalFunction; | |
227 | 237 |
228 // _outermostNode is only null the first time we enter the body of the | 238 // _outermostNode is only null the first time we enter the body of the |
229 // field, constructor, or method that is being analyzed. | 239 // field, constructor, or method that is being analyzed. |
230 _isInsideClosure = _outermostNode != null; | 240 _isInsideClosure = _outermostNode != null; |
231 _executableContext = node; | 241 _executableContext = node; |
232 | 242 |
233 _currentScopeInfo = new KernelScopeInfo(_hasThisLocal); | 243 _currentScopeInfo = new KernelScopeInfo(_hasThisLocal); |
234 if (_isInsideClosure) { | 244 if (_isInsideClosure) { |
235 _closuresToGenerate[node] = _currentScopeInfo; | 245 _closuresToGenerate[node] = _currentScopeInfo; |
236 _currentLocalFunction = node.parent; | 246 print("EEEEEEEEEEEEEEEeee $_currentScopeInfo"); |
237 } else { | 247 } else { |
238 _outermostNode = node; | 248 _outermostNode = node; |
239 _model.scopeInfo = _currentScopeInfo; | |
240 } | 249 } |
| 250 _model.scopeInfo = _currentScopeInfo; |
241 | 251 |
242 enterNewScope(node, () { | 252 enterNewScope(node, () { |
243 node.visitChildren(this); | 253 node.visitChildren(this); |
244 }); | 254 }); |
245 | 255 |
246 KernelScopeInfo savedScopeInfo = _currentScopeInfo; | 256 KernelScopeInfo savedScopeInfo = _currentScopeInfo; |
247 bool savedIsInsideClosure = _isInsideClosure; | 257 bool savedIsInsideClosure = _isInsideClosure; |
248 | 258 |
249 // Restore old values. | 259 // Restore old values. |
250 _isInsideClosure = oldIsInsideClosure; | 260 _isInsideClosure = oldIsInsideClosure; |
251 _currentScopeInfo = oldScopeInfo; | 261 _currentScopeInfo = oldScopeInfo; |
252 _executableContext = oldExecutableContext; | 262 _executableContext = oldExecutableContext; |
253 _currentLocalFunction = oldLocalFunction; | |
254 | 263 |
255 // Mark all free variables as captured and expect to encounter them in the | 264 // Mark all free variables as captured and expect to encounter them in the |
256 // outer function. | 265 // outer function. |
257 Iterable<ir.VariableDeclaration> freeVariables = | 266 Iterable<ir.VariableDeclaration> freeVariables = |
258 savedScopeInfo.freeVariables; | 267 savedScopeInfo.freeVariables; |
259 assert(freeVariables.isEmpty || savedIsInsideClosure); | 268 assert(freeVariables.isEmpty || savedIsInsideClosure); |
260 for (ir.VariableDeclaration freeVariable in freeVariables) { | 269 for (ir.VariableDeclaration freeVariable in freeVariables) { |
261 _capturedVariables.add(freeVariable); | 270 _capturedVariables.add(freeVariable); |
262 _markVariableAsUsed(freeVariable); | 271 _markVariableAsUsed(freeVariable); |
263 } | 272 } |
(...skipping 14 matching lines...) Expand all Loading... |
278 } | 287 } |
279 | 288 |
280 void translateConstructorOrProcedure(ir.Node constructorOrProcedure) { | 289 void translateConstructorOrProcedure(ir.Node constructorOrProcedure) { |
281 constructorOrProcedure.accept(this); | 290 constructorOrProcedure.accept(this); |
282 } | 291 } |
283 | 292 |
284 void visitFunctionNode(ir.FunctionNode functionNode) { | 293 void visitFunctionNode(ir.FunctionNode functionNode) { |
285 visitInvokable(functionNode); | 294 visitInvokable(functionNode); |
286 } | 295 } |
287 } | 296 } |
OLD | NEW |