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 |