| 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/tasks.dart'; | 9 import '../common/tasks.dart'; |
| 9 import '../elements/entities.dart'; | 10 import '../elements/entities.dart'; |
| 10 import '../kernel/element_map.dart'; | 11 import '../kernel/element_map.dart'; |
| 11 import '../world.dart'; | 12 import '../world.dart'; |
| 12 import 'elements.dart'; | 13 import 'elements.dart'; |
| 13 import 'closure_visitors.dart'; | 14 import 'closure_visitors.dart'; |
| 14 import 'locals.dart'; | 15 import 'locals.dart'; |
| 15 | 16 |
| 16 /// Closure conversion code using our new Entity model. Closure conversion is | 17 /// Closure conversion code using our new Entity model. Closure conversion is |
| 17 /// necessary because the semantics of closures are slightly different in Dart | 18 /// necessary because the semantics of closures are slightly different in Dart |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 void convertClosures(Iterable<MemberEntity> processedEntities, | 60 void convertClosures(Iterable<MemberEntity> processedEntities, |
| 60 ClosedWorldRefiner closedWorldRefiner) { | 61 ClosedWorldRefiner closedWorldRefiner) { |
| 61 var closuresToGenerate = <ir.TreeNode, ScopeInfo>{}; | 62 var closuresToGenerate = <ir.TreeNode, ScopeInfo>{}; |
| 62 processedEntities.forEach((MemberEntity kEntity) { | 63 processedEntities.forEach((MemberEntity kEntity) { |
| 63 MemberEntity entity = kEntity; | 64 MemberEntity entity = kEntity; |
| 64 if (_kToJElementMap != null) { | 65 if (_kToJElementMap != null) { |
| 65 entity = _kToJElementMap.toBackendMember(kEntity); | 66 entity = _kToJElementMap.toBackendMember(kEntity); |
| 66 } | 67 } |
| 67 if (entity.isAbstract) return; | 68 if (entity.isAbstract) return; |
| 68 if (entity.isField && !entity.isInstanceMember) { | 69 if (entity.isField && !entity.isInstanceMember) { |
| 69 ir.Field field = _elementMap.getMemberNode(entity); | 70 MemberDefinition definition = _elementMap.getMemberDefinition(entity); |
| 71 assert(definition.kind == MemberKind.regular, |
| 72 failedAt(entity, "Unexpected member definition $definition")); |
| 73 ir.Field field = definition.node; |
| 70 // Skip top-level/static fields without an initializer. | 74 // Skip top-level/static fields without an initializer. |
| 71 if (field.initializer == null) return; | 75 if (field.initializer == null) return; |
| 72 } | 76 } |
| 73 _buildClosureModel(entity, closuresToGenerate, closedWorldRefiner); | 77 _buildClosureModel(entity, closuresToGenerate, closedWorldRefiner); |
| 74 }); | 78 }); |
| 75 | 79 |
| 76 for (ir.TreeNode node in closuresToGenerate.keys) { | 80 for (ir.TreeNode node in closuresToGenerate.keys) { |
| 77 _produceSyntheticElements( | 81 _produceSyntheticElements( |
| 78 node, closuresToGenerate[node], closedWorldRefiner); | 82 node, closuresToGenerate[node], closedWorldRefiner); |
| 79 } | 83 } |
| 80 } | 84 } |
| 81 | 85 |
| 82 /// Inspect members and mark if those members capture any state that needs to | 86 /// Inspect members and mark if those members capture any state that needs to |
| 83 /// be marked as free variables. | 87 /// be marked as free variables. |
| 84 void _buildClosureModel( | 88 void _buildClosureModel( |
| 85 MemberEntity entity, | 89 MemberEntity entity, |
| 86 Map<ir.TreeNode, ScopeInfo> closuresToGenerate, | 90 Map<ir.TreeNode, ScopeInfo> closuresToGenerate, |
| 87 ClosedWorldRefiner closedWorldRefiner) { | 91 ClosedWorldRefiner closedWorldRefiner) { |
| 88 if (_scopeMap.keys.contains(entity)) return; | 92 if (_scopeMap.keys.contains(entity)) return; |
| 89 ir.Node node = _elementMap.getMemberNode(entity); | 93 MemberDefinition definition = _elementMap.getMemberDefinition(entity); |
| 94 switch (definition.kind) { |
| 95 case MemberKind.regular: |
| 96 case MemberKind.constructor: |
| 97 break; |
| 98 default: |
| 99 failedAt(entity, "Unexpected member definition $definition"); |
| 100 } |
| 101 ir.Node node = definition.node; |
| 90 if (_scopesCapturedInClosureMap.keys.contains(node)) return; | 102 if (_scopesCapturedInClosureMap.keys.contains(node)) return; |
| 91 CapturedScopeBuilder translator = new CapturedScopeBuilder( | 103 CapturedScopeBuilder translator = new CapturedScopeBuilder( |
| 92 _scopesCapturedInClosureMap, | 104 _scopesCapturedInClosureMap, |
| 93 _scopeMap, | 105 _scopeMap, |
| 94 entity, | 106 entity, |
| 95 closuresToGenerate, | 107 closuresToGenerate, |
| 96 _globalLocalsMap.getLocalsMap(entity), | 108 _globalLocalsMap.getLocalsMap(entity), |
| 97 _elementMap); | 109 _elementMap); |
| 98 if (entity.isField) { | 110 if (entity.isField) { |
| 99 if (node is ir.Field && node.initializer != null) { | 111 if (node is ir.Field && node.initializer != null) { |
| 100 translator.translateLazyInitializer(node); | 112 translator.translateLazyInitializer(node); |
| 101 } | 113 } |
| 102 } else { | 114 } else { |
| 103 assert(node is ir.Procedure || node is ir.Constructor); | 115 assert(node is ir.Procedure || node is ir.Constructor); |
| 104 translator.translateConstructorOrProcedure(node); | 116 translator.translateConstructorOrProcedure(node); |
| 105 } | 117 } |
| 106 } | 118 } |
| 107 | 119 |
| 108 /// Given what variables are captured at each point, construct closure classes | 120 /// Given what variables are captured at each point, construct closure classes |
| 109 /// with fields containing the captured variables to replicate the Dart | 121 /// with fields containing the captured variables to replicate the Dart |
| 110 /// closure semantics in JS. | 122 /// closure semantics in JS. |
| 111 void _produceSyntheticElements( | 123 void _produceSyntheticElements( |
| 112 ir.TreeNode /* ir.Field | ir.FunctionNode */ node, | 124 ir.TreeNode /* ir.Field | ir.FunctionNode */ node, |
| 113 ScopeInfo info, | 125 ScopeInfo info, |
| 114 ClosedWorldRefiner closedWorldRefiner) { | 126 ClosedWorldRefiner closedWorldRefiner) { |
| 115 Entity entity; | 127 Entity entity; |
| 116 KernelClosureClass closureClass = | 128 KernelClosureClass closureClass = |
| 117 new KernelClosureClass.fromScopeInfo(info); | 129 new KernelClosureClass.fromScopeInfo(info, node.location); |
| 118 if (node is ir.FunctionNode) { | 130 if (node is ir.FunctionNode) { |
| 119 // We want the original declaration where that function is used to point | 131 // We want the original declaration where that function is used to point |
| 120 // to the correct closure class. | 132 // to the correct closure class. |
| 121 // TODO(efortuna): entity equivalent of element.declaration? | 133 // TODO(efortuna): entity equivalent of element.declaration? |
| 122 node = (node as ir.FunctionNode).parent; | 134 node = (node as ir.FunctionNode).parent; |
| 123 _closureRepresentationMap[closureClass.callMethod] = closureClass; | 135 _closureRepresentationMap[closureClass.callMethod] = closureClass; |
| 124 } | 136 } |
| 125 | 137 |
| 126 if (node is ir.Member) { | 138 if (node is ir.Member) { |
| 127 entity = _elementMap.getMember(node); | 139 entity = _elementMap.getMember(node); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 146 ConstructorBodyEntity constructorBody = entity; | 158 ConstructorBodyEntity constructorBody = entity; |
| 147 entity = constructorBody.constructor; | 159 entity = constructorBody.constructor; |
| 148 } | 160 } |
| 149 | 161 |
| 150 return _scopeMap[entity] ?? getClosureRepresentationInfo(entity); | 162 return _scopeMap[entity] ?? getClosureRepresentationInfo(entity); |
| 151 } | 163 } |
| 152 | 164 |
| 153 // TODO(efortuna): Eventually scopesCapturedInClosureMap[node] should always | 165 // TODO(efortuna): Eventually scopesCapturedInClosureMap[node] should always |
| 154 // be non-null, and we should just test that with an assert. | 166 // be non-null, and we should just test that with an assert. |
| 155 @override | 167 @override |
| 156 CapturedScope getCapturedScope(MemberEntity entity) => | 168 CapturedScope getCapturedScope(MemberEntity entity) { |
| 157 _scopesCapturedInClosureMap[_elementMap.getMemberNode(entity)] ?? | 169 MemberDefinition definition = _elementMap.getMemberDefinition(entity); |
| 158 const CapturedScope(); | 170 switch (definition.kind) { |
| 171 case MemberKind.regular: |
| 172 case MemberKind.constructor: |
| 173 case MemberKind.constructorBody: |
| 174 return _scopesCapturedInClosureMap[definition.node] ?? |
| 175 const CapturedScope(); |
| 176 default: |
| 177 throw failedAt(entity, "Unexpected member definition $definition"); |
| 178 } |
| 179 } |
| 159 | 180 |
| 160 @override | 181 @override |
| 161 // TODO(efortuna): Eventually scopesCapturedInClosureMap[node] should always | 182 // TODO(efortuna): Eventually scopesCapturedInClosureMap[node] should always |
| 162 // be non-null, and we should just test that with an assert. | 183 // be non-null, and we should just test that with an assert. |
| 163 CapturedLoopScope getCapturedLoopScope(ir.Node loopNode) => | 184 CapturedLoopScope getCapturedLoopScope(ir.Node loopNode) => |
| 164 _scopesCapturedInClosureMap[loopNode] ?? const CapturedLoopScope(); | 185 _scopesCapturedInClosureMap[loopNode] ?? const CapturedLoopScope(); |
| 165 | 186 |
| 166 @override | 187 @override |
| 167 // TODO(efortuna): Eventually closureRepresentationMap[node] should always be | 188 // TODO(efortuna): Eventually closureRepresentationMap[node] should always be |
| 168 // non-null, and we should just test that with an assert. | 189 // non-null, and we should just test that with an assert. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 KernelCapturedLoopScope(Set<Local> boxedVariables, this.boxedLoopVariables, | 249 KernelCapturedLoopScope(Set<Local> boxedVariables, this.boxedLoopVariables, |
| 229 Local context, Local thisLocal) | 250 Local context, Local thisLocal) |
| 230 : super(boxedVariables, context, thisLocal); | 251 : super(boxedVariables, context, thisLocal); |
| 231 | 252 |
| 232 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; | 253 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; |
| 233 } | 254 } |
| 234 | 255 |
| 235 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. | 256 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. |
| 236 class KernelClosureClass extends KernelScopeInfo | 257 class KernelClosureClass extends KernelScopeInfo |
| 237 implements ClosureRepresentationInfo, JClass { | 258 implements ClosureRepresentationInfo, JClass { |
| 259 final ir.Location location; |
| 260 |
| 238 // TODO(efortuna): Generate unique name for each closure class. | 261 // TODO(efortuna): Generate unique name for each closure class. |
| 239 final String name = 'ClosureClass'; | 262 final String name = 'ClosureClass'; |
| 240 | 263 |
| 241 /// Index into the classData, classList and classEnvironment lists where this | 264 /// Index into the classData, classList and classEnvironment lists where this |
| 242 /// entity is stored in [JsToFrontendMapImpl]. | 265 /// entity is stored in [JsToFrontendMapImpl]. |
| 243 int classIndex; | 266 int classIndex; |
| 244 | 267 |
| 245 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); | 268 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); |
| 246 | 269 |
| 247 KernelClosureClass.fromScopeInfo(KernelScopeInfo info) | 270 KernelClosureClass.fromScopeInfo(KernelScopeInfo info, this.location) |
| 248 : super.from(info.thisLocal, info); | 271 : super.from(info.thisLocal, info); |
| 249 | 272 |
| 250 // TODO(efortuna): Implement. | 273 // TODO(efortuna): Implement. |
| 251 Local get closureEntity => null; | 274 Local get closureEntity => null; |
| 252 | 275 |
| 253 ClassEntity get closureClassEntity => this; | 276 ClassEntity get closureClassEntity => this; |
| 254 | 277 |
| 255 // TODO(efortuna): Implement. | 278 // TODO(efortuna): Implement. |
| 256 FunctionEntity get callMethod => null; | 279 FunctionEntity get callMethod => null; |
| 257 | 280 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 281 // that (and the subsequent adjustment here) will follow soon. | 304 // that (and the subsequent adjustment here) will follow soon. |
| 282 bool get isClosure => false; | 305 bool get isClosure => false; |
| 283 | 306 |
| 284 bool get isAbstract => false; | 307 bool get isAbstract => false; |
| 285 | 308 |
| 286 // TODO(efortuna): Talk to Johnni. | 309 // TODO(efortuna): Talk to Johnni. |
| 287 JLibrary get library => null; | 310 JLibrary get library => null; |
| 288 | 311 |
| 289 String toString() => '${jsElementPrefix}class($name)'; | 312 String toString() => '${jsElementPrefix}class($name)'; |
| 290 } | 313 } |
| 314 |
| 315 class ClosureClassDefinition implements ClassDefinition { |
| 316 final ClassEntity cls; |
| 317 final ir.Location location; |
| 318 |
| 319 ClosureClassDefinition(this.cls, this.location); |
| 320 |
| 321 ClassKind get kind => ClassKind.closure; |
| 322 |
| 323 ir.Node get node => |
| 324 throw new UnsupportedError('ClosureClassDefinition.node for $cls'); |
| 325 |
| 326 String toString() => |
| 327 'ClosureClassDefinition(kind:$kind,cls:$cls,location:$location)'; |
| 328 } |
| OLD | NEW |