| 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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 var capturedScope = 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); |
| 96 _model.scopeInfo = _scopesCapturedInClosureMap[node] = capturedScope; | 92 _model.scopeInfo = _scopesCapturedInClosureMap[node] = capturedScope; |
| 97 } | 93 } |
| 98 } | 94 } |
| 99 | 95 |
| 100 /// Generate a unique name for the [_boxCounter]th box field. | 96 /// Generate a unique name for the [_boxCounter]th box field. |
| 101 /// | 97 /// |
| 102 /// The result is used as the name of [NodeBox]s and [BoxLocal]s, and must | 98 /// The result is used as the name of [NodeBox]s and [BoxLocal]s, and must |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 _markVariableAsUsed(node.variable); | 144 _markVariableAsUsed(node.variable); |
| 149 } | 145 } |
| 150 | 146 |
| 151 @override | 147 @override |
| 152 visitVariableSet(ir.VariableSet node) { | 148 visitVariableSet(ir.VariableSet node) { |
| 153 _mutatedVariables.add(node.variable); | 149 _mutatedVariables.add(node.variable); |
| 154 _markVariableAsUsed(node.variable); | 150 _markVariableAsUsed(node.variable); |
| 155 node.visitChildren(this); | 151 node.visitChildren(this); |
| 156 } | 152 } |
| 157 | 153 |
| 154 @override |
| 155 visitVariableDeclaration(ir.VariableDeclaration declaration) { |
| 156 if (!declaration.isFieldFormal) { |
| 157 _scopeVariables.add(declaration); |
| 158 } |
| 159 |
| 160 declaration.visitChildren(this); |
| 161 } |
| 162 |
| 158 /// Add this variable to the set of free variables if appropriate and add to | 163 /// Add this variable to the set of free variables if appropriate and add to |
| 159 /// the tally of variables used in try or sync blocks. | 164 /// the tally of variables used in try or sync blocks. |
| 160 void _markVariableAsUsed(ir.VariableDeclaration variable) { | 165 void _markVariableAsUsed(ir.VariableDeclaration variable) { |
| 161 if (_isInsideClosure && !_inCurrentContext(variable)) { | 166 if (_isInsideClosure && !_inCurrentContext(variable)) { |
| 162 // If the element is not declared in the current function and the element | 167 // If the element is not declared in the current function and the element |
| 163 // is not the closure itself we need to mark the element as free variable. | 168 // is not the closure itself we need to mark the element as free variable. |
| 164 // Note that the check on [insideClosure] is not just an | 169 // Note that the check on [insideClosure] is not just an |
| 165 // optimization: factories have type parameters as function | 170 // optimization: factories have type parameters as function |
| 166 // parameters, and type parameters are declared in the class, not | 171 // parameters, and type parameters are declared in the class, not |
| 167 // the factory. | 172 // the factory. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 boxedLoopVariables.add(variable); | 212 boxedLoopVariables.add(variable); |
| 208 } | 213 } |
| 209 } | 214 } |
| 210 }); | 215 }); |
| 211 KernelCapturedScope scope = _scopesCapturedInClosureMap[node]; | 216 KernelCapturedScope scope = _scopesCapturedInClosureMap[node]; |
| 212 if (scope == null) return; | 217 if (scope == null) return; |
| 213 _scopesCapturedInClosureMap[node] = new KernelCapturedLoopScope( | 218 _scopesCapturedInClosureMap[node] = new KernelCapturedLoopScope( |
| 214 scope.boxedVariables, | 219 scope.boxedVariables, |
| 215 scope.capturedVariablesAccessor, | 220 scope.capturedVariablesAccessor, |
| 216 boxedLoopVariables, | 221 boxedLoopVariables, |
| 217 scope.context, | |
| 218 scope.localsUsedInTryOrSync, | 222 scope.localsUsedInTryOrSync, |
| 219 scope.freeVariables, | 223 scope.freeVariables, |
| 220 scope.hasThisLocal); | 224 scope.hasThisLocal); |
| 221 } | 225 } |
| 222 | 226 |
| 223 void visitInvokable(ir.TreeNode node) { | 227 void visitInvokable(ir.TreeNode node) { |
| 224 assert(node is ir.Member || | 228 assert(node is ir.Member || |
| 225 node is ir.FunctionExpression || | 229 node is ir.FunctionExpression || |
| 226 node is ir.FunctionDeclaration); | 230 node is ir.FunctionDeclaration); |
| 227 bool oldIsInsideClosure = _isInsideClosure; | 231 bool oldIsInsideClosure = _isInsideClosure; |
| 228 ir.TreeNode oldExecutableContext = _executableContext; | 232 ir.TreeNode oldExecutableContext = _executableContext; |
| 229 KernelScopeInfo oldScopeInfo = _currentScopeInfo; | 233 KernelScopeInfo oldScopeInfo = _currentScopeInfo; |
| 230 ir.TreeNode oldLocalFunction = _currentLocalFunction; | |
| 231 | 234 |
| 232 // _outermostNode is only null the first time we enter the body of the | 235 // _outermostNode is only null the first time we enter the body of the |
| 233 // field, constructor, or method that is being analyzed. | 236 // field, constructor, or method that is being analyzed. |
| 234 _isInsideClosure = _outermostNode != null; | 237 _isInsideClosure = _outermostNode != null; |
| 235 _executableContext = node; | 238 _executableContext = node; |
| 236 | 239 |
| 237 _currentScopeInfo = new KernelScopeInfo(_hasThisLocal); | 240 _currentScopeInfo = new KernelScopeInfo(_hasThisLocal); |
| 238 if (_isInsideClosure) { | 241 if (_isInsideClosure) { |
| 239 _closuresToGenerate[node] = _currentScopeInfo; | 242 _closuresToGenerate[node] = _currentScopeInfo; |
| 240 _currentLocalFunction = node.parent; | |
| 241 } else { | 243 } else { |
| 242 _outermostNode = node; | 244 _outermostNode = node; |
| 243 } | 245 } |
| 244 _model.scopeInfo = _currentScopeInfo; | 246 _model.scopeInfo = _currentScopeInfo; |
| 245 | 247 |
| 246 enterNewScope(node, () { | 248 enterNewScope(node, () { |
| 247 node.visitChildren(this); | 249 node.visitChildren(this); |
| 248 }); | 250 }); |
| 249 | 251 |
| 250 KernelScopeInfo savedScopeInfo = _currentScopeInfo; | 252 KernelScopeInfo savedScopeInfo = _currentScopeInfo; |
| 251 bool savedIsInsideClosure = _isInsideClosure; | 253 bool savedIsInsideClosure = _isInsideClosure; |
| 252 | 254 |
| 253 // Restore old values. | 255 // Restore old values. |
| 254 _isInsideClosure = oldIsInsideClosure; | 256 _isInsideClosure = oldIsInsideClosure; |
| 255 _currentScopeInfo = oldScopeInfo; | 257 _currentScopeInfo = oldScopeInfo; |
| 256 _executableContext = oldExecutableContext; | 258 _executableContext = oldExecutableContext; |
| 257 _currentLocalFunction = oldLocalFunction; | |
| 258 | 259 |
| 259 // Mark all free variables as captured and expect to encounter them in the | 260 // Mark all free variables as captured and expect to encounter them in the |
| 260 // outer function. | 261 // outer function. |
| 261 Iterable<ir.VariableDeclaration> freeVariables = | 262 Iterable<ir.VariableDeclaration> freeVariables = |
| 262 savedScopeInfo.freeVariables; | 263 savedScopeInfo.freeVariables; |
| 263 assert(freeVariables.isEmpty || savedIsInsideClosure); | 264 assert(freeVariables.isEmpty || savedIsInsideClosure); |
| 264 for (ir.VariableDeclaration freeVariable in freeVariables) { | 265 for (ir.VariableDeclaration freeVariable in freeVariables) { |
| 265 _capturedVariables.add(freeVariable); | 266 _capturedVariables.add(freeVariable); |
| 266 _markVariableAsUsed(freeVariable); | 267 _markVariableAsUsed(freeVariable); |
| 267 } | 268 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 295 @override | 296 @override |
| 296 void visitFunctionExpression(ir.FunctionExpression functionExpression) { | 297 void visitFunctionExpression(ir.FunctionExpression functionExpression) { |
| 297 visitInvokable(functionExpression); | 298 visitInvokable(functionExpression); |
| 298 } | 299 } |
| 299 | 300 |
| 300 @override | 301 @override |
| 301 void visitFunctionDeclaration(ir.FunctionDeclaration functionDeclaration) { | 302 void visitFunctionDeclaration(ir.FunctionDeclaration functionDeclaration) { |
| 302 visitInvokable(functionDeclaration); | 303 visitInvokable(functionDeclaration); |
| 303 } | 304 } |
| 304 } | 305 } |
| OLD | NEW |