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 |