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

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

Issue 1608483004: dart2js: Flatten the code generation visitor a little bit. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 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 | « 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 '../../closure.dart' show 9 import '../../closure.dart' show
10 ClosureClassElement; 10 ClosureClassElement;
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 final Map<tree_ir.Label, String> labelNames = <tree_ir.Label, String>{}; 84 final Map<tree_ir.Label, String> labelNames = <tree_ir.Label, String>{};
85 85
86 List<js.Statement> accumulator = new List<js.Statement>(); 86 List<js.Statement> accumulator = new List<js.Statement>();
87 87
88 CodeGenerator(this.glue, this.registry); 88 CodeGenerator(this.glue, this.registry);
89 89
90 /// Generates JavaScript code for the body of [function]. 90 /// Generates JavaScript code for the body of [function].
91 js.Fun buildFunction(tree_ir.FunctionDefinition function) { 91 js.Fun buildFunction(tree_ir.FunctionDefinition function) {
92 registerDefaultParameterValues(function.element); 92 registerDefaultParameterValues(function.element);
93 currentFunction = function.element; 93 currentFunction = function.element;
94 visitStatement(function.body); 94 tree_ir.Statement statement = function.body;
95 while (statement != null) {
96 statement = visitStatement(statement);
97 }
95 98
96 List<js.Parameter> parameters = new List<js.Parameter>(); 99 List<js.Parameter> parameters = new List<js.Parameter>();
97 Set<tree_ir.Variable> parameterSet = new Set<tree_ir.Variable>(); 100 Set<tree_ir.Variable> parameterSet = new Set<tree_ir.Variable>();
98 Set<String> declaredVariables = new Set<String>(); 101 Set<String> declaredVariables = new Set<String>();
99 102
100 for (tree_ir.Variable parameter in function.parameters) { 103 for (tree_ir.Variable parameter in function.parameters) {
101 String name = getVariableName(parameter); 104 String name = getVariableName(parameter);
102 parameters.add(new js.Parameter(name)); 105 parameters.add(new js.Parameter(name));
103 parameterSet.add(parameter); 106 parameterSet.add(parameter);
104 declaredVariables.add(name); 107 declaredVariables.add(name);
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 ++counter; 214 ++counter;
212 name = '$prefix$counter'; 215 name = '$prefix$counter';
213 } 216 }
214 variableNames[variable] = name; 217 variableNames[variable] = name;
215 218
216 return name; 219 return name;
217 } 220 }
218 221
219 List<js.Expression> visitExpressionList( 222 List<js.Expression> visitExpressionList(
220 List<tree_ir.Expression> expressions) { 223 List<tree_ir.Expression> expressions) {
221 return new List<js.Expression>.generate(expressions.length, 224 List<js.Expression> result = new List<js.Expression>(expressions.length);
222 (int index) => visitExpression(expressions[index]), 225 for (int i = 0; i < expressions.length; ++i) {
223 growable: false); 226 result[i] = visitExpression(expressions[i]);
227 }
228 return result;
224 } 229 }
225 230
226 giveup(tree_ir.Node node, 231 giveup(tree_ir.Node node,
227 [String reason = 'unimplemented in CodeGenerator']) { 232 [String reason = 'unimplemented in CodeGenerator']) {
228 throw new CodegenBailout(node, reason); 233 throw new CodegenBailout(node, reason);
229 } 234 }
230 235
231 @override 236 @override
232 js.Expression visitConditional(tree_ir.Conditional node) { 237 js.Expression visitConditional(tree_ir.Conditional node) {
233 return new js.Conditional( 238 return new js.Conditional(
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after
611 } else if (isShortContinue(node)) { 616 } else if (isShortContinue(node)) {
612 // An unlabeled continue is better than a labeled break. 617 // An unlabeled continue is better than a labeled break.
613 shortContinue.use(); 618 shortContinue.use();
614 accumulator.add(new js.Continue(null)); 619 accumulator.add(new js.Continue(null));
615 } else { 620 } else {
616 accumulator.add(new js.Break(makeLabel(node.target))); 621 accumulator.add(new js.Break(makeLabel(node.target)));
617 } 622 }
618 } 623 }
619 624
620 @override 625 @override
621 void visitExpressionStatement(tree_ir.ExpressionStatement node) { 626 visitExpressionStatement(tree_ir.ExpressionStatement node) {
622 js.Expression exp = visitExpression(node.expression); 627 js.Expression exp = visitExpression(node.expression);
623 if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) { 628 if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) {
624 // Emit as 'return exp' to assist local analysis in the VM. 629 // Emit as 'return exp' to assist local analysis in the VM.
625 accumulator.add(new js.Return(exp)); 630 accumulator.add(new js.Return(exp));
631 return null;
626 } else { 632 } else {
627 accumulator.add(new js.ExpressionStatement(exp)); 633 accumulator.add(new js.ExpressionStatement(exp));
628 visitStatement(node.next); 634 return node.next;
629 } 635 }
630 } 636 }
631 637
632 bool isNullReturn(tree_ir.Statement node) { 638 bool isNullReturn(tree_ir.Statement node) {
633 return node is tree_ir.Return && isNull(node.value); 639 return node is tree_ir.Return && isNull(node.value);
634 } 640 }
635 641
636 bool isEndOfMethod(tree_ir.Statement node) { 642 bool isEndOfMethod(tree_ir.Statement node) {
637 return isNullReturn(node) || 643 return isNullReturn(node) ||
638 node is tree_ir.Break && isNullReturn(node.target.binding.next); 644 node is tree_ir.Break && isNullReturn(node.target.binding.next);
639 } 645 }
640 646
641 @override 647 @override
642 void visitIf(tree_ir.If node) { 648 visitIf(tree_ir.If node) {
643 js.Expression condition = visitExpression(node.condition); 649 js.Expression condition = visitExpression(node.condition);
644 int usesBefore = fallthrough.useCount; 650 int usesBefore = fallthrough.useCount;
645 // Unless the 'else' part ends the method. make sure to terminate any 651 // Unless the 'else' part ends the method. make sure to terminate any
646 // uncompletable code paths in the 'then' part. 652 // uncompletable code paths in the 'then' part.
647 emitUnreachableAsReturn.add(!isEndOfMethod(node.elseStatement)); 653 emitUnreachableAsReturn.add(!isEndOfMethod(node.elseStatement));
648 js.Statement thenBody = buildBodyStatement(node.thenStatement); 654 js.Statement thenBody = buildBodyStatement(node.thenStatement);
649 emitUnreachableAsReturn.removeLast(); 655 emitUnreachableAsReturn.removeLast();
650 bool thenHasFallthrough = (fallthrough.useCount > usesBefore); 656 bool thenHasFallthrough = (fallthrough.useCount > usesBefore);
651 if (thenHasFallthrough) { 657 if (thenHasFallthrough) {
652 js.Statement elseBody = buildBodyStatement(node.elseStatement); 658 js.Statement elseBody = buildBodyStatement(node.elseStatement);
653 accumulator.add(new js.If(condition, thenBody, elseBody)); 659 accumulator.add(new js.If(condition, thenBody, elseBody));
660 return null;
654 } else { 661 } else {
655 // The 'then' body cannot complete normally, so emit a short 'if' 662 // The 'then' body cannot complete normally, so emit a short 'if'
656 // and put the 'else' body after it. 663 // and put the 'else' body after it.
657 accumulator.add(new js.If.noElse(condition, thenBody)); 664 accumulator.add(new js.If.noElse(condition, thenBody));
658 visitStatement(node.elseStatement); 665 return node.elseStatement;
659 } 666 }
660 } 667 }
661 668
662 @override 669 @override
663 void visitLabeledStatement(tree_ir.LabeledStatement node) { 670 visitLabeledStatement(tree_ir.LabeledStatement node) {
664 fallthrough.push(node.next); 671 fallthrough.push(node.next);
665 js.Statement body = buildBodyStatement(node.body); 672 js.Statement body = buildBodyStatement(node.body);
666 fallthrough.pop(); 673 fallthrough.pop();
667 accumulator.add(insertLabel(node.label, body)); 674 accumulator.add(insertLabel(node.label, body));
668 visitStatement(node.next); 675 return node.next;
669 } 676 }
670 677
671 /// Creates a name for [label] if it does not already have one. 678 /// Creates a name for [label] if it does not already have one.
672 /// 679 ///
673 /// This also marks the label as being used. 680 /// This also marks the label as being used.
674 String makeLabel(tree_ir.Label label) { 681 String makeLabel(tree_ir.Label label) {
675 return labelNames.putIfAbsent(label, () => 'L${labelNames.length}'); 682 return labelNames.putIfAbsent(label, () => 'L${labelNames.length}');
676 } 683 }
677 684
678 /// Wraps a node in a labeled statement unless the label is unused. 685 /// Wraps a node in a labeled statement unless the label is unused.
(...skipping 11 matching lines...) Expand all
690 if (accumulator.length == 1) { 697 if (accumulator.length == 1) {
691 return accumulator.single; 698 return accumulator.single;
692 } 699 }
693 return new js.Block(accumulator); 700 return new js.Block(accumulator);
694 } 701 }
695 702
696 /// Builds a nested statement. 703 /// Builds a nested statement.
697 js.Statement buildBodyStatement(tree_ir.Statement statement) { 704 js.Statement buildBodyStatement(tree_ir.Statement statement) {
698 List<js.Statement> savedAccumulator = accumulator; 705 List<js.Statement> savedAccumulator = accumulator;
699 accumulator = <js.Statement>[]; 706 accumulator = <js.Statement>[];
700 visitStatement(statement); 707 while (statement != null) {
708 statement = visitStatement(statement);
709 }
701 js.Statement result = _bodyAsStatement(); 710 js.Statement result = _bodyAsStatement();
702 accumulator = savedAccumulator; 711 accumulator = savedAccumulator;
703 return result; 712 return result;
704 } 713 }
705 714
706 js.Block buildBodyBlock(tree_ir.Statement statement) { 715 js.Block buildBodyBlock(tree_ir.Statement statement) {
707 List<js.Statement> savedAccumulator = accumulator; 716 List<js.Statement> savedAccumulator = accumulator;
708 accumulator = <js.Statement>[]; 717 accumulator = <js.Statement>[];
709 visitStatement(statement); 718 while (statement != null) {
719 statement = visitStatement(statement);
720 }
710 js.Statement result = new js.Block(accumulator); 721 js.Statement result = new js.Block(accumulator);
711 accumulator = savedAccumulator; 722 accumulator = savedAccumulator;
712 return result; 723 return result;
713 } 724 }
714 725
715 js.Expression makeSequence(List<tree_ir.Expression> list) { 726 js.Expression makeSequence(List<tree_ir.Expression> list) {
716 return list.map(visitExpression).reduce((x,y) => new js.Binary(',', x, y)); 727 return list.map(visitExpression).reduce((x,y) => new js.Binary(',', x, y));
717 } 728 }
718 729
719 @override 730 @override
720 void visitFor(tree_ir.For node) { 731 visitFor(tree_ir.For node) {
721 js.Expression condition = visitExpression(node.condition); 732 js.Expression condition = visitExpression(node.condition);
722 shortBreak.push(node.next); 733 shortBreak.push(node.next);
723 shortContinue.push(node); 734 shortContinue.push(node);
724 fallthrough.push(node); 735 fallthrough.push(node);
725 emitUnreachableAsReturn.add(true); 736 emitUnreachableAsReturn.add(true);
726 js.Statement body = buildBodyStatement(node.body); 737 js.Statement body = buildBodyStatement(node.body);
727 emitUnreachableAsReturn.removeLast(); 738 emitUnreachableAsReturn.removeLast();
728 fallthrough.pop(); 739 fallthrough.pop();
729 shortContinue.pop(); 740 shortContinue.pop();
730 shortBreak.pop(); 741 shortBreak.pop();
731 js.Statement loopNode; 742 js.Statement loopNode;
732 if (node.updates.isEmpty) { 743 if (node.updates.isEmpty) {
733 loopNode = new js.While(condition, body); 744 loopNode = new js.While(condition, body);
734 } else { // Compile as a for loop. 745 } else { // Compile as a for loop.
735 js.Expression init; 746 js.Expression init;
736 if (accumulator.isNotEmpty && 747 if (accumulator.isNotEmpty &&
737 accumulator.last is js.ExpressionStatement) { 748 accumulator.last is js.ExpressionStatement) {
738 // Take the preceding expression from the accumulator and use 749 // Take the preceding expression from the accumulator and use
739 // it as the initializer expression. 750 // it as the initializer expression.
740 js.ExpressionStatement initStmt = accumulator.removeLast(); 751 js.ExpressionStatement initStmt = accumulator.removeLast();
741 init = initStmt.expression; 752 init = initStmt.expression;
742 } 753 }
743 js.Expression update = makeSequence(node.updates); 754 js.Expression update = makeSequence(node.updates);
744 loopNode = new js.For(init, condition, update, body); 755 loopNode = new js.For(init, condition, update, body);
745 } 756 }
746 accumulator.add(insertLabel(node.label, loopNode)); 757 accumulator.add(insertLabel(node.label, loopNode));
747 visitStatement(node.next); 758 return node.next;
748 } 759 }
749 760
750 @override 761 @override
751 void visitWhileTrue(tree_ir.WhileTrue node) { 762 void visitWhileTrue(tree_ir.WhileTrue node) {
752 // A short break in the while will jump to the current fallthrough target. 763 // A short break in the while will jump to the current fallthrough target.
753 shortBreak.push(fallthrough.target); 764 shortBreak.push(fallthrough.target);
754 shortContinue.push(node); 765 shortContinue.push(node);
755 fallthrough.push(node); 766 fallthrough.push(node);
756 emitUnreachableAsReturn.add(true); 767 emitUnreachableAsReturn.add(true);
757 js.Statement jsBody = buildBodyStatement(node.body); 768 js.Statement jsBody = buildBodyStatement(node.body);
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
1008 js.Expression visitForeignExpression(tree_ir.ForeignExpression node) { 1019 js.Expression visitForeignExpression(tree_ir.ForeignExpression node) {
1009 return handleForeignCode(node); 1020 return handleForeignCode(node);
1010 } 1021 }
1011 1022
1012 @override 1023 @override
1013 void visitForeignStatement(tree_ir.ForeignStatement node) { 1024 void visitForeignStatement(tree_ir.ForeignStatement node) {
1014 accumulator.add(handleForeignCode(node)); 1025 accumulator.add(handleForeignCode(node));
1015 } 1026 }
1016 1027
1017 @override 1028 @override
1018 void visitYield(tree_ir.Yield node) { 1029 visitYield(tree_ir.Yield node) {
1019 js.Expression value = visitExpression(node.input); 1030 js.Expression value = visitExpression(node.input);
1020 accumulator.add(new js.DartYield(value, node.hasStar)); 1031 accumulator.add(new js.DartYield(value, node.hasStar));
1021 visitStatement(node.next); 1032 return node.next;
1022 } 1033 }
1023 1034
1024 @override 1035 @override
1025 void visitNullCheck(tree_ir.NullCheck node) { 1036 visitNullCheck(tree_ir.NullCheck node) {
1026 js.Expression value = visitExpression(node.value); 1037 js.Expression value = visitExpression(node.value);
1027 // TODO(sra): Try to use the selector even when [useSelector] is false. The 1038 // TODO(sra): Try to use the selector even when [useSelector] is false. The
1028 // reason we use 'toString' is that it is always defined so avoids a slow 1039 // reason we use 'toString' is that it is always defined so avoids a slow
1029 // lookup (in V8) of an absent property. We could use the property for the 1040 // lookup (in V8) of an absent property. We could use the property for the
1030 // selector if we knew it was present. The property is present if the 1041 // selector if we knew it was present. The property is present if the
1031 // associated method was not inlined away, or if there is a noSuchMethod 1042 // associated method was not inlined away, or if there is a noSuchMethod
1032 // hook for that selector. We don't know these things here, but the decision 1043 // hook for that selector. We don't know these things here, but the decision
1033 // could be deferred by creating a deferred property that was resolved after 1044 // could be deferred by creating a deferred property that was resolved after
1034 // codegen. 1045 // codegen.
1035 js.Expression access = node.selector != null && node.useSelector 1046 js.Expression access = node.selector != null && node.useSelector
1036 ? js.js('#.#', [value, glue.invocationName(node.selector)]) 1047 ? js.js('#.#', [value, glue.invocationName(node.selector)])
1037 : js.js('#.toString', [value]); 1048 : js.js('#.toString', [value]);
1038 if (node.condition != null) { 1049 if (node.condition != null) {
1039 js.Expression condition = visitExpression(node.condition); 1050 js.Expression condition = visitExpression(node.condition);
1040 js.Statement body = isNullReturn(node.next) 1051 js.Statement body = isNullReturn(node.next)
1041 ? new js.ExpressionStatement(access) 1052 ? new js.ExpressionStatement(access)
1042 : new js.Return(access); 1053 : new js.Return(access);
1043 accumulator.add(new js.If.noElse(condition, body)); 1054 accumulator.add(new js.If.noElse(condition, body));
1044 } else { 1055 } else {
1045 accumulator.add(new js.ExpressionStatement(access)); 1056 accumulator.add(new js.ExpressionStatement(access));
1046 } 1057 }
1047 visitStatement(node.next); 1058 return node.next;
1048 } 1059 }
1049 1060
1050 @override 1061 @override
1051 js.Expression visitApplyBuiltinOperator(tree_ir.ApplyBuiltinOperator node) { 1062 js.Expression visitApplyBuiltinOperator(tree_ir.ApplyBuiltinOperator node) {
1052 List<js.Expression> args = visitExpressionList(node.arguments); 1063 List<js.Expression> args = visitExpressionList(node.arguments);
1053 switch (node.operator) { 1064 switch (node.operator) {
1054 case BuiltinOperator.NumAdd: 1065 case BuiltinOperator.NumAdd:
1055 return new js.Binary('+', args[0], args[1]); 1066 return new js.Binary('+', args[0], args[1]);
1056 case BuiltinOperator.NumSubtract: 1067 case BuiltinOperator.NumSubtract:
1057 return new js.Binary('-', args[0], args[1]); 1068 return new js.Binary('-', args[0], args[1]);
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
1225 void registerDefaultParameterValues(ExecutableElement element) { 1236 void registerDefaultParameterValues(ExecutableElement element) {
1226 if (element is! FunctionElement) return; 1237 if (element is! FunctionElement) return;
1227 FunctionElement function = element; 1238 FunctionElement function = element;
1228 if (function.isStatic) return; // Defaults are inlined at call sites. 1239 if (function.isStatic) return; // Defaults are inlined at call sites.
1229 function.functionSignature.forEachOptionalParameter((param) { 1240 function.functionSignature.forEachOptionalParameter((param) {
1230 ConstantValue constant = glue.getDefaultParameterValue(param); 1241 ConstantValue constant = glue.getDefaultParameterValue(param);
1231 registry.registerCompileTimeConstant(constant); 1242 registry.registerCompileTimeConstant(constant);
1232 }); 1243 });
1233 } 1244 }
1234 } 1245 }
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