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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/js_backend/codegen/codegen.dart
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index 7d97df0dd884deb1f971ba482dbd71559861cfc8..db5a0f9af0f105990f19ce8c3fe411319ae1042d 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -27,8 +27,10 @@ class CodeGenerator extends tree_ir.Visitor<dynamic, js.Expression> {
final Glue glue;
+ ExecutableElement currentFunction;
+
/// Variables to be hoisted at the top of the current function.
- List<js.VariableDeclaration> variables = <js.VariableDeclaration>[];
+ List<js.VariableInitialization> variables = <js.VariableInitialization>[];
/// Maps variables to their name.
Map<tree_ir.Variable, String> variableNames = <tree_ir.Variable, String>{};
@@ -37,11 +39,13 @@ class CodeGenerator extends tree_ir.Visitor<dynamic, js.Expression> {
Maplet<VariableElement, String> constantNames =
new Maplet<VariableElement, String>();
- /// Variables that have had their declaration created.
+ /// Variables that already have had their declaration created.
+ /// We keep this set, so that we can create declarations for the rest after
+ /// visiting a function body.
Set<tree_ir.Variable> declaredVariables = new Set<tree_ir.Variable>();
/// Variable names that have already been used. Used to avoid name clashes.
- Set<String> usedVariableNames;
+ Set<String> usedVariableNames = new Set<String>();
List<js.Parameter> parameters = new List<js.Parameter>();
List<js.Statement> accumulator = new List<js.Statement>();
@@ -53,13 +57,72 @@ class CodeGenerator extends tree_ir.Visitor<dynamic, js.Expression> {
CodeGenerator(this.glue, this.registry);
void buildFunction(tree_ir.FunctionDefinition function) {
+ currentFunction = function.element;
visitStatement(function.body);
for (tree_ir.Variable parameter in function.parameters) {
- parameters.add(new js.Parameter(variableNames[parameter]));
+ String name = getVariableName(parameter);
+ parameters.add(new js.Parameter(name));
+ declaredVariables.add(parameter);
+ }
+
+ // Some of the variable declarations have already been added
+ // if their first assignment could be pulled into the initializer.
+ // Add the remaining variable declarations now.
+ for (tree_ir.Variable variable in variableNames.keys) {
+ if (!declaredVariables.contains(variable)) {
+ addDeclaration(variable);
+ }
+ }
+ if (variables.length > 0) {
+ // Would be nice to avoid inserting at the beginning of list.
+ accumulator.insert(0, new js.ExpressionStatement(
+ new js.VariableDeclarationList(variables)));
}
body = new js.Block(accumulator);
}
+ void addDeclaration(tree_ir.Variable variable, [js.Expression initializer]) {
+ assert(!declaredVariables.contains(variable));
+ String name = getVariableName(variable);
+ js.VariableInitialization decl = new js.VariableInitialization(
+ new js.VariableDeclaration(name),
+ initializer);
+ declaredVariables.add(variable);
+ variables.add(decl);
+ }
+
+ /// Generates a name for the given variable. First trying with the name of
+ /// the [Variable.element] if it is non-null.
+ String getVariableName(tree_ir.Variable variable) {
+ // TODO(sigurdm): Handle case where the variable belongs to an enclosing
+ // function.
+ if (variable.host.element != currentFunction) giveup(variable);
+
+ // Get the name if we already have one.
+ String name = variableNames[variable];
+ if (name != null) {
+ return name;
+ }
+
+ // Synthesize a variable name that isn't used elsewhere.
+ // The [usedVariableNames] set is shared between nested emitters,
+ // so this also prevents clash with variables in an enclosing/inner scope.
+ // The renaming phase after codegen will further prefix local variables
+ // so they cannot clash with top-level variables or fields.
+ String prefix = variable.element == null ? 'v' : variable.element.name;
+ int counter = 0;
+ name = glue.safeVariableName(variable.element == null
+ ? '$prefix$counter'
+ : variable.element.name);
+ while (!usedVariableNames.add(name)) {
+ ++counter;
+ name = '$prefix$counter';
+ }
+ variableNames[variable] = name;
+
+ return name;
+ }
+
List<js.Expression> visitArguments(List<tree_ir.Expression> arguments) {
return arguments.map(visitExpression).toList();
}
@@ -166,7 +229,7 @@ class CodeGenerator extends tree_ir.Visitor<dynamic, js.Expression> {
@override
js.Expression visitVariable(tree_ir.Variable node) {
- return giveup(node);
+ return new js.VariableUse(getVariableName(node));
// TODO: implement visitVariable
}
@@ -203,8 +266,42 @@ class CodeGenerator extends tree_ir.Visitor<dynamic, js.Expression> {
@override
void visitAssign(tree_ir.Assign node) {
- giveup(node);
- // TODO: implement visitAssign
+ // Try to emit a local function declaration. This is useful for functions
+ // that may occur in expression context, but could not be inlined anywhere.
+ if (node.variable.element is FunctionElement &&
floitsch 2014/11/18 19:00:43 I don't think we need to special case function-exp
+ node.definition is tree_ir.FunctionExpression &&
+ !declaredVariables.contains(node.variable)) {
+ // TODO(sigurdm): implement function expressions.
+ giveup(node.definition);
+ }
+
+ bool isFirstOccurrence = (variableNames[node.variable] == null);
+ bool isDeclaredHere = node.variable.host.element == currentFunction;
+ String name = getVariableName(node.variable);
+ tree_ir.Expression value = node.definition;
+ js.Expression definition = visitExpression(value);
+
+ // Emit a variable declaration if we are required to do so.
+ // 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
+ if (node.isDeclaration) {
+ if (isNullLiteral(definition)) {
+ definition = null;
+ }
+ js.VariableInitialization initialization =
+ new js.VariableInitialization(new js.VariableDeclaration(name),
+ definition);
+ declaredVariables.add(node.variable);
+ accumulator.add(new js.ExpressionStatement(
+ new js.VariableDeclarationList([initialization])));
+ visitStatement(node.next);
+ return;
+ }
+
+ accumulator.add(new js.ExpressionStatement(new js.Assignment(
+ visitVariable(node.variable),
+ definition)));
+ visitStatement(node.next);
+
}
@override
@@ -231,4 +328,7 @@ class CodeGenerator extends tree_ir.Visitor<dynamic, js.Expression> {
accumulator.add(new js.Return(visitExpression(node.value)));
}
}
+
+ bool isNullLiteral(js.Expression exp) => exp is js.LiteralNull;
+
}
« 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