| 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 |