Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(325)

Side by Side Diff: pkg/compiler/lib/src/js_model/closure.dart

Issue 2964113004: Revert "Added for-loop variable tracking and regular closures/initializers captured variable tracki… (Closed)
Patch Set: Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/compiler/lib/src/closure.dart ('k') | pkg/compiler/lib/src/js_model/closure_visitors.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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';
11 import '../world.dart'; 11 import '../world.dart';
12 import 'elements.dart';
13 import 'closure_visitors.dart';
14 import 'locals.dart'; 12 import 'locals.dart';
15 13
14 class KernelClosureDataBuilder extends ir.Visitor {
15 final KernelToLocalsMap _localsMap;
16 final KernelClosureRepresentationInfo info;
17
18 bool _inTry = false;
19
20 KernelClosureDataBuilder(this._localsMap, ThisLocal thisLocal)
21 : info = new KernelClosureRepresentationInfo(thisLocal);
22
23 @override
24 defaultNode(ir.Node node) {
25 node.visitChildren(this);
26 }
27
28 @override
29 visitTryCatch(ir.TryCatch node) {
30 bool oldInTry = _inTry;
31 _inTry = true;
32 node.visitChildren(this);
33 _inTry = oldInTry;
34 }
35
36 @override
37 visitTryFinally(ir.TryFinally node) {
38 bool oldInTry = _inTry;
39 _inTry = true;
40 node.visitChildren(this);
41 _inTry = oldInTry;
42 }
43
44 @override
45 visitVariableGet(ir.VariableGet node) {
46 if (_inTry) {
47 info.registerUsedInTryOrSync(_localsMap.getLocal(node.variable));
48 }
49 }
50
51 @override
52 visitVariableSet(ir.VariableSet node) {
53 if (_inTry) {
54 info.registerUsedInTryOrSync(_localsMap.getLocal(node.variable));
55 }
56 node.visitChildren(this);
57 }
58 }
59
16 /// Closure conversion code using our new Entity model. Closure conversion is 60 /// Closure conversion code using our new Entity model. Closure conversion is
17 /// necessary because the semantics of closures are slightly different in Dart 61 /// necessary because the semantics of closures are slightly different in Dart
18 /// than JavaScript. Closure conversion is separated out into two phases: 62 /// than JavaScript. Closure conversion is separated out into two phases:
19 /// generation of a new (temporary) representation to store where variables need 63 /// generation of a new (temporary) representation to store where variables need
20 /// to be hoisted/captured up at another level to re-write the closure, and then 64 /// to be hoisted/captured up at another level to re-write the closure, and then
21 /// the code generation phase where we generate elements and/or instructions to 65 /// the code generation phase where we generate elements and/or instructions to
22 /// represent this new code path. 66 /// represent this new code path.
23 /// 67 ///
24 /// For a general explanation of how closure conversion works at a high level, 68 /// For a general explanation of how closure conversion works at a high level,
25 /// check out: 69 /// check out:
26 /// http://siek.blogspot.com/2012/07/essence-of-closure-conversion.html or 70 /// http://siek.blogspot.com/2012/07/essence-of-closure-conversion.html or
27 /// http://matt.might.net/articles/closure-conversion/. 71 /// http://matt.might.net/articles/closure-conversion/.
28 // TODO(efortuna): Change inheritance hierarchy so that the
29 // ClosureConversionTask doesn't inherit from ClosureTask because it's just a
30 // glorified timer.
31 class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> { 72 class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
32 final KernelToElementMapForBuilding _elementMap; 73 final KernelToElementMapForBuilding _elementMap;
33 final GlobalLocalsMap _globalLocalsMap; 74 final GlobalLocalsMap _globalLocalsMap;
34 Map<ir.Node, ClosureScope> _closureScopeMap = <ir.Node, ClosureScope>{}; 75 Map<Entity, ClosureRepresentationInfo> _infoMap =
35
36 Map<Entity, ClosureRepresentationInfo> _closureRepresentationMap =
37 <Entity, ClosureRepresentationInfo>{}; 76 <Entity, ClosureRepresentationInfo>{};
38 77
39 /// Should only be used at the very beginning to ensure we are looking at the 78 KernelClosureConversionTask(
40 /// right kind of elements. 79 Measurer measurer, this._elementMap, this._globalLocalsMap)
41 // TODO(efortuna): Remove this map once we have one kernel backend strategy.
42 final JsToFrontendMap _kToJElementMap;
43
44 KernelClosureConversionTask(Measurer measurer, this._elementMap,
45 this._kToJElementMap, this._globalLocalsMap)
46 : super(measurer); 80 : super(measurer);
47 81
48 /// The combined steps of generating our intermediate representation of 82 /// The combined steps of generating our intermediate representation of
49 /// closures that need to be rewritten and generating the element model. 83 /// closures that need to be rewritten and generating the element model.
50 /// Ultimately these two steps will be split apart with the second step 84 /// Ultimately these two steps will be split apart with the second step
51 /// happening later in compilation just before codegen. These steps are 85 /// happening later in compilation just before codegen. These steps are
52 /// combined here currently to provide a consistent interface to the rest of 86 /// combined here currently to provide a consistent interface to the rest of
53 /// the compiler until we are ready to separate these phases. 87 /// the compiler until we are ready to separate these phases.
54 @override 88 @override
55 void convertClosures(Iterable<MemberEntity> processedEntities, 89 void convertClosures(Iterable<MemberEntity> processedEntities,
56 ClosedWorldRefiner closedWorldRefiner) { 90 ClosedWorldRefiner closedWorldRefiner) {
57 var closuresToGenerate = <ir.Node, ScopeInfo>{}; 91 // TODO(efortuna): implement.
58 processedEntities.forEach((MemberEntity kEntity) {
59 MemberEntity entity = kEntity;
60 if (_kToJElementMap != null) {
61 entity = _kToJElementMap.toBackendMember(kEntity);
62 }
63 if (entity.isAbstract) return;
64 if (entity.isField && !entity.isInstanceMember) {
65 ir.Field field = _elementMap.getMemberNode(entity);
66 // Skip top-level/static fields without an initializer.
67 if (field.initializer == null) return;
68 }
69 _buildClosureModel(entity, closuresToGenerate, closedWorldRefiner);
70 });
71
72 for (ir.Node node in closuresToGenerate.keys) {
73 _produceSyntheticElements(
74 node, closuresToGenerate[node], closedWorldRefiner);
75 }
76 } 92 }
77 93
78 /// Inspect members and mark if those members capture any state that needs to 94 /// TODO(johnniwinther,efortuna): Implement this.
79 /// be marked as free variables. 95 @override
80 void _buildClosureModel( 96 ClosureScope getClosureScope(ir.Node node) {
81 MemberEntity entity, 97 return const ClosureScope();
82 Map<ir.Node, ScopeInfo> closuresToGenerate,
83 ClosedWorldRefiner closedWorldRefiner) {
84 ir.Node node = _elementMap.getMemberNode(entity);
85 if (_closureScopeMap.keys.contains(node)) return;
86 ClosureScopeBuilder translator = new ClosureScopeBuilder(_closureScopeMap,
87 closuresToGenerate, _globalLocalsMap.getLocalsMap(entity), _elementMap);
88 if (entity.isField) {
89 if (node is ir.Field && node.initializer != null) {
90 translator.translateLazyInitializer(node);
91 }
92 } else {
93 assert(node is ir.Procedure || node is ir.Constructor);
94 translator.translateConstructorOrProcedure(node);
95 }
96 }
97
98 /// Given what variables are captured at each point, construct closure classes
99 /// with fields containing the captured variables to replicate the Dart
100 /// closure semantics in JS.
101 void _produceSyntheticElements(
102 ir.Node node, ScopeInfo info, ClosedWorldRefiner closedWorldRefiner) {
103 Entity entity;
104 KernelClosureClass closureClass =
105 new KernelClosureClass.fromScopeInfo(info);
106 if (node is ir.FunctionNode) {
107 // We want the original declaration where that function is used to point
108 // to the correct closure class.
109 // TODO(efortuna): entity equivalent of element.declaration?
110 node = (node as ir.FunctionNode).parent;
111 _closureRepresentationMap[closureClass.callMethod] = closureClass;
112 }
113
114 if (node is ir.Member) {
115 entity = _elementMap.getMember(node);
116 } else {
117 entity = _elementMap.getLocalFunction(node);
118 }
119 assert(entity != null);
120
121 _closureRepresentationMap[entity] = closureClass;
122 } 98 }
123 99
124 @override 100 @override
125 ScopeInfo getScopeInfo(Entity entity) { 101 ScopeInfo getScopeInfo(Entity entity) {
102 // TODO(efortuna): Specialize this function from the one below.
126 return getClosureRepresentationInfo(entity); 103 return getClosureRepresentationInfo(entity);
127 } 104 }
128 105
106 /// TODO(johnniwinther,efortuna): Implement this.
129 @override 107 @override
130 // TODO(efortuna): Eventually closureScopeMap[node] should always be non-null, 108 LoopClosureScope getLoopClosureScope(ir.Node loopNode) {
131 // and we should just test that with an assert. 109 return const LoopClosureScope();
132 ClosureScope getClosureScope(ir.Node node) => 110 }
133 _closureScopeMap[node] ?? const ClosureScope();
134 111
135 @override 112 @override
136 // TODO(efortuna): Eventually closureScopeMap[node] should always be non-null, 113 ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) {
137 // and we should just test that with an assert. 114 return _infoMap.putIfAbsent(entity, () {
138 LoopClosureScope getLoopClosureScope(ir.Node loopNode) => 115 if (entity is MemberEntity) {
139 _closureScopeMap[node] ?? const LoopClosureScope(); 116 ir.Member node = _elementMap.getMemberNode(entity);
117 ThisLocal thisLocal;
118 if (entity.isInstanceMember) {
119 thisLocal = new ThisLocal(entity);
120 }
121 KernelClosureDataBuilder builder = new KernelClosureDataBuilder(
122 _globalLocalsMap.getLocalsMap(entity), thisLocal);
123 node.accept(builder);
124 return builder.info;
125 }
140 126
141 @override 127 /// TODO(johnniwinther,efortuna): Implement this.
142 // TODO(efortuna): Eventually closureRepresentationMap[node] should always be 128 return const ClosureRepresentationInfo();
143 // non-null, and we should just test that with an assert. 129 });
144 ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) => 130 }
145 _closureRepresentationMap[entity] ?? const ClosureRepresentationInfo();
146 } 131 }
147 132
148 class KernelScopeInfo extends ScopeInfo { 133 // TODO(johnniwinther): Add unittest for the computed
149 final Set<Local> localsUsedInTryOrSync; 134 // [ClosureRepresentationInfo].
150 final Local thisLocal; 135 class KernelClosureRepresentationInfo extends ClosureRepresentationInfo {
151 final Set<Local> boxedVariables = new Set<Local>(); 136 final ThisLocal thisLocal;
137 final Set<Local> _localsUsedInTryOrSync = new Set<Local>();
152 138
153 /// The set of variables that were defined in another scope, but are used in 139 KernelClosureRepresentationInfo(this.thisLocal);
154 /// this scope.
155 Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>();
156 140
157 KernelScopeInfo(this.thisLocal) : localsUsedInTryOrSync = new Set<Local>(); 141 void registerUsedInTryOrSync(Local local) {
158 142 _localsUsedInTryOrSync.add(local);
159 KernelScopeInfo.from(this.thisLocal, KernelScopeInfo info)
160 : localsUsedInTryOrSync = info.variablesUsedInTryOrSync,
161 boxedVariables = info.boxedVariables;
162
163 KernelScopeInfo.withBoxedVariables(this.boxedVariables, this.thisLocal);
164
165 void forEachBoxedVariable(f(Local local, FieldEntity field)) {
166 boxedVariables.forEach((Local l) {
167 // TODO(efortuna): add FieldEntities as created.
168 f(l, null);
169 });
170 } 143 }
171 144
172 bool localIsUsedInTryOrSync(Local variable) => 145 bool variableIsUsedInTryOrSync(Local variable) =>
173 localsUsedInTryOrSync.contains(variable); 146 _localsUsedInTryOrSync.contains(variable);
174 147
175 String toString() { 148 String toString() {
176 StringBuffer sb = new StringBuffer(); 149 StringBuffer sb = new StringBuffer();
177 sb.write('this=$thisLocal,'); 150 sb.write('this=$thisLocal,');
178 sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}'); 151 sb.write('localsUsedInTryOrSync={${_localsUsedInTryOrSync.join(', ')}}');
179 return sb.toString(); 152 return sb.toString();
180 } 153 }
181
182 bool isBoxed(Local variable) => boxedVariables.contains(variable);
183 } 154 }
184
185 class KernelClosureScope extends KernelScopeInfo implements ClosureScope {
186 final Local context;
187
188 KernelClosureScope(Set<Local> boxedVariables, this.context, Local thisLocal)
189 : super.withBoxedVariables(boxedVariables, thisLocal);
190
191 bool get requiresContextBox => boxedVariables.isNotEmpty;
192 }
193
194 class KernelLoopClosureScope extends KernelClosureScope
195 implements LoopClosureScope {
196 final List<Local> boxedLoopVariables;
197
198 KernelLoopClosureScope(Set<Local> boxedVariables, this.boxedLoopVariables,
199 Local context, Local thisLocal)
200 : super(boxedVariables, context, thisLocal);
201
202 bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
203 }
204
205 // TODO(johnniwinther): Add unittest for the computed [ClosureClass].
206 class KernelClosureClass extends KernelScopeInfo
207 implements ClosureRepresentationInfo {
208 KernelClosureClass.fromScopeInfo(ScopeInfo info)
209 : super.from(info.thisLocal, info);
210
211 // TODO(efortuna): Implement.
212 Local get closureEntity => null;
213
214 // TODO(efortuna): Implement.
215 ClassEntity get closureClassEntity => null;
216
217 // TODO(efortuna): Implement.
218 FunctionEntity get callMethod => null;
219
220 // TODO(efortuna): Implement.
221 List<Local> get createdFieldEntities => const <Local>[];
222
223 // TODO(efortuna): Implement.
224 FieldEntity get thisFieldEntity => null;
225
226 // TODO(efortuna): Implement.
227 void forEachCapturedVariable(f(Local from, FieldEntity to)) {}
228
229 // TODO(efortuna): Implement.
230 @override
231 void forEachBoxedVariable(f(Local local, FieldEntity field)) {}
232
233 // TODO(efortuna): Implement.
234 void forEachFreeVariable(f(Local variable, FieldEntity field)) {}
235
236 // TODO(efortuna): Implement.
237 bool isVariableBoxed(Local variable) => false;
238
239 // TODO(efortuna): Implement.
240 // Why is this closure not actually a closure? Well, to properly call
241 // ourselves a closure, we need to register the new closure class with the
242 // ClosedWorldRefiner, which currently only takes elements. The change to
243 // that (and the subsequent adjustment here) will follow soon.
244 bool get isClosure => false;
245 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/closure.dart ('k') | pkg/compiler/lib/src/js_model/closure_visitors.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698