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

Side by Side Diff: pkg/kernel/lib/transformations/closure_conversion.dart

Issue 2526793002: Remove closure_conversion.dart from pkg/kernel. (Closed)
Patch Set: Created 4 years 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/kernel/bin/transform.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library kernel.transformations.closure_conversion;
6
7 import '../ast.dart';
8 import '../core_types.dart';
9 import '../visitor.dart';
10
11 Program transformProgram(Program program) {
12 var captured = new CapturedVariables();
13 captured.visitProgram(program);
14
15 var convert =
16 new ClosureConverter(new CoreTypes(program), captured.variables);
17 return convert.visitProgram(program);
18 }
19
20 class CapturedVariables extends RecursiveVisitor {
21 FunctionNode _currentFunction;
22 final Map<VariableDeclaration, FunctionNode> _function =
23 <VariableDeclaration, FunctionNode>{};
24
25 final Set<VariableDeclaration> variables = new Set<VariableDeclaration>();
26
27 visitFunctionNode(FunctionNode node) {
28 var saved = _currentFunction;
29 _currentFunction = node;
30 node.visitChildren(this);
31 _currentFunction = saved;
32 }
33
34 visitVariableDeclaration(VariableDeclaration node) {
35 _function[node] = _currentFunction;
36 node.visitChildren(this);
37 }
38
39 visitVariableGet(VariableGet node) {
40 if (_function[node.variable] != _currentFunction) {
41 variables.add(node.variable);
42 }
43 node.visitChildren(this);
44 }
45
46 visitVariableSet(VariableSet node) {
47 if (_function[node.variable] != _currentFunction) {
48 variables.add(node.variable);
49 }
50 node.visitChildren(this);
51 }
52 }
53
54 abstract class Context {
55 Expression get expression;
56
57 void extend(VariableDeclaration variable, Expression value);
58
59 Expression lookup(VariableDeclaration variable);
60 Expression assign(VariableDeclaration variable, Expression value);
61
62 Context toClosureContext(VariableDeclaration parameter);
63 }
64
65 class NoContext extends Context {
66 final ClosureConverter converter;
67
68 NoContext(this.converter);
69
70 Expression get expression => new NullLiteral();
71
72 void extend(VariableDeclaration variable, Expression value) {
73 converter.context =
74 new LocalContext(converter, this)..extend(variable, value);
75 }
76
77
78 Expression lookup(VariableDeclaration variable) {
79 throw 'Unbound NoContext.lookup($variable)';
80 }
81
82 Expression assign(VariableDeclaration variable, Expression value) {
83 throw 'Unbound NoContext.assign($variable, ...)';
84 }
85
86 Context toClosureContext(VariableDeclaration parameter) {
87 return new ClosureContext(converter, parameter,
88 <List<VariableDeclaration>>[]);
89 }
90 }
91
92
93 class LocalContext extends Context {
94 final ClosureConverter converter;
95 final Context parent;
96 final VariableDeclaration self;
97 final IntLiteral size;
98 final List<VariableDeclaration> variables = <VariableDeclaration>[];
99
100 LocalContext._internal(this.converter, this.parent, this.self, this.size);
101
102 factory LocalContext(ClosureConverter converter, Context parent) {
103 Class contextClass = converter.internalContextClass;
104 assert(contextClass.constructors.length == 1);
105 IntLiteral zero = new IntLiteral(0);
106 VariableDeclaration declaration =
107 new VariableDeclaration.forValue(
108 new ConstructorInvocation(contextClass.constructors.first,
109 new Arguments(<Expression>[zero])),
110 type: new InterfaceType(contextClass));
111 converter.insert(declaration);
112 converter.insert(new ExpressionStatement(
113 new PropertySet(new VariableGet(declaration),
114 new Name('parent'),
115 parent.expression)));
116
117 return new LocalContext._internal(converter, parent, declaration, zero);
118 }
119
120 Expression get expression => new VariableGet(self);
121
122 void extend(VariableDeclaration variable, Expression value) {
123 converter.insert(
124 new ExpressionStatement(
125 new MethodInvocation(
126 expression,
127 new Name('[]='),
128 new Arguments(
129 <Expression>[new IntLiteral(variables.length), value]))));
130 ++size.value;
131 variables.add(variable);
132 }
133
134 Expression lookup(VariableDeclaration variable) {
135 var index = variables.indexOf(variable);
136 return index == -1
137 ? parent.lookup(variable)
138 : new MethodInvocation(
139 expression,
140 new Name('[]'),
141 new Arguments(<Expression>[new IntLiteral(index)]));
142 }
143
144 Expression assign(VariableDeclaration variable, Expression value) {
145 var index = variables.indexOf(variable);
146 return index == -1
147 ? parent.assign(variable, value)
148 : new MethodInvocation(
149 expression,
150 new Name('[]='),
151 new Arguments(<Expression>[new IntLiteral(index), value]));
152 }
153
154 Context toClosureContext(VariableDeclaration parameter) {
155 List<List<VariableDeclaration>> variabless = <List<VariableDeclaration>>[];
156 var current = this;
157 while (current != null && current is! NoContext) {
158 if (current is LocalContext) {
159 variabless.add(current.variables);
160 current = current.parent;
161 } else if (current is ClosureContext) {
162 variabless.addAll(current.variabless);
163 current = null;
164 } else if (current is LoopContext) {
165 // TODO.
166 current = current.parent;
167 }
168 }
169 return new ClosureContext(converter, parameter, variabless);
170 }
171 }
172
173 class LoopContext {
174 final ClosureConverter converter;
175 final Context parent;
176
177 LoopContext(this.converter, this.parent);
178
179 void extend(VariableDeclaration variable, Expression value) {
180 converter.context =
181 new LocalContext(converter, parent)..extend(variable, value);
182 }
183 }
184
185 class ClosureContext extends Context {
186 final ClosureConverter converter;
187 final VariableDeclaration self;
188 final List<List<VariableDeclaration>> variabless;
189
190 ClosureContext(this.converter, this.self, this.variabless);
191
192 Expression get expression => new VariableGet(self);
193
194 void extend(VariableDeclaration variable, Expression value) {
195 converter.context =
196 new LocalContext(converter, this)..extend(variable, value);
197 }
198
199 Expression lookup(VariableDeclaration variable) {
200 var context = expression;
201 for (var variables in variabless) {
202 var index = variables.indexOf(variable);
203 if (index != -1) {
204 return new MethodInvocation(
205 context,
206 new Name('[]'),
207 new Arguments(<Expression>[new IntLiteral(index)]));
208 }
209 context = new PropertyGet(context, new Name('parent'));
210 }
211 throw 'Unbound ClosureContext.lookup($variable)';
212 }
213
214 Expression assign(VariableDeclaration variable, Expression value) {
215 var context = expression;
216 for (var variables in variabless) {
217 var index = variables.indexOf(variable);
218 if (index != -1) {
219 return new MethodInvocation(
220 context,
221 new Name('[]='),
222 new Arguments(<Expression>[new IntLiteral(index), value]));
223 }
224 context = new PropertyGet(context, new Name('parent'));
225 }
226 throw 'Unbound ClosureContext.lookup($variable)';
227 }
228
229 Context toClosureContext(VariableDeclaration parameter) {
230 return new ClosureContext(converter, parameter, variabless);
231 }
232 }
233
234 class ClosureConverter extends Transformer {
235 final CoreTypes coreTypes;
236 Class internalContextClass;
237 final Set<VariableDeclaration> captured;
238
239 Block _currentBlock;
240 int _insertionIndex = 0;
241
242 Context context;
243
244 ClosureConverter(this.coreTypes, this.captured) {
245 internalContextClass = coreTypes.getCoreClass('dart:_internal', 'Context');
246 }
247
248 void insert(Statement statement) {
249 _currentBlock.statements.insert(_insertionIndex++, statement);
250 statement.parent = _currentBlock;
251 }
252
253 TreeNode visitConstructor(Constructor node) {
254 return node;
255 }
256
257 TreeNode visitFunctionDeclaration(FunctionDeclaration node) {
258 if (captured.contains(node.variable)) {
259 context.extend(node.variable,
260 new FunctionExpression(node.function));
261 }
262
263 Block savedBlock = _currentBlock;
264 int savedIndex = _insertionIndex;
265 Context savedContext = context;
266
267 Statement body = node.function.body;
268 assert(body != null);
269
270 if (body is Block) {
271 _currentBlock = body;
272 } else {
273 _currentBlock = new Block(<Statement>[body]);
274 node.function.body = body.parent = _currentBlock;
275 }
276 _insertionIndex = 0;
277
278 // TODO: This is really the closure, not the context.
279 VariableDeclaration parameter =
280 new VariableDeclaration(null,
281 type: internalContextClass.rawType,
282 isFinal: true);
283 node.function.positionalParameters.insert(0, parameter);
284 parameter.parent = node.function;
285 ++node.function.requiredParameterCount;
286 context = context.toClosureContext(parameter);
287
288 // Don't visit the children, because that included a variable declaration.
289 node.function = node.function.accept(this);
290
291 _currentBlock = savedBlock;
292 _insertionIndex = savedIndex;
293 context = savedContext;
294
295 return captured.contains(node.variable) ? null : node;
296 }
297
298 TreeNode visitFunctionExpression(FunctionExpression node) {
299 Block savedBlock = _currentBlock;
300 int savedIndex = _insertionIndex;
301 Context savedContext = context;
302
303 Statement body = node.function.body;
304 assert(body != null);
305
306 if (body is Block) {
307 _currentBlock = body;
308 } else {
309 _currentBlock = new Block(<Statement>[body]);
310 node.function.body = body.parent = _currentBlock;
311 }
312 _insertionIndex = 0;
313
314 // TODO: This is really the closure, not the context.
315 VariableDeclaration parameter =
316 new VariableDeclaration(null,
317 type: internalContextClass.rawType,
318 isFinal: true);
319 node.function.positionalParameters.insert(0, parameter);
320 parameter.parent = node.function;
321 ++node.function.requiredParameterCount;
322 context = context.toClosureContext(parameter);
323
324 node.transformChildren(this);
325
326 _currentBlock = savedBlock;
327 _insertionIndex = savedIndex;
328 context = savedContext;
329
330 return node;
331 }
332
333 TreeNode visitProcedure(Procedure node) {
334 assert(_currentBlock == null);
335 assert(_insertionIndex == 0);
336 assert(context == null);
337
338 Statement body = node.function.body;
339 if (body == null) return node;
340
341 // Ensure that the body is a block which becomes the current block.
342 if (body is Block) {
343 _currentBlock = body;
344 } else {
345 _currentBlock = new Block(<Statement>[body]);
346 node.function.body = body.parent = _currentBlock;
347 }
348 _insertionIndex = 0;
349
350 // Start with no context. This happens after setting up _currentBlock
351 // so statements can be emitted into _currentBlock if necessary.
352 context = new NoContext(this);
353
354 node.transformChildren(this);
355
356 _currentBlock = null;
357 _insertionIndex = 0;
358 context = null;
359 return node;
360 }
361
362 TreeNode visitLocalInitializer(LocalInitializer node) {
363 assert(!captured.contains(node.variable));
364 node.transformChildren(this);
365 return node;
366 }
367
368 TreeNode visitFunctionNode(FunctionNode node) {
369 transformList(node.typeParameters, this, node);
370
371 void extend(VariableDeclaration parameter) {
372 context.extend(parameter, new VariableGet(parameter));
373 }
374 // TODO: Can parameters contain initializers (e.g., for optional ones) that
375 // need to be closure converted?
376 node.positionalParameters.where(captured.contains).forEach(extend);
377 node.namedParameters.where(captured.contains).forEach(extend);
378
379 assert(node.body != null);
380 node.body = node.body.accept(this);
381 node.body.parent = node;
382 return node;
383 }
384
385 TreeNode visitBlock(Block node) {
386 Block savedBlock;
387 int savedIndex;
388 if (_currentBlock != node) {
389 savedBlock = _currentBlock;
390 savedIndex = _insertionIndex;
391 _currentBlock = node;
392 _insertionIndex = 0;
393 }
394
395 while (_insertionIndex < _currentBlock.statements.length) {
396 assert(_currentBlock == node);
397
398 var original = _currentBlock.statements[_insertionIndex];
399 var transformed = original.accept(this);
400 assert(_currentBlock.statements[_insertionIndex] == original);
401 if (transformed == null) {
402 _currentBlock.statements.removeAt(_insertionIndex);
403 } else {
404 _currentBlock.statements[_insertionIndex++] = transformed;
405 transformed.parent = _currentBlock;
406 }
407 }
408
409 if (savedBlock != null) {
410 _currentBlock = savedBlock;
411 _insertionIndex = savedIndex;
412 }
413 return node;
414 }
415
416 TreeNode visitVariableDeclaration(VariableDeclaration node) {
417 node.transformChildren(this);
418
419 if (!captured.contains(node)) return node;
420 context.extend(node, node.initializer ?? new NullLiteral());
421
422 // TODO(ahe): Return null here when the parent has been correctly
423 // rewritten. So far, only for-in is known to use this return value.
424 return new VariableDeclaration(null, initializer: new InvalidExpression());
425 }
426
427 TreeNode visitVariableGet(VariableGet node) {
428 return captured.contains(node.variable)
429 ? context.lookup(node.variable)
430 : node;
431 }
432
433 TreeNode visitVariableSet(VariableSet node) {
434 node.transformChildren(this);
435
436 return captured.contains(node.variable)
437 ? context.assign(node.variable, node.value)
438 : node;
439 }
440 }
OLDNEW
« no previous file with comments | « pkg/kernel/bin/transform.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698