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 |