| 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 '../common.dart'; | 8 import '../common.dart'; |
| 9 import '../common/tasks.dart'; | 9 import '../common/tasks.dart'; |
| 10 import '../elements/elements.dart'; | 10 import '../elements/elements.dart'; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 | 54 |
| 55 /// The combined steps of generating our intermediate representation of | 55 /// The combined steps of generating our intermediate representation of |
| 56 /// closures that need to be rewritten and generating the element model. | 56 /// closures that need to be rewritten and generating the element model. |
| 57 /// Ultimately these two steps will be split apart with the second step | 57 /// Ultimately these two steps will be split apart with the second step |
| 58 /// happening later in compilation just before codegen. These steps are | 58 /// happening later in compilation just before codegen. These steps are |
| 59 /// combined here currently to provide a consistent interface to the rest of | 59 /// combined here currently to provide a consistent interface to the rest of |
| 60 /// the compiler until we are ready to separate these phases. | 60 /// the compiler until we are ready to separate these phases. |
| 61 @override | 61 @override |
| 62 void convertClosures(Iterable<MemberEntity> processedEntities, | 62 void convertClosures(Iterable<MemberEntity> processedEntities, |
| 63 ClosedWorldRefiner closedWorldRefiner) { | 63 ClosedWorldRefiner closedWorldRefiner) { |
| 64 var closuresToGenerate = <ir.TreeNode, ScopeInfo>{}; | 64 var closuresToGenerate = <MemberEntity, Map<ir.TreeNode, ScopeInfo>>{}; |
| 65 |
| 65 processedEntities.forEach((MemberEntity kEntity) { | 66 processedEntities.forEach((MemberEntity kEntity) { |
| 66 MemberEntity entity = _kToJElementMap.toBackendMember(kEntity); | 67 MemberEntity entity = _kToJElementMap.toBackendMember(kEntity); |
| 67 if (entity.isAbstract) return; | 68 if (entity.isAbstract) return; |
| 68 if (entity.isField && !entity.isInstanceMember) { | 69 if (entity.isField && !entity.isInstanceMember) { |
| 69 MemberDefinition definition = _elementMap.getMemberDefinition(entity); | 70 MemberDefinition definition = _elementMap.getMemberDefinition(entity); |
| 70 assert(definition.kind == MemberKind.regular, | 71 assert(definition.kind == MemberKind.regular, |
| 71 failedAt(entity, "Unexpected member definition $definition")); | 72 failedAt(entity, "Unexpected member definition $definition")); |
| 72 ir.Field field = definition.node; | 73 ir.Field field = definition.node; |
| 73 // Skip top-level/static fields without an initializer. | 74 // Skip top-level/static fields without an initializer. |
| 74 if (field.initializer == null) return; | 75 if (field.initializer == null) return; |
| 75 } | 76 } |
| 76 _buildClosureModel(entity, closuresToGenerate, closedWorldRefiner); | 77 closuresToGenerate[entity] = |
| 78 _buildClosureModel(entity, closedWorldRefiner); |
| 77 }); | 79 }); |
| 78 | 80 |
| 79 for (ir.TreeNode node in closuresToGenerate.keys) { | 81 closuresToGenerate.forEach( |
| 80 _produceSyntheticElements( | 82 (MemberEntity member, Map<ir.TreeNode, ScopeInfo> closuresToGenerate) { |
| 81 node, closuresToGenerate[node], closedWorldRefiner); | 83 for (ir.TreeNode node in closuresToGenerate.keys) { |
| 82 } | 84 _produceSyntheticElements( |
| 85 member, node, closuresToGenerate[node], closedWorldRefiner); |
| 86 } |
| 87 }); |
| 83 } | 88 } |
| 84 | 89 |
| 85 /// Inspect members and mark if those members capture any state that needs to | 90 /// Inspect members and mark if those members capture any state that needs to |
| 86 /// be marked as free variables. | 91 /// be marked as free variables. |
| 87 void _buildClosureModel( | 92 Map<ir.TreeNode, ScopeInfo> _buildClosureModel( |
| 88 MemberEntity entity, | 93 MemberEntity entity, ClosedWorldRefiner closedWorldRefiner) { |
| 89 Map<ir.TreeNode, ScopeInfo> closuresToGenerate, | 94 assert(!_scopeMap.containsKey(entity), |
| 90 ClosedWorldRefiner closedWorldRefiner) { | 95 failedAt(entity, "ScopeInfo already computed for $entity.")); |
| 91 if (_scopeMap.keys.contains(entity)) return; | 96 Map<ir.TreeNode, ScopeInfo> closuresToGenerate = <ir.TreeNode, ScopeInfo>{}; |
| 92 MemberDefinition definition = _elementMap.getMemberDefinition(entity); | 97 MemberDefinition definition = _elementMap.getMemberDefinition(entity); |
| 93 switch (definition.kind) { | 98 switch (definition.kind) { |
| 94 case MemberKind.regular: | 99 case MemberKind.regular: |
| 95 case MemberKind.constructor: | 100 case MemberKind.constructor: |
| 96 break; | 101 break; |
| 97 default: | 102 default: |
| 98 failedAt(entity, "Unexpected member definition $definition"); | 103 failedAt(entity, "Unexpected member definition $definition"); |
| 99 } | 104 } |
| 100 ir.Node node = definition.node; | 105 ir.Node node = definition.node; |
| 101 if (_capturedScopesMap.keys.contains(node)) return; | 106 assert(!_scopeMap.containsKey(entity), |
| 107 failedAt(entity, "CaptureScope already computed for $node.")); |
| 102 CapturedScopeBuilder translator = new CapturedScopeBuilder( | 108 CapturedScopeBuilder translator = new CapturedScopeBuilder( |
| 103 entity, | 109 entity, |
| 104 _capturedScopesMap, | 110 _capturedScopesMap, |
| 105 _scopeMap, | 111 _scopeMap, |
| 106 closuresToGenerate, | 112 closuresToGenerate, |
| 107 _globalLocalsMap.getLocalsMap(entity), | 113 _globalLocalsMap.getLocalsMap(entity)); |
| 108 _elementMap); | |
| 109 if (entity.isField) { | 114 if (entity.isField) { |
| 110 if (node is ir.Field && node.initializer != null) { | 115 if (node is ir.Field && node.initializer != null) { |
| 111 translator.translateLazyInitializer(node); | 116 translator.translateLazyInitializer(node); |
| 112 } | 117 } |
| 113 } else { | 118 } else { |
| 114 assert(node is ir.Procedure || node is ir.Constructor); | 119 assert(node is ir.Procedure || node is ir.Constructor); |
| 115 translator.translateConstructorOrProcedure(node); | 120 translator.translateConstructorOrProcedure(node); |
| 116 } | 121 } |
| 122 return closuresToGenerate; |
| 117 } | 123 } |
| 118 | 124 |
| 119 /// Given what variables are captured at each point, construct closure classes | 125 /// Given what variables are captured at each point, construct closure classes |
| 120 /// with fields containing the captured variables to replicate the Dart | 126 /// with fields containing the captured variables to replicate the Dart |
| 121 /// closure semantics in JS. If this closure captures any variables (meaning | 127 /// closure semantics in JS. If this closure captures any variables (meaning |
| 122 /// the closure accesses a variable that gets accessed at some point), then | 128 /// the closure accesses a variable that gets accessed at some point), then |
| 123 /// boxForCapturedVariables stores the local context for those variables. | 129 /// boxForCapturedVariables stores the local context for those variables. |
| 124 /// If no variables are captured, this parameter is null. | 130 /// If no variables are captured, this parameter is null. |
| 125 void _produceSyntheticElements( | 131 void _produceSyntheticElements( |
| 132 MemberEntity member, |
| 126 ir.TreeNode /* ir.Member | ir.FunctionNode */ node, | 133 ir.TreeNode /* ir.Member | ir.FunctionNode */ node, |
| 127 ScopeInfo info, | 134 ScopeInfo info, |
| 128 ClosedWorldRefiner closedWorldRefiner) { | 135 ClosedWorldRefiner closedWorldRefiner) { |
| 136 String name = _computeClosureName(node); |
| 137 KernelClosureClass closureClass = new KernelClosureClass.fromScopeInfo( |
| 138 name, member.library, info, node.location); |
| 139 |
| 129 Entity entity; | 140 Entity entity; |
| 130 ir.Library library; | |
| 131 if (node is ir.Member) { | 141 if (node is ir.Member) { |
| 132 entity = _elementMap.getMember(node); | 142 entity = member; |
| 133 library = node.enclosingLibrary; | |
| 134 } else { | 143 } else { |
| 135 assert(node is ir.FunctionNode); | 144 assert(node is ir.FunctionNode); |
| 136 entity = _elementMap.getLocalFunction(node.parent); | 145 KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member); |
| 137 // TODO(efortuna): Consider the less roundabout way of getting this value | 146 entity = localsMap.getLocalFunction(node.parent); |
| 138 // which is just storing the "enclosingLibrary" value of the original call | 147 // We want the original declaration where that function is used to point |
| 139 // to CapturedScopeBuilder. | 148 // to the correct closure class. |
| 140 ir.TreeNode temp = node; | 149 _closureRepresentationMap[closureClass.callMethod] = closureClass; |
| 141 while (temp != null && temp is! ir.Library) { | |
| 142 temp = temp.parent; | |
| 143 } | |
| 144 assert(temp is ir.Library); | |
| 145 library = temp; | |
| 146 } | 150 } |
| 147 assert(entity != null); | 151 assert(entity != null); |
| 148 | |
| 149 String name = _computeClosureName(node); | |
| 150 KernelClosureClass closureClass = new KernelClosureClass.fromScopeInfo( | |
| 151 name, _elementMap.getLibrary(library), info, node.location); | |
| 152 if (node is ir.FunctionNode) { | |
| 153 // We want the original declaration where that function is used to point | |
| 154 // to the correct closure class. | |
| 155 // TODO(efortuna): entity equivalent of element.declaration? | |
| 156 node = (node as ir.FunctionNode).parent; | |
| 157 _closureRepresentationMap[closureClass.callMethod] = closureClass; | |
| 158 } | |
| 159 | |
| 160 _closureRepresentationMap[entity] = closureClass; | 152 _closureRepresentationMap[entity] = closureClass; |
| 161 | 153 |
| 162 // Register that a new class has been created. | 154 // Register that a new class has been created. |
| 163 closedWorldRefiner.registerClosureClass( | 155 closedWorldRefiner.registerClosureClass(closureClass); |
| 164 closureClass, node is ir.Member && node.isInstanceMember); | |
| 165 } | 156 } |
| 166 | 157 |
| 167 // Returns a non-unique name for the given closure element. | 158 // Returns a non-unique name for the given closure element. |
| 168 String _computeClosureName(ir.TreeNode treeNode) { | 159 String _computeClosureName(ir.TreeNode treeNode) { |
| 169 var parts = <String>[]; | 160 var parts = <String>[]; |
| 170 if (treeNode is ir.Field && treeNode.name.name != "") { | 161 if (treeNode is ir.Field && treeNode.name.name != "") { |
| 171 parts.add(treeNode.name.name); | 162 parts.add(treeNode.name.name); |
| 172 } else { | 163 } else { |
| 173 parts.add('closure'); | 164 parts.add('closure'); |
| 174 } | 165 } |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 KernelClosureClass.fromScopeInfo( | 339 KernelClosureClass.fromScopeInfo( |
| 349 this.name, this.library, KernelScopeInfo info, this.location) | 340 this.name, this.library, KernelScopeInfo info, this.location) |
| 350 : super.from(info.thisLocal, info) { | 341 : super.from(info.thisLocal, info) { |
| 351 // Make a corresponding field entity in this closure class for every single | 342 // Make a corresponding field entity in this closure class for every single |
| 352 // freeVariable in the KernelScopeInfo.freeVariable. | 343 // freeVariable in the KernelScopeInfo.freeVariable. |
| 353 int i = 0; | 344 int i = 0; |
| 354 for (ir.VariableDeclaration variable in info.freeVariables) { | 345 for (ir.VariableDeclaration variable in info.freeVariables) { |
| 355 // NOTE: This construction order may be slightly different than the | 346 // NOTE: This construction order may be slightly different than the |
| 356 // old Element version. The old version did all the boxed items and then | 347 // old Element version. The old version did all the boxed items and then |
| 357 // all the others. | 348 // all the others. |
| 358 Local capturedLocal = info.localsMap.getLocal(variable); | 349 Local capturedLocal = info.localsMap.getLocalVariable(variable); |
| 359 if (info.isBoxed(capturedLocal)) { | 350 if (info.isBoxed(capturedLocal)) { |
| 360 // TODO(efortuna): Coming soon. | 351 // TODO(efortuna): Coming soon. |
| 361 } else { | 352 } else { |
| 362 localToFieldMap[capturedLocal] = new ClosureField( | 353 localToFieldMap[capturedLocal] = new ClosureField( |
| 363 _getClosureVariableName(capturedLocal.name, i), | 354 _getClosureVariableName(capturedLocal.name, i), |
| 364 this, | 355 this, |
| 365 variable.isConst, | 356 variable.isConst, |
| 366 variable.isFinal || variable.isConst); | 357 variable.isFinal || variable.isConst); |
| 367 // TODO(efortuna): These probably need to get registered somewhere. | 358 // TODO(efortuna): These probably need to get registered somewhere. |
| 368 } | 359 } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 ClosureClassDefinition(this.cls, this.location); | 425 ClosureClassDefinition(this.cls, this.location); |
| 435 | 426 |
| 436 ClassKind get kind => ClassKind.closure; | 427 ClassKind get kind => ClassKind.closure; |
| 437 | 428 |
| 438 ir.Node get node => | 429 ir.Node get node => |
| 439 throw new UnsupportedError('ClosureClassDefinition.node for $cls'); | 430 throw new UnsupportedError('ClosureClassDefinition.node for $cls'); |
| 440 | 431 |
| 441 String toString() => | 432 String toString() => |
| 442 'ClosureClassDefinition(kind:$kind,cls:$cls,location:$location)'; | 433 'ClosureClassDefinition(kind:$kind,cls:$cls,location:$location)'; |
| 443 } | 434 } |
| OLD | NEW |