| 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/tasks.dart'; | 8 import '../common/tasks.dart'; |
| 9 import '../elements/entities.dart'; | 9 import '../elements/entities.dart'; |
| 10 import '../kernel/element_map.dart'; | 10 import '../kernel/element_map.dart'; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 | 47 |
| 48 /// The combined steps of generating our intermediate representation of | 48 /// The combined steps of generating our intermediate representation of |
| 49 /// closures that need to be rewritten and generating the element model. | 49 /// closures that need to be rewritten and generating the element model. |
| 50 /// Ultimately these two steps will be split apart with the second step | 50 /// Ultimately these two steps will be split apart with the second step |
| 51 /// happening later in compilation just before codegen. These steps are | 51 /// happening later in compilation just before codegen. These steps are |
| 52 /// combined here currently to provide a consistent interface to the rest of | 52 /// combined here currently to provide a consistent interface to the rest of |
| 53 /// the compiler until we are ready to separate these phases. | 53 /// the compiler until we are ready to separate these phases. |
| 54 @override | 54 @override |
| 55 void convertClosures(Iterable<MemberEntity> processedEntities, | 55 void convertClosures(Iterable<MemberEntity> processedEntities, |
| 56 ClosedWorldRefiner closedWorldRefiner) { | 56 ClosedWorldRefiner closedWorldRefiner) { |
| 57 var closuresToGenerate = <ir.Node, ScopeInfo>{}; | 57 var closuresToGenerate = <ir.TreeNode, ScopeInfo>{}; |
| 58 processedEntities.forEach((MemberEntity kEntity) { | 58 processedEntities.forEach((MemberEntity kEntity) { |
| 59 MemberEntity entity = kEntity; | 59 MemberEntity entity = kEntity; |
| 60 if (_kToJElementMap != null) { | 60 if (_kToJElementMap != null) { |
| 61 entity = _kToJElementMap.toBackendMember(kEntity); | 61 entity = _kToJElementMap.toBackendMember(kEntity); |
| 62 } | 62 } |
| 63 if (entity.isAbstract) return; | 63 if (entity.isAbstract) return; |
| 64 if (entity.isField && !entity.isInstanceMember) { | 64 if (entity.isField && !entity.isInstanceMember) { |
| 65 ir.Field field = _elementMap.getMemberNode(entity); | 65 ir.Field field = _elementMap.getMemberNode(entity); |
| 66 // Skip top-level/static fields without an initializer. | 66 // Skip top-level/static fields without an initializer. |
| 67 if (field.initializer == null) return; | 67 if (field.initializer == null) return; |
| 68 } | 68 } |
| 69 _buildClosureModel(entity, closuresToGenerate, closedWorldRefiner); | 69 _buildClosureModel(entity, closuresToGenerate, closedWorldRefiner); |
| 70 }); | 70 }); |
| 71 | 71 |
| 72 for (ir.Node node in closuresToGenerate.keys) { | 72 for (ir.TreeNode node in closuresToGenerate.keys) { |
| 73 _produceSyntheticElements( | 73 _produceSyntheticElements( |
| 74 node, closuresToGenerate[node], closedWorldRefiner); | 74 node, closuresToGenerate[node], closedWorldRefiner); |
| 75 } | 75 } |
| 76 } | 76 } |
| 77 | 77 |
| 78 /// Inspect members and mark if those members capture any state that needs to | 78 /// Inspect members and mark if those members capture any state that needs to |
| 79 /// be marked as free variables. | 79 /// be marked as free variables. |
| 80 void _buildClosureModel( | 80 void _buildClosureModel( |
| 81 MemberEntity entity, | 81 MemberEntity entity, |
| 82 Map<ir.Node, ScopeInfo> closuresToGenerate, | 82 Map<ir.TreeNode, ScopeInfo> closuresToGenerate, |
| 83 ClosedWorldRefiner closedWorldRefiner) { | 83 ClosedWorldRefiner closedWorldRefiner) { |
| 84 ir.Node node = _elementMap.getMemberNode(entity); | 84 ir.Node node = _elementMap.getMemberNode(entity); |
| 85 if (_closureScopeMap.keys.contains(node)) return; | 85 if (_closureScopeMap.keys.contains(node)) return; |
| 86 ClosureScopeBuilder translator = new ClosureScopeBuilder(_closureScopeMap, | 86 ClosureScopeBuilder translator = new ClosureScopeBuilder(_closureScopeMap, |
| 87 closuresToGenerate, _globalLocalsMap.getLocalsMap(entity), _elementMap); | 87 closuresToGenerate, _globalLocalsMap.getLocalsMap(entity), _elementMap); |
| 88 if (entity.isField) { | 88 if (entity.isField) { |
| 89 if (node is ir.Field && node.initializer != null) { | 89 if (node is ir.Field && node.initializer != null) { |
| 90 translator.translateLazyInitializer(node); | 90 translator.translateLazyInitializer(node); |
| 91 } | 91 } |
| 92 } else { | 92 } else { |
| 93 assert(node is ir.Procedure || node is ir.Constructor); | 93 assert(node is ir.Procedure || node is ir.Constructor); |
| 94 translator.translateConstructorOrProcedure(node); | 94 translator.translateConstructorOrProcedure(node); |
| 95 } | 95 } |
| 96 } | 96 } |
| 97 | 97 |
| 98 /// Given what variables are captured at each point, construct closure classes | 98 /// Given what variables are captured at each point, construct closure classes |
| 99 /// with fields containing the captured variables to replicate the Dart | 99 /// with fields containing the captured variables to replicate the Dart |
| 100 /// closure semantics in JS. | 100 /// closure semantics in JS. |
| 101 void _produceSyntheticElements( | 101 void _produceSyntheticElements( |
| 102 ir.Node node, ScopeInfo info, ClosedWorldRefiner closedWorldRefiner) { | 102 ir.TreeNode /* ir.Field | ir.FunctionNode */ node, |
| 103 ScopeInfo info, |
| 104 ClosedWorldRefiner closedWorldRefiner) { |
| 103 Entity entity; | 105 Entity entity; |
| 104 KernelClosureClass closureClass = | 106 KernelClosureClass closureClass = |
| 105 new KernelClosureClass.fromScopeInfo(info); | 107 new KernelClosureClass.fromScopeInfo(info); |
| 106 if (node is ir.FunctionNode) { | 108 if (node is ir.FunctionNode) { |
| 107 // We want the original declaration where that function is used to point | 109 // We want the original declaration where that function is used to point |
| 108 // to the correct closure class. | 110 // to the correct closure class. |
| 109 // TODO(efortuna): entity equivalent of element.declaration? | 111 // TODO(efortuna): entity equivalent of element.declaration? |
| 110 node = (node as ir.FunctionNode).parent; | 112 node = (node as ir.FunctionNode).parent; |
| 111 _closureRepresentationMap[closureClass.callMethod] = closureClass; | 113 _closureRepresentationMap[closureClass.callMethod] = closureClass; |
| 112 } | 114 } |
| 113 | 115 |
| 114 if (node is ir.Member) { | 116 if (node is ir.Member) { |
| 115 entity = _elementMap.getMember(node); | 117 entity = _elementMap.getMember(node); |
| 116 } else { | 118 } else { |
| 117 entity = _elementMap.getLocalFunction(node); | 119 entity = _elementMap.getLocalFunction(node); |
| 118 } | 120 } |
| 119 assert(entity != null); | 121 assert(entity != null); |
| 120 | 122 |
| 121 _closureRepresentationMap[entity] = closureClass; | 123 _closureRepresentationMap[entity] = closureClass; |
| 124 |
| 125 // Register that a new class has been created. |
| 126 closedWorldRefiner.registerClosureClass( |
| 127 closureClass, node is ir.Member && node.isInstanceMember); |
| 122 } | 128 } |
| 123 | 129 |
| 124 @override | 130 @override |
| 125 ScopeInfo getScopeInfo(Entity entity) { | 131 ScopeInfo getScopeInfo(Entity entity) { |
| 126 return getClosureRepresentationInfo(entity); | 132 return getClosureRepresentationInfo(entity); |
| 127 } | 133 } |
| 128 | 134 |
| 129 // TODO(efortuna): Eventually closureScopeMap[node] should always be non-null, | 135 // TODO(efortuna): Eventually closureScopeMap[node] should always be non-null, |
| 130 // and we should just test that with an assert. | 136 // and we should just test that with an assert. |
| 131 ClosureScope _getClosureScope(ir.Node node) => | 137 ClosureScope _getClosureScope(ir.Node node) => |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 | 219 |
| 214 KernelLoopClosureScope(Set<Local> boxedVariables, this.boxedLoopVariables, | 220 KernelLoopClosureScope(Set<Local> boxedVariables, this.boxedLoopVariables, |
| 215 Local context, Local thisLocal) | 221 Local context, Local thisLocal) |
| 216 : super(boxedVariables, context, thisLocal); | 222 : super(boxedVariables, context, thisLocal); |
| 217 | 223 |
| 218 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; | 224 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty; |
| 219 } | 225 } |
| 220 | 226 |
| 221 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. | 227 // TODO(johnniwinther): Add unittest for the computed [ClosureClass]. |
| 222 class KernelClosureClass extends KernelScopeInfo | 228 class KernelClosureClass extends KernelScopeInfo |
| 223 implements ClosureRepresentationInfo { | 229 implements ClosureRepresentationInfo, JClass { |
| 224 KernelClosureClass.fromScopeInfo(ScopeInfo info) | 230 // TODO(efortuna): Generate unique name for each closure class. |
| 231 final String name = 'ClosureClass'; |
| 232 |
| 233 /// Index into the classData, classList and classEnvironment lists where this |
| 234 /// entity is stored in [JsToFrontendMapImpl]. |
| 235 int classIndex; |
| 236 |
| 237 final Map<Local, JField> localToFieldMap = new Map<Local, JField>(); |
| 238 |
| 239 KernelClosureClass.fromScopeInfo(KernelScopeInfo info) |
| 225 : super.from(info.thisLocal, info); | 240 : super.from(info.thisLocal, info); |
| 226 | 241 |
| 227 // TODO(efortuna): Implement. | 242 // TODO(efortuna): Implement. |
| 228 Local get closureEntity => null; | 243 Local get closureEntity => null; |
| 229 | 244 |
| 230 // TODO(efortuna): Implement. | 245 ClassEntity get closureClassEntity => this; |
| 231 ClassEntity get closureClassEntity => null; | |
| 232 | 246 |
| 233 // TODO(efortuna): Implement. | 247 // TODO(efortuna): Implement. |
| 234 FunctionEntity get callMethod => null; | 248 FunctionEntity get callMethod => null; |
| 235 | 249 |
| 236 // TODO(efortuna): Implement. | 250 // TODO(efortuna): Implement. |
| 237 List<Local> get createdFieldEntities => const <Local>[]; | 251 List<Local> get createdFieldEntities => const <Local>[]; |
| 238 | 252 |
| 239 // TODO(efortuna): Implement. | 253 // TODO(efortuna): Implement. |
| 240 FieldEntity get thisFieldEntity => null; | 254 FieldEntity get thisFieldEntity => null; |
| 241 | 255 |
| 242 // TODO(efortuna): Implement. | 256 // TODO(efortuna): Implement. |
| 243 void forEachCapturedVariable(f(Local from, FieldEntity to)) {} | 257 void forEachCapturedVariable(f(Local from, FieldEntity to)) {} |
| 244 | 258 |
| 245 // TODO(efortuna): Implement. | 259 // TODO(efortuna): Implement. |
| 246 @override | 260 @override |
| 247 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} | 261 void forEachBoxedVariable(f(Local local, FieldEntity field)) {} |
| 248 | 262 |
| 249 // TODO(efortuna): Implement. | 263 // TODO(efortuna): Implement. |
| 250 void forEachFreeVariable(f(Local variable, FieldEntity field)) {} | 264 void forEachFreeVariable(f(Local variable, FieldEntity field)) {} |
| 251 | 265 |
| 252 // TODO(efortuna): Implement. | 266 // TODO(efortuna): Implement. |
| 253 bool isVariableBoxed(Local variable) => false; | 267 bool isVariableBoxed(Local variable) => false; |
| 254 | 268 |
| 255 // TODO(efortuna): Implement. | 269 // TODO(efortuna): Implement. |
| 256 // Why is this closure not actually a closure? Well, to properly call | 270 // Why is this closure not actually a closure? Well, to properly call |
| 257 // ourselves a closure, we need to register the new closure class with the | 271 // ourselves a closure, we need to register the new closure class with the |
| 258 // ClosedWorldRefiner, which currently only takes elements. The change to | 272 // ClosedWorldRefiner, which currently only takes elements. The change to |
| 259 // that (and the subsequent adjustment here) will follow soon. | 273 // that (and the subsequent adjustment here) will follow soon. |
| 260 bool get isClosure => false; | 274 bool get isClosure => false; |
| 275 |
| 276 bool get isAbstract => false; |
| 277 |
| 278 // TODO(efortuna): Talk to Johnni. |
| 279 JLibrary get library => null; |
| 280 |
| 281 String toString() => '${jsElementPrefix}class($name)'; |
| 261 } | 282 } |
| OLD | NEW |