Chromium Code Reviews| Index: pkg/compiler/lib/src/js_model/closure_visitors.dart |
| diff --git a/pkg/compiler/lib/src/js_model/closure_visitors.dart b/pkg/compiler/lib/src/js_model/closure_visitors.dart |
| index d5e291b10098c7d615295ecf0268fa994d9a02c3..0447a7d07b7f25d339f87ecc57fe5b639148bc2f 100644 |
| --- a/pkg/compiler/lib/src/js_model/closure_visitors.dart |
| +++ b/pkg/compiler/lib/src/js_model/closure_visitors.dart |
| @@ -34,7 +34,7 @@ class CapturedScopeBuilder extends ir.Visitor { |
| /// Pointer to the context in which this closure is executed. |
| /// For example, in the expression `var foo = () => 3 + i;`, the executable |
| /// context as we walk the nodes in that expression is the ir.Field `foo`. |
| - ir.Node _executableContext; |
| + ir.TreeNode _executableContext; |
| /// A flag to indicate if we are currently inside a closure. |
| bool _isInsideClosure = false; |
| @@ -61,6 +61,10 @@ class CapturedScopeBuilder extends ir.Visitor { |
| final bool _hasThisLocal; |
| + /// Keeps track of the number of boxes that we've created so that they each |
| + /// have unique names. |
| + int _boxCounter = 0; |
| + |
| CapturedScopeBuilder(this._model, {bool hasThisLocal}) |
| : this._hasThisLocal = hasThisLocal; |
| @@ -84,6 +88,8 @@ class CapturedScopeBuilder extends ir.Visitor { |
| KernelScopeInfo from = _model.scopeInfo; |
| _scopesCapturedInClosureMap[node] = new KernelCapturedScope( |
| capturedVariablesForScope, |
| + new NodeBox(getBoxName(), _executableContext, |
| + _getMemberContext(_executableContext)), |
|
Johnni Winther
2017/08/01 09:09:10
The member context is not needed. See comment in [
Emily Fortuna
2017/08/01 19:30:06
got it.
|
| _currentLocalFunction, |
| from.localsUsedInTryOrSync, |
| from.freeVariables, |
| @@ -91,6 +97,35 @@ class CapturedScopeBuilder extends ir.Visitor { |
| } |
| } |
| + /// Look up the outermost member that contains this node. |
| + /// |
| + /// For top level, static or instance members, the member context is the |
| + /// node itself. For parameters, local variables and nested closures, the |
| + /// member context is the top level, static or instance member in which it is |
| + /// defined. |
| + ir.Member _getMemberContext(ir.TreeNode startNode) { |
| + ir.TreeNode node = startNode; |
| + while (node is! ir.Member && node != _outermostNode) { |
| + node = node.parent; |
| + } |
| + assert(node is ir.Member); |
| + return node; |
| + } |
| + |
| + /// Generate a unique name for the [_boxCounter]th box field. |
| + /// |
| + /// The result is used as the name of [NodeBox]s and [BoxLocal]s, and must |
| + /// therefore be unique to avoid breaking an invariant in the element model |
| + /// (classes cannot declare multiple fields with the same name). |
| + /// |
| + /// Also, the names should be distinct from real field names to prevent |
| + /// clashes with selectors for those fields. |
| + /// |
| + /// These names are not used in generated code, just as element name. |
| + String getBoxName() { |
| + return "_box_${_boxCounter++}"; |
| + } |
| + |
| /// Perform book-keeping with the current set of local variables that have |
| /// been seen thus far before entering this new scope. |
| void enterNewScope(ir.Node node, void visitNewScope()) { |
| @@ -192,6 +227,7 @@ class CapturedScopeBuilder extends ir.Visitor { |
| if (scope == null) return; |
| _scopesCapturedInClosureMap[node] = new KernelCapturedLoopScope( |
| scope.boxedVariables, |
| + scope.capturedVariablesAccessor, |
| boxedLoopVariables, |
| scope.context, |
| scope.localsUsedInTryOrSync, |
| @@ -201,7 +237,7 @@ class CapturedScopeBuilder extends ir.Visitor { |
| void visitInvokable(ir.TreeNode node) { |
| bool oldIsInsideClosure = _isInsideClosure; |
| - ir.Node oldExecutableContext = _executableContext; |
| + ir.TreeNode oldExecutableContext = _executableContext; |
| KernelScopeInfo oldScopeInfo = _currentScopeInfo; |
| ir.TreeNode oldLocalFunction = _currentLocalFunction; |