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

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: added test. 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
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 CodegenBailout { 16 class CodegenBailout {
17 final tree_ir.Node node; 17 final tree_ir.Node node;
18 final String reason; 18 final String reason;
19 CodegenBailout(this.node, this.reason); 19 CodegenBailout(this.node, this.reason);
20 String get message { 20 String get message {
21 return 'bailout${node != null ? " on $node" : ""}: $reason'; 21 return 'bailout${node != null ? " on $node" : ""}: $reason';
22 } 22 }
23 } 23 }
24 24
25 class CodeGenerator extends tree_ir.Visitor<dynamic, js.Expression> { 25 class CodeGenerator extends tree_ir.Visitor<dynamic, js.Expression> {
26 final CodegenRegistry registry; 26 final CodegenRegistry registry;
27 27
28 final Glue glue; 28 final Glue glue;
29 29
30 ExecutableElement currentFunction;
31
30 /// Variables to be hoisted at the top of the current function. 32 /// Variables to be hoisted at the top of the current function.
31 List<js.VariableDeclaration> variables = <js.VariableDeclaration>[]; 33 List<js.VariableInitialization> variables = <js.VariableInitialization>[];
32 34
33 /// Maps variables to their name. 35 /// Maps variables to their name.
34 Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{}; 36 Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{};
35 37
36 /// Maps local constants to their name. 38 /// Maps local constants to their name.
37 Maplet<VariableElement, String> constantNames = 39 Maplet<VariableElement, String> constantNames =
38 new Maplet<VariableElement, String>(); 40 new Maplet<VariableElement, String>();
39 41
40 /// Variables that have had their declaration created. 42 /// Variables that already have had their declaration created.
43 /// We keep this set, so that we can create declarations for the rest after
44 /// visiting a function body.
41 Set<tree_ir.Variable> declaredVariables = new Set<tree_ir.Variable>(); 45 Set<tree_ir.Variable> declaredVariables = new Set<tree_ir.Variable>();
42 46
43 /// Variable names that have already been used. Used to avoid name clashes. 47 /// Variable names that have already been used. Used to avoid name clashes.
44 Set<String> usedVariableNames; 48 Set<String> usedVariableNames = new Set<String>();
45 49
46 List<js.Parameter> parameters = new List<js.Parameter>(); 50 List<js.Parameter> parameters = new List<js.Parameter>();
47 List<js.Statement> accumulator = new List<js.Statement>(); 51 List<js.Statement> accumulator = new List<js.Statement>();
48 52
49 js.Block body; 53 js.Block body;
50 54
51 /// Generates JavaScript code for the body of [function]. 55 /// Generates JavaScript code for the body of [function].
52 /// The code will be in [body] and the parameters will be in [parameters]. 56 /// The code will be in [body] and the parameters will be in [parameters].
53 CodeGenerator(this.glue, this.registry); 57 CodeGenerator(this.glue, this.registry);
54 58
55 void buildFunction(tree_ir.FunctionDefinition function) { 59 void buildFunction(tree_ir.FunctionDefinition function) {
60 currentFunction = function.element;
56 visitStatement(function.body); 61 visitStatement(function.body);
57 for (tree_ir.Variable parameter in function.parameters) { 62 for (tree_ir.Variable parameter in function.parameters) {
58 parameters.add(new js.Parameter(variableNames[parameter])); 63 String name = getVariableName(parameter);
64 parameters.add(new js.Parameter(name));
65 declaredVariables.add(parameter);
66 }
67
68 // Some of the variable declarations have already been added
69 // if their first assignment could be pulled into the initializer.
70 // Add the remaining variable declarations now.
71 for (tree_ir.Variable variable in variableNames.keys) {
72 if (!declaredVariables.contains(variable)) {
73 addDeclaration(variable);
74 }
75 }
76 if (variables.length > 0) {
77 // Would be nice to avoid inserting at the beginning of list.
78 accumulator.insert(0, new js.ExpressionStatement(
79 new js.VariableDeclarationList(variables)));
59 } 80 }
60 body = new js.Block(accumulator); 81 body = new js.Block(accumulator);
61 } 82 }
62 83
84 void addDeclaration(tree_ir.Variable variable, [js.Expression initializer]) {
85 assert(!declaredVariables.contains(variable));
86 String name = getVariableName(variable);
87 js.VariableInitialization decl = new js.VariableInitialization(
88 new js.VariableDeclaration(name),
89 initializer);
90 declaredVariables.add(variable);
91 variables.add(decl);
92 }
93
94 /// Generates a name for the given variable. First trying with the name of
95 /// the [Variable.element] if it is non-null.
96 String getVariableName(tree_ir.Variable variable) {
97 // TODO(sigurdm): Handle case where the variable belongs to an enclosing
98 // function.
99 if (variable.host.element != currentFunction) giveup(variable);
100
101 // Get the name if we already have one.
102 String name = variableNames[variable];
103 if (name != null) {
104 return name;
105 }
106
107 // Synthesize a variable name that isn't used elsewhere.
108 // The [usedVariableNames] set is shared between nested emitters,
109 // so this also prevents clash with variables in an enclosing/inner scope.
110 // The renaming phase after codegen will further prefix local variables
111 // so they cannot clash with top-level variables or fields.
112 String prefix = variable.element == null ? 'v' : variable.element.name;
113 int counter = 0;
114 name = glue.safeVariableName(variable.element == null
115 ? '$prefix$counter'
116 : variable.element.name);
117 while (!usedVariableNames.add(name)) {
118 ++counter;
119 name = '$prefix$counter';
120 }
121 variableNames[variable] = name;
122
123 return name;
124 }
125
63 List<js.Expression> visitArguments(List<tree_ir.Expression> arguments) { 126 List<js.Expression> visitArguments(List<tree_ir.Expression> arguments) {
64 return arguments.map(visitExpression).toList(); 127 return arguments.map(visitExpression).toList();
65 } 128 }
66 129
67 giveup(tree_ir.Node node, 130 giveup(tree_ir.Node node,
68 [String reason = 'unimplemented in CodeGenerator']) { 131 [String reason = 'unimplemented in CodeGenerator']) {
69 throw new CodegenBailout(node, reason); 132 throw new CodegenBailout(node, reason);
70 } 133 }
71 134
72 @override 135 @override
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
159 } 222 }
160 223
161 @override 224 @override
162 js.Expression visitTypeOperator(tree_ir.TypeOperator node) { 225 js.Expression visitTypeOperator(tree_ir.TypeOperator node) {
163 return giveup(node); 226 return giveup(node);
164 // TODO: implement visitTypeOperator 227 // TODO: implement visitTypeOperator
165 } 228 }
166 229
167 @override 230 @override
168 js.Expression visitVariable(tree_ir.Variable node) { 231 js.Expression visitVariable(tree_ir.Variable node) {
169 return giveup(node); 232 return new js.VariableUse(getVariableName(node));
170 // TODO: implement visitVariable 233 // TODO: implement visitVariable
171 } 234 }
172 235
173 @override 236 @override
174 void visitContinue(tree_ir.Continue node) { 237 void visitContinue(tree_ir.Continue node) {
175 return giveup(node); 238 return giveup(node);
176 // TODO: implement visitContinue 239 // TODO: implement visitContinue
177 } 240 }
178 241
179 @override 242 @override
(...skipping 16 matching lines...) Expand all
196 } 259 }
197 260
198 @override 261 @override
199 void visitLabeledStatement(tree_ir.LabeledStatement node) { 262 void visitLabeledStatement(tree_ir.LabeledStatement node) {
200 giveup(node); 263 giveup(node);
201 // TODO: implement visitLabeledStatement 264 // TODO: implement visitLabeledStatement
202 } 265 }
203 266
204 @override 267 @override
205 void visitAssign(tree_ir.Assign node) { 268 void visitAssign(tree_ir.Assign node) {
206 giveup(node); 269 // Try to emit a local function declaration. This is useful for functions
207 // TODO: implement visitAssign 270 // that may occur in expression context, but could not be inlined anywhere.
271 if (node.variable.element is FunctionElement &&
floitsch 2014/11/18 19:00:43 I don't think we need to special case function-exp
272 node.definition is tree_ir.FunctionExpression &&
273 !declaredVariables.contains(node.variable)) {
274 // TODO(sigurdm): implement function expressions.
275 giveup(node.definition);
276 }
277
278 bool isFirstOccurrence = (variableNames[node.variable] == null);
279 bool isDeclaredHere = node.variable.host.element == currentFunction;
280 String name = getVariableName(node.variable);
281 tree_ir.Expression value = node.definition;
282 js.Expression definition = visitExpression(value);
283
284 // Emit a variable declaration if we are required to do so.
285 // This is to ensure that a fresh closure variable is created.
floitsch 2014/11/18 19:00:44 That doesn't make sense in the dart2js backend. I
286 if (node.isDeclaration) {
287 if (isNullLiteral(definition)) {
288 definition = null;
289 }
290 js.VariableInitialization initialization =
291 new js.VariableInitialization(new js.VariableDeclaration(name),
292 definition);
293 declaredVariables.add(node.variable);
294 accumulator.add(new js.ExpressionStatement(
295 new js.VariableDeclarationList([initialization])));
296 visitStatement(node.next);
297 return;
298 }
299
300 accumulator.add(new js.ExpressionStatement(new js.Assignment(
301 visitVariable(node.variable),
302 definition)));
303 visitStatement(node.next);
304
208 } 305 }
209 306
210 @override 307 @override
211 void visitBreak(tree_ir.Break node) { 308 void visitBreak(tree_ir.Break node) {
212 giveup(node); 309 giveup(node);
213 // TODO: implement visitBreak 310 // TODO: implement visitBreak
214 } 311 }
215 312
216 @override 313 @override
217 void visitWhileCondition(tree_ir.WhileCondition node) { 314 void visitWhileCondition(tree_ir.WhileCondition node) {
218 giveup(node); 315 giveup(node);
219 // TODO: implement visitWhileCondition 316 // TODO: implement visitWhileCondition
220 } 317 }
221 318
222 @override 319 @override
223 void visitWhileTrue(tree_ir.WhileTrue node) { 320 void visitWhileTrue(tree_ir.WhileTrue node) {
224 giveup(node); 321 giveup(node);
225 // TODO: implement visitWhileTrue 322 // TODO: implement visitWhileTrue
226 } 323 }
227 324
228 @override 325 @override
229 void visitReturn(tree_ir.Return node) { 326 void visitReturn(tree_ir.Return node) {
230 if (node.value != null) { 327 if (node.value != null) {
231 accumulator.add(new js.Return(visitExpression(node.value))); 328 accumulator.add(new js.Return(visitExpression(node.value)));
232 } 329 }
233 } 330 }
331
332 bool isNullLiteral(js.Expression exp) => exp is js.LiteralNull;
333
234 } 334 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart ('k') | pkg/compiler/lib/src/js_backend/codegen/glue.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698