| Index: pkg/compiler/lib/src/js_model/closure.dart
|
| diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
|
| index 4730e0cf5b51ad37dad4d7012a6af6757f39de1b..301c9bf59ba24d8dec0faac40346eb12624910e7 100644
|
| --- a/pkg/compiler/lib/src/js_model/closure.dart
|
| +++ b/pkg/compiler/lib/src/js_model/closure.dart
|
| @@ -61,7 +61,8 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
|
| @override
|
| void convertClosures(Iterable<MemberEntity> processedEntities,
|
| ClosedWorldRefiner closedWorldRefiner) {
|
| - var closuresToGenerate = <ir.TreeNode, ScopeInfo>{};
|
| + var closuresToGenerate = <MemberEntity, Map<ir.TreeNode, ScopeInfo>>{};
|
| +
|
| processedEntities.forEach((MemberEntity kEntity) {
|
| MemberEntity entity = _kToJElementMap.toBackendMember(kEntity);
|
| if (entity.isAbstract) return;
|
| @@ -73,22 +74,26 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
|
| // Skip top-level/static fields without an initializer.
|
| if (field.initializer == null) return;
|
| }
|
| - _buildClosureModel(entity, closuresToGenerate, closedWorldRefiner);
|
| + closuresToGenerate[entity] =
|
| + _buildClosureModel(entity, closedWorldRefiner);
|
| });
|
|
|
| - for (ir.TreeNode node in closuresToGenerate.keys) {
|
| - _produceSyntheticElements(
|
| - node, closuresToGenerate[node], closedWorldRefiner);
|
| - }
|
| + closuresToGenerate.forEach(
|
| + (MemberEntity member, Map<ir.TreeNode, ScopeInfo> closuresToGenerate) {
|
| + for (ir.TreeNode node in closuresToGenerate.keys) {
|
| + _produceSyntheticElements(
|
| + member, node, closuresToGenerate[node], closedWorldRefiner);
|
| + }
|
| + });
|
| }
|
|
|
| /// Inspect members and mark if those members capture any state that needs to
|
| /// be marked as free variables.
|
| - void _buildClosureModel(
|
| - MemberEntity entity,
|
| - Map<ir.TreeNode, ScopeInfo> closuresToGenerate,
|
| - ClosedWorldRefiner closedWorldRefiner) {
|
| - if (_scopeMap.keys.contains(entity)) return;
|
| + Map<ir.TreeNode, ScopeInfo> _buildClosureModel(
|
| + MemberEntity entity, ClosedWorldRefiner closedWorldRefiner) {
|
| + assert(!_scopeMap.containsKey(entity),
|
| + failedAt(entity, "ScopeInfo already computed for $entity."));
|
| + Map<ir.TreeNode, ScopeInfo> closuresToGenerate = <ir.TreeNode, ScopeInfo>{};
|
| MemberDefinition definition = _elementMap.getMemberDefinition(entity);
|
| switch (definition.kind) {
|
| case MemberKind.regular:
|
| @@ -98,14 +103,14 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
|
| failedAt(entity, "Unexpected member definition $definition");
|
| }
|
| ir.Node node = definition.node;
|
| - if (_capturedScopesMap.keys.contains(node)) return;
|
| + assert(!_scopeMap.containsKey(entity),
|
| + failedAt(entity, "CaptureScope already computed for $node."));
|
| CapturedScopeBuilder translator = new CapturedScopeBuilder(
|
| entity,
|
| _capturedScopesMap,
|
| _scopeMap,
|
| closuresToGenerate,
|
| - _globalLocalsMap.getLocalsMap(entity),
|
| - _elementMap);
|
| + _globalLocalsMap.getLocalsMap(entity));
|
| if (entity.isField) {
|
| if (node is ir.Field && node.initializer != null) {
|
| translator.translateLazyInitializer(node);
|
| @@ -114,6 +119,7 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
|
| assert(node is ir.Procedure || node is ir.Constructor);
|
| translator.translateConstructorOrProcedure(node);
|
| }
|
| + return closuresToGenerate;
|
| }
|
|
|
| /// Given what variables are captured at each point, construct closure classes
|
| @@ -123,45 +129,30 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
|
| /// boxForCapturedVariables stores the local context for those variables.
|
| /// If no variables are captured, this parameter is null.
|
| void _produceSyntheticElements(
|
| + MemberEntity member,
|
| ir.TreeNode /* ir.Member | ir.FunctionNode */ node,
|
| ScopeInfo info,
|
| ClosedWorldRefiner closedWorldRefiner) {
|
| + String name = _computeClosureName(node);
|
| + KernelClosureClass closureClass = new KernelClosureClass.fromScopeInfo(
|
| + name, member.library, info, node.location);
|
| +
|
| Entity entity;
|
| - ir.Library library;
|
| if (node is ir.Member) {
|
| - entity = _elementMap.getMember(node);
|
| - library = node.enclosingLibrary;
|
| + entity = member;
|
| } else {
|
| assert(node is ir.FunctionNode);
|
| - entity = _elementMap.getLocalFunction(node.parent);
|
| - // TODO(efortuna): Consider the less roundabout way of getting this value
|
| - // which is just storing the "enclosingLibrary" value of the original call
|
| - // to CapturedScopeBuilder.
|
| - ir.TreeNode temp = node;
|
| - while (temp != null && temp is! ir.Library) {
|
| - temp = temp.parent;
|
| - }
|
| - assert(temp is ir.Library);
|
| - library = temp;
|
| - }
|
| - assert(entity != null);
|
| -
|
| - String name = _computeClosureName(node);
|
| - KernelClosureClass closureClass = new KernelClosureClass.fromScopeInfo(
|
| - name, _elementMap.getLibrary(library), info, node.location);
|
| - if (node is ir.FunctionNode) {
|
| + KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
|
| + entity = localsMap.getLocalFunction(node.parent);
|
| // We want the original declaration where that function is used to point
|
| // to the correct closure class.
|
| - // TODO(efortuna): entity equivalent of element.declaration?
|
| - node = (node as ir.FunctionNode).parent;
|
| _closureRepresentationMap[closureClass.callMethod] = closureClass;
|
| }
|
| -
|
| + assert(entity != null);
|
| _closureRepresentationMap[entity] = closureClass;
|
|
|
| // Register that a new class has been created.
|
| - closedWorldRefiner.registerClosureClass(
|
| - closureClass, node is ir.Member && node.isInstanceMember);
|
| + closedWorldRefiner.registerClosureClass(closureClass);
|
| }
|
|
|
| // Returns a non-unique name for the given closure element.
|
| @@ -355,7 +346,7 @@ class KernelClosureClass extends KernelScopeInfo
|
| // NOTE: This construction order may be slightly different than the
|
| // old Element version. The old version did all the boxed items and then
|
| // all the others.
|
| - Local capturedLocal = info.localsMap.getLocal(variable);
|
| + Local capturedLocal = info.localsMap.getLocalVariable(variable);
|
| if (info.isBoxed(capturedLocal)) {
|
| // TODO(efortuna): Coming soon.
|
| } else {
|
|
|