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

Side by Side Diff: pkg/compiler/lib/src/js_backend/codegen/codegen.dart

Issue 726543002: Add support for local variables(including parameters) to cps->js. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | 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
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 library code_generator; 5 library code_generator;
6 6
7 import 'glue.dart'; 7 import 'glue.dart';
8 8
9 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir; 9 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir;
10 import '../../js/js.dart' as js; 10 import '../../js/js.dart' as js;
11 import '../../elements/elements.dart'; 11 import '../../elements/elements.dart';
12 import '../../util/maplet.dart'; 12 import '../../util/maplet.dart';
13 import '../../constants/values.dart'; 13 import '../../constants/values.dart';
14 import '../../dart2jslib.dart'; 14 import '../../dart2jslib.dart';
15 15
16 class CodeGenerator extends tree_ir.Visitor<dynamic, js.Expression> { 16 class CodeGenerator extends tree_ir.Visitor<dynamic, js.Expression> {
17 static const String UNIMPLEMENTED = "Javascript generation aborted"; 17 static const String UNIMPLEMENTED = "Javascript generation aborted";
18 18
19 final CodegenRegistry registry; 19 final CodegenRegistry registry;
20 20
21 final Glue glue; 21 final Glue glue;
22 22
23 ExecutableElement currentFunction;
24
23 /// Variables to be hoisted at the top of the current function. 25 /// Variables to be hoisted at the top of the current function.
24 List<js.VariableDeclaration> variables = <js.VariableDeclaration>[]; 26 List<js.VariableInitialization> variables = <js.VariableInitialization>[];
25 27
26 /// Maps variables to their name. 28 /// Maps variables to their name.
27 Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{}; 29 Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{};
28 30
29 /// Maps local constants to their name. 31 /// Maps local constants to their name.
30 Maplet<VariableElement, String> constantNames = 32 Maplet<VariableElement, String> constantNames =
31 new Maplet<VariableElement, String>(); 33 new Maplet<VariableElement, String>();
32 34
33 /// Variables that have had their declaration created. 35 /// Variables that have had their declaration created.
floitsch 2014/11/13 15:59:32 I'm not sure I understand that comment.
sigurdm 2014/11/18 15:17:46 I tried to improve it.
34 Set<tree_ir.Variable> declaredVariables = new Set<tree_ir.Variable>(); 36 Set<tree_ir.Variable> declaredVariables = new Set<tree_ir.Variable>();
35 37
36 /// Variable names that have already been used. Used to avoid name clashes. 38 /// Variable names that have already been used. Used to avoid name clashes.
37 Set<String> usedVariableNames; 39 Set<String> usedVariableNames = new Set<String>();
38 40
39 List<js.Parameter> parameters = new List<js.Parameter>(); 41 List<js.Parameter> parameters = new List<js.Parameter>();
40 List<js.Statement> accumulator = new List<js.Statement>(); 42 List<js.Statement> accumulator = new List<js.Statement>();
41 43
44 tree_ir.Statement firstStatement;
45
42 js.Block body; 46 js.Block body;
43 47
44 /// Generates JavaScript code for the body of [function]. 48 /// Generates JavaScript code for the body of [function].
45 /// The code will be in [body] and the parameters will be in [parameters]. 49 /// The code will be in [body] and the parameters will be in [parameters].
46 CodeGenerator(this.glue, this.registry); 50 CodeGenerator(this.glue, this.registry);
47 51
48 void buildFunction(tree_ir.FunctionDefinition function) { 52 void buildFunction(tree_ir.FunctionDefinition function) {
53 currentFunction = function.element;
54 firstStatement = function.body;
49 visitStatement(function.body); 55 visitStatement(function.body);
50 for (tree_ir.Variable parameter in function.parameters) { 56 for (tree_ir.Variable parameter in function.parameters) {
51 parameters.add(new js.Parameter(variableNames[parameter])); 57 parameters.add(new js.Parameter(variableNames[parameter]));
58 variableNames[parameter] = parameter.element.name;
floitsch 2014/11/13 15:59:32 We will need to filter names here. There are some
sigurdm 2014/11/18 15:17:46 Yes I think that is the right thing to do. I think
59 usedVariableNames.add(parameter.element.name);
60 declaredVariables.add(parameter);
61 }
62
63
64 // Some of the variable declarations have already been added
65 // if their first assignment could be pulled into the initializer.
floitsch 2014/11/13 15:59:32 Not completely clear what this means.
66 // Add the remaining variable declarations now.
67 for (tree_ir.Variable variable in variableNames.keys) {
68 if (!declaredVariables.contains(variable)) {
69 addDeclaration(variable);
70 }
71 }
72 if (variables.length > 0) {
73 // Would be nice to avoid inserting at the beginning of list.
74 accumulator.insert(0, new js.ExpressionStatement(
75 new js.VariableDeclarationList(variables)));
52 } 76 }
53 body = new js.Block(accumulator); 77 body = new js.Block(accumulator);
54 } 78 }
55 79
80 void addDeclaration(tree_ir.Variable variable, [js.Expression initializer]) {
81 assert(!declaredVariables.contains(variable));
82 String name = getVariableName(variable);
83 js.VariableInitialization decl = new js.VariableInitialization(
84 new js.VariableDeclaration(name),
85 initializer);
86 declaredVariables.add(variable);
87 variables.add(decl);
88 }
89
90 /// Generates a name for the given variable. First trying with the name of
91 /// the [Variable.element] if it is non-null.
92 String getVariableName(tree_ir.Variable variable) {
93 // TODO(sigurdm): Handle case where the variable belongs to an enclosing
94 // function.
95 if (variable.host.element != currentFunction) throw UNIMPLEMENTED;
96
97 // Get the name if we already have one.
98 String name = variableNames[variable];
99 if (name != null) {
100 return name;
101 }
102
103 // Synthesize a variable name that isn't used elsewhere.
104 // The [usedVariableNames] set is shared between nested emitters,
105 // so this also prevents clash with variables in an enclosing/inner scope.
106 // The renaming phase after codegen will further prefix local variables
107 // so they cannot clash with top-level variables or fields.
108 String prefix = variable.element == null ? 'v' : variable.element.name;
109 int counter = 0;
110 name = variable.element == null ? '$prefix$counter' : variable.element.name;
111 while (!usedVariableNames.add(name)) {
112 ++counter;
113 name = '$prefix$counter';
114 }
115 variableNames[variable] = name;
116
117 return name;
118 }
119
56 List<js.Expression> visitArguments(List<tree_ir.Expression> arguments) { 120 List<js.Expression> visitArguments(List<tree_ir.Expression> arguments) {
57 return arguments.map(visitExpression).toList(); 121 return arguments.map(visitExpression).toList();
58 } 122 }
59 123
60 giveup(tree_ir.Node node) { 124 giveup(tree_ir.Node node) {
61 throw UNIMPLEMENTED; 125 throw UNIMPLEMENTED;
62 } 126 }
63 127
64 @override 128 @override
65 js.Expression visitConcatenateStrings(tree_ir.ConcatenateStrings node) { 129 js.Expression visitConcatenateStrings(tree_ir.ConcatenateStrings node) {
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 } 231 }
168 232
169 @override 233 @override
170 js.Expression visitTypeOperator(tree_ir.TypeOperator node) { 234 js.Expression visitTypeOperator(tree_ir.TypeOperator node) {
171 return giveup(node); 235 return giveup(node);
172 // TODO: implement visitTypeOperator 236 // TODO: implement visitTypeOperator
173 } 237 }
174 238
175 @override 239 @override
176 js.Expression visitVariable(tree_ir.Variable node) { 240 js.Expression visitVariable(tree_ir.Variable node) {
177 return giveup(node); 241 return new js.VariableUse(getVariableName(node));
178 // TODO: implement visitVariable 242 // TODO: implement visitVariable
179 } 243 }
180 244
181 @override 245 @override
182 void visitContinue(tree_ir.Continue node) { 246 void visitContinue(tree_ir.Continue node) {
183 return giveup(node); 247 return giveup(node);
184 // TODO: implement visitContinue 248 // TODO: implement visitContinue
185 } 249 }
186 250
187 @override 251 @override
(...skipping 16 matching lines...) Expand all
204 } 268 }
205 269
206 @override 270 @override
207 void visitLabeledStatement(tree_ir.LabeledStatement node) { 271 void visitLabeledStatement(tree_ir.LabeledStatement node) {
208 giveup(node); 272 giveup(node);
209 // TODO: implement visitLabeledStatement 273 // TODO: implement visitLabeledStatement
210 } 274 }
211 275
212 @override 276 @override
213 void visitAssign(tree_ir.Assign node) { 277 void visitAssign(tree_ir.Assign node) {
214 giveup(node); 278 // Try to emit a local function declaration. This is useful for functions
215 // TODO: implement visitAssign 279 // that may occur in expression context, but could not be inlined anywhere.
280 if (node.variable.element is FunctionElement &&
281 node.definition is tree_ir.FunctionExpression &&
282 !declaredVariables.contains(node.variable)) {
283 // TODO(sigurdm): implement function expressions.
284 giveup(node.definition);
285 }
286
287
288 bool isFirstOccurrence = (variableNames[node.variable] == null);
289 bool isDeclaredHere = node.variable.host.element == currentFunction;
290 String name = getVariableName(node.variable);
291 tree_ir.Expression value = node.definition;
292 js.Expression definition = visitExpression(value);
293
294 // Try to pull into initializer.
floitsch 2014/11/13 15:59:32 I don't think we want to do this. We found that: v
sigurdm 2014/11/18 15:17:45 Ok, removed for now.
295 if (firstStatement == node && isFirstOccurrence && isDeclaredHere) {
296 // if (isNullLiteral(definition)) definition = null;
floitsch 2014/11/13 15:59:32 commented code.
sigurdm 2014/11/18 15:17:46 Removed
297 addDeclaration(node.variable, definition);
298 firstStatement = node.next;
299 visitStatement(node.next);
300 return;
301 }
302
303 // Emit a variable declaration if we are required to do so.
304 // This is to ensure that a fresh closure variable is created.
305 if (node.isDeclaration) {
306 assert(isFirstOccurrence);
307 assert(isDeclaredHere);
308 // if (isNullLiteral(definition)) definition = null;
floitsch 2014/11/13 15:59:32 commented code.
sigurdm 2014/11/18 15:17:46 Done.
309 js.VariableInitialization decl =
310 new js.VariableInitialization(new js.VariableDeclaration(name),
311 definition);
312 declaredVariables.add(node.variable);
313 accumulator.add(new js.ExpressionStatement(
314 new js.VariableDeclarationList([decl])));
315 visitStatement(node.next);
floitsch 2014/11/13 15:59:32 I'm surprised that the visit-functions have to tri
sigurdm 2014/11/18 15:17:46 Yes - this is a side effect of how the tree IR is
316 return;
317 }
318
319 accumulator.add(new js.ExpressionStatement(new js.Assignment(
320 visitVariable(node.variable),
321 definition)));
322 visitStatement(node.next);
323
216 } 324 }
217 325
218 @override 326 @override
219 void visitBreak(tree_ir.Break node) { 327 void visitBreak(tree_ir.Break node) {
220 giveup(node); 328 giveup(node);
221 // TODO: implement visitBreak 329 // TODO: implement visitBreak
222 } 330 }
223 331
224 @override 332 @override
225 void visitWhileCondition(tree_ir.WhileCondition node) { 333 void visitWhileCondition(tree_ir.WhileCondition node) {
226 giveup(node); 334 giveup(node);
227 // TODO: implement visitWhileCondition 335 // TODO: implement visitWhileCondition
228 } 336 }
229 337
230 @override 338 @override
231 void visitWhileTrue(tree_ir.WhileTrue node) { 339 void visitWhileTrue(tree_ir.WhileTrue node) {
232 giveup(node); 340 giveup(node);
233 // TODO: implement visitWhileTrue 341 // TODO: implement visitWhileTrue
234 } 342 }
235 343
236 @override 344 @override
237 void visitReturn(tree_ir.Return node) { 345 void visitReturn(tree_ir.Return node) {
238 if (node.value != null) { 346 if (node.value != null) {
239 accumulator.add(new js.Return(visitExpression(node.value))); 347 accumulator.add(new js.Return(visitExpression(node.value)));
240 } 348 }
241 } 349 }
242 } 350 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698