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

Side by Side Diff: pkg/compiler/lib/src/ssa/builder_kernel.dart

Issue 2637483002: Implement switch statement, without the "complex switch statement" (aka switch statement with conti… (Closed)
Patch Set: . Created 3 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
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 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 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 import 'package:kernel/ast.dart' as ir; 5 import 'package:kernel/ast.dart' as ir;
6 6
7 import '../closure.dart'; 7 import '../closure.dart';
8 import '../common.dart'; 8 import '../common.dart';
9 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; 9 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
10 import '../common/names.dart'; 10 import '../common/names.dart';
(...skipping 22 matching lines...) Expand all
33 import '../universe/use.dart' show StaticUse; 33 import '../universe/use.dart' show StaticUse;
34 import '../world.dart'; 34 import '../world.dart';
35 import 'graph_builder.dart'; 35 import 'graph_builder.dart';
36 import 'jump_handler.dart'; 36 import 'jump_handler.dart';
37 import 'kernel_ast_adapter.dart'; 37 import 'kernel_ast_adapter.dart';
38 import 'kernel_string_builder.dart'; 38 import 'kernel_string_builder.dart';
39 import 'locals_handler.dart'; 39 import 'locals_handler.dart';
40 import 'loop_handler.dart'; 40 import 'loop_handler.dart';
41 import 'nodes.dart'; 41 import 'nodes.dart';
42 import 'ssa_branch_builder.dart'; 42 import 'ssa_branch_builder.dart';
43 import 'switch_handler.dart';
43 import 'type_builder.dart'; 44 import 'type_builder.dart';
44 import 'types.dart' show TypeMaskFactory; 45 import 'types.dart' show TypeMaskFactory;
45 46
46 class SsaKernelBuilderTask extends CompilerTask { 47 class SsaKernelBuilderTask extends CompilerTask {
47 final JavaScriptBackend backend; 48 final JavaScriptBackend backend;
48 final SourceInformationStrategy sourceInformationFactory; 49 final SourceInformationStrategy sourceInformationFactory;
49 50
50 String get name => 'SSA kernel builder'; 51 String get name => 'SSA kernel builder';
51 52
52 SsaKernelBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) 53 SsaKernelBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory)
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after
551 // Empty statement adds no instructions to current block. 552 // Empty statement adds no instructions to current block.
552 } 553 }
553 554
554 @override 555 @override
555 void visitExpressionStatement(ir.ExpressionStatement exprStatement) { 556 void visitExpressionStatement(ir.ExpressionStatement exprStatement) {
556 if (!isReachable) return; 557 if (!isReachable) return;
557 ir.Expression expression = exprStatement.expression; 558 ir.Expression expression = exprStatement.expression;
558 if (expression is ir.Throw) { 559 if (expression is ir.Throw) {
559 // TODO(sra): Prevent generating a statement when inlining. 560 // TODO(sra): Prevent generating a statement when inlining.
560 _visitThrowExpression(expression.expression); 561 _visitThrowExpression(expression.expression);
562 handleInTryStatement();
561 closeAndGotoExit(new HThrow(pop(), null)); 563 closeAndGotoExit(new HThrow(pop(), null));
562 } else { 564 } else {
563 expression.accept(this); 565 expression.accept(this);
564 pop(); 566 pop();
565 } 567 }
566 } 568 }
567 569
568 @override 570 @override
569 void visitReturnStatement(ir.ReturnStatement returnStatement) { 571 void visitReturnStatement(ir.ReturnStatement returnStatement) {
570 HInstruction value; 572 HInstruction value;
571 if (returnStatement.expression == null) { 573 if (returnStatement.expression == null) {
572 value = graph.addConstantNull(closedWorld); 574 value = graph.addConstantNull(closedWorld);
573 } else { 575 } else {
574 assert(_targetFunction != null && _targetFunction is ir.FunctionNode); 576 assert(_targetFunction != null && _targetFunction is ir.FunctionNode);
575 returnStatement.expression.accept(this); 577 returnStatement.expression.accept(this);
576 value = typeBuilder.potentiallyCheckOrTrustType( 578 value = typeBuilder.potentiallyCheckOrTrustType(
577 pop(), astAdapter.getFunctionReturnType(_targetFunction)); 579 pop(), astAdapter.getFunctionReturnType(_targetFunction));
578 } 580 }
579 // TODO(het): Add source information 581 // TODO(het): Add source information
582 handleInTryStatement();
580 // TODO(het): Set a return value instead of closing the function when we 583 // TODO(het): Set a return value instead of closing the function when we
581 // support inlining. 584 // support inlining.
582 closeAndGotoExit(new HReturn(value, null)); 585 closeAndGotoExit(new HReturn(value, null));
583 } 586 }
584 587
585 @override 588 @override
586 void visitForStatement(ir.ForStatement forStatement) { 589 void visitForStatement(ir.ForStatement forStatement) {
587 assert(isReachable); 590 assert(isReachable);
588 assert(forStatement.body != null); 591 assert(forStatement.body != null);
589 void buildInitializer() { 592 void buildInitializer() {
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
813 @override 816 @override
814 visitDoStatement(ir.DoStatement doStatement) { 817 visitDoStatement(ir.DoStatement doStatement) {
815 // TODO(efortuna): I think this can be rewritten using 818 // TODO(efortuna): I think this can be rewritten using
816 // LoopHandler.handleLoop with some tricks about when the "update" happens. 819 // LoopHandler.handleLoop with some tricks about when the "update" happens.
817 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); 820 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler);
818 localsHandler.startLoop(astAdapter.getNode(doStatement)); 821 localsHandler.startLoop(astAdapter.getNode(doStatement));
819 JumpHandler jumpHandler = loopHandler.beginLoopHeader(doStatement); 822 JumpHandler jumpHandler = loopHandler.beginLoopHeader(doStatement);
820 HLoopInformation loopInfo = current.loopInformation; 823 HLoopInformation loopInfo = current.loopInformation;
821 HBasicBlock loopEntryBlock = current; 824 HBasicBlock loopEntryBlock = current;
822 HBasicBlock bodyEntryBlock = current; 825 HBasicBlock bodyEntryBlock = current;
823 JumpTarget target = astAdapter.elements 826 JumpTarget target = astAdapter.getJumpTarget(doStatement);
824 .getTargetDefinition(astAdapter.getNode(doStatement));
825 bool hasContinues = target != null && target.isContinueTarget; 827 bool hasContinues = target != null && target.isContinueTarget;
826 if (hasContinues) { 828 if (hasContinues) {
827 // Add extra block to hang labels on. 829 // Add extra block to hang labels on.
828 // It doesn't currently work if they are on the same block as the 830 // It doesn't currently work if they are on the same block as the
829 // HLoopInfo. The handling of HLabeledBlockInformation will visit a 831 // HLoopInfo. The handling of HLabeledBlockInformation will visit a
830 // SubGraph that starts at the same block again, so the HLoopInfo is 832 // SubGraph that starts at the same block again, so the HLoopInfo is
831 // either handled twice, or it's handled after the labeled block info, 833 // either handled twice, or it's handled after the labeled block info,
832 // both of which generate the wrong code. 834 // both of which generate the wrong code.
833 // Using a separate block is just a simple workaround. 835 // Using a separate block is just a simple workaround.
834 bodyEntryBlock = openNewBlock(); 836 bodyEntryBlock = openNewBlock();
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
926 loopEntryBlock.loopInformation = null; 928 loopEntryBlock.loopInformation = null;
927 929
928 if (jumpHandler.hasAnyBreak()) { 930 if (jumpHandler.hasAnyBreak()) {
929 // Null branchBlock because the body of the do-while loop always aborts, 931 // Null branchBlock because the body of the do-while loop always aborts,
930 // so we never get to the condition. 932 // so we never get to the condition.
931 loopHandler.endLoop(loopEntryBlock, null, jumpHandler, localsHandler); 933 loopHandler.endLoop(loopEntryBlock, null, jumpHandler, localsHandler);
932 934
933 // Since the body of the loop has a break, we attach a synthesized label 935 // Since the body of the loop has a break, we attach a synthesized label
934 // to the body. 936 // to the body.
935 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); 937 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock);
936 JumpTarget target = astAdapter.elements 938 JumpTarget target = astAdapter.getJumpTarget(doStatement);
937 .getTargetDefinition(astAdapter.getNode(doStatement));
938 LabelDefinition label = target.addLabel(null, 'loop'); 939 LabelDefinition label = target.addLabel(null, 'loop');
939 label.setBreakTarget(); 940 label.setBreakTarget();
940 HLabeledBlockInformation info = new HLabeledBlockInformation( 941 HLabeledBlockInformation info = new HLabeledBlockInformation(
941 new HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]); 942 new HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]);
942 loopEntryBlock.setBlockFlow(info, current); 943 loopEntryBlock.setBlockFlow(info, current);
943 jumpHandler.forEachBreak((HBreak breakInstruction, _) { 944 jumpHandler.forEachBreak((HBreak breakInstruction, _) {
944 HBasicBlock block = breakInstruction.block; 945 HBasicBlock block = breakInstruction.block;
945 block.addAtExit(new HBreak.toLabel(label)); 946 block.addAtExit(new HBreak.toLabel(label));
946 block.remove(breakInstruction); 947 block.remove(breakInstruction);
947 }); 948 });
948 } 949 }
949 } 950 }
950 jumpHandler.close(); 951 jumpHandler.close();
951 } 952 }
952 953
953 @override 954 @override
954 void visitIfStatement(ir.IfStatement ifStatement) { 955 void visitIfStatement(ir.IfStatement ifStatement) {
955 handleIf( 956 handleIf(
956 visitCondition: () => ifStatement.condition.accept(this), 957 visitCondition: () => ifStatement.condition.accept(this),
957 visitThen: () => ifStatement.then.accept(this), 958 visitThen: () => ifStatement.then.accept(this),
958 visitElse: () => ifStatement.otherwise?.accept(this)); 959 visitElse: () => ifStatement.otherwise?.accept(this));
959 } 960 }
960 961
962 void handleIf(
963 {ir.Node node,
964 void visitCondition(),
965 void visitThen(),
966 void visitElse(),
967 SourceInformation sourceInformation}) {
968 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(
969 this, compiler, node == null ? node : astAdapter.getNode(node));
970 branchBuilder.handleIf(visitCondition, visitThen, visitElse,
971 sourceInformation: sourceInformation);
972 }
973
961 @override 974 @override
962 void visitAsExpression(ir.AsExpression asExpression) { 975 void visitAsExpression(ir.AsExpression asExpression) {
963 asExpression.operand.accept(this); 976 asExpression.operand.accept(this);
964 HInstruction expressionInstruction = pop(); 977 HInstruction expressionInstruction = pop();
965 ResolutionDartType type = astAdapter.getDartType(asExpression.type); 978 ResolutionDartType type = astAdapter.getDartType(asExpression.type);
966 if (type.isMalformed) { 979 if (type.isMalformed) {
967 if (type is MalformedType) { 980 if (type is MalformedType) {
968 ErroneousElement element = type.element; 981 ErroneousElement element = type.element;
969 generateTypeError(asExpression, element.message); 982 generateTypeError(asExpression, element.message);
970 } else { 983 } else {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1014 void fail() { 1027 void fail() {
1015 assertStatement.message.accept(this); 1028 assertStatement.message.accept(this);
1016 _pushStaticInvocation(astAdapter.assertThrow, <HInstruction>[pop()], 1029 _pushStaticInvocation(astAdapter.assertThrow, <HInstruction>[pop()],
1017 astAdapter.assertThrowReturnType); 1030 astAdapter.assertThrowReturnType);
1018 pop(); 1031 pop();
1019 } 1032 }
1020 1033
1021 handleIf(visitCondition: buildCondition, visitThen: fail); 1034 handleIf(visitCondition: buildCondition, visitThen: fail);
1022 } 1035 }
1023 1036
1037 /// Creates a [JumpHandler] for a statement. The node must be a jump
1038 /// target. If there are no breaks or continues targeting the statement,
1039 /// a special "null handler" is returned.
1040 ///
1041 /// [isLoopJump] is [:true:] when the jump handler is for a loop. This is used
sra1 2017/01/14 03:18:22 [:x:] --> `x`
Emily Fortuna 2017/01/17 23:33:09 Done.
1042 /// to distinguish the synthesized loop created for a switch statement with
1043 /// continue statements from simple switch statements.
1044 JumpHandler createJumpHandler(ir.TreeNode node, {bool isLoopJump: false}) {
1045 JumpTarget target = astAdapter.getJumpTarget(node);
1046 assert(target is KernelJumpTarget);
1047 if (target == null) {
1048 // No breaks or continues to this node.
1049 return new NullJumpHandler(compiler.reporter);
1050 }
1051 if (isLoopJump && node is ir.SwitchStatement) {
1052 throw 'Kernel Switch Statement handler not yet implemented.';
1053 }
1054
1055 return new JumpHandler(this, target);
1056 }
1057
1024 @override 1058 @override
1025 void visitBreakStatement(ir.BreakStatement breakStatement) { 1059 void visitBreakStatement(ir.BreakStatement breakStatement) {
1026 assert(!isAborted()); 1060 assert(!isAborted());
1061 handleInTryStatement();
1027 JumpTarget target = astAdapter.getJumpTarget(breakStatement.target); 1062 JumpTarget target = astAdapter.getJumpTarget(breakStatement.target);
1028 assert(target != null); 1063 assert(target != null);
1029 JumpHandler handler = jumpTargets[target]; 1064 JumpHandler handler = jumpTargets[target];
1030 assert(handler != null); 1065 assert(handler != null);
1031 handler.generateBreak(handler.labels.first); 1066 if (handler.labels.isNotEmpty) {
1067 handler.generateBreak(handler.labels.first);
1068 } else {
1069 handler.generateBreak();
1070 }
1032 } 1071 }
1033 1072
1034 @override 1073 @override
1035 void visitLabeledStatement(ir.LabeledStatement labeledStatement) { 1074 void visitLabeledStatement(ir.LabeledStatement labeledStatement) {
1036 JumpTarget target = astAdapter.getJumpTarget(labeledStatement);
1037 JumpHandler handler = new JumpHandler(this, target);
1038
1039 ir.Statement body = labeledStatement.body; 1075 ir.Statement body = labeledStatement.body;
1040 if (body is ir.WhileStatement || 1076 if (body is ir.WhileStatement ||
1041 body is ir.DoStatement || 1077 body is ir.DoStatement ||
1042 body is ir.ForStatement || 1078 body is ir.ForStatement ||
1043 body is ir.ForInStatement) { 1079 body is ir.ForInStatement ||
1044 // loops handle breaks on their own 1080 body is ir.SwitchStatement) {
1081 // loops and switches handle breaks on their own
1045 body.accept(this); 1082 body.accept(this);
1046 return; 1083 return;
1047 } 1084 }
1085 JumpHandler handler = createJumpHandler(labeledStatement);
1086
1048 LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler); 1087 LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler);
1049 1088
1050 HBasicBlock newBlock = openNewBlock(); 1089 HBasicBlock newBlock = openNewBlock();
1051 body.accept(this); 1090 body.accept(this);
1052 SubGraph bodyGraph = new SubGraph(newBlock, lastOpenedBlock); 1091 SubGraph bodyGraph = new SubGraph(newBlock, lastOpenedBlock);
1053 1092
1054 HBasicBlock joinBlock = graph.addNewBlock(); 1093 HBasicBlock joinBlock = graph.addNewBlock();
1055 List<LocalsHandler> breakHandlers = <LocalsHandler>[]; 1094 List<LocalsHandler> breakHandlers = <LocalsHandler>[];
1056 handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { 1095 handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) {
1057 breakInstruction.block.addSuccessor(joinBlock); 1096 breakInstruction.block.addSuccessor(joinBlock);
1058 breakHandlers.add(locals); 1097 breakHandlers.add(locals);
1059 }); 1098 });
1060 1099
1061 if (!isAborted()) { 1100 if (!isAborted()) {
1062 goto(current, joinBlock); 1101 goto(current, joinBlock);
1063 breakHandlers.add(localsHandler); 1102 breakHandlers.add(localsHandler);
1064 } 1103 }
1065 1104
1066 open(joinBlock); 1105 open(joinBlock);
1067 localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock); 1106 localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock);
1068 1107
1069 // There was at least one reachable break, so the label is needed. 1108 // There was at least one reachable break, so the label is needed.
1070 newBlock.setBlockFlow( 1109 newBlock.setBlockFlow(
1071 new HLabeledBlockInformation( 1110 new HLabeledBlockInformation(
1072 new HSubGraphBlockInformation(bodyGraph), handler.labels), 1111 new HSubGraphBlockInformation(bodyGraph), handler.labels),
1073 joinBlock); 1112 joinBlock);
1074 handler.close(); 1113 handler.close();
1075 } 1114 }
1076 1115
1116 /// Loop through the cases in a switch and create a mapping of case
1117 /// expressions to constants.
1118 Map<ir.Expression, ConstantValue> buildSwitchCaseConstants(
1119 ir.SwitchStatement switchStatement) {
1120 Map<ir.Expression, ConstantValue> constants =
1121 new Map<ir.Expression, ConstantValue>();
1122 for (ir.SwitchCase switchCase in switchStatement.cases) {
1123 for (ir.Expression caseExpression in switchCase.expressions) {
1124 ConstantValue constant = astAdapter.getConstantFor(caseExpression);
1125 constants[caseExpression] = constant;
1126 }
1127 }
1128 return constants;
1129 }
1130
1131 @override
1132 void visitContinueSwitchStatement(
1133 ir.ContinueSwitchStatement switchStatement) {
1134 handleInTryStatement();
1135 JumpTarget target = astAdapter.getJumpTarget(switchStatement.target);
1136 assert(target != null);
1137 JumpHandler handler = jumpTargets[target];
1138 assert(handler != null);
1139 assert(target.labels.isNotEmpty);
1140 handler.generateContinue(target.labels.first);
1141 }
1142
1143 @override
1144 void visitSwitchStatement(ir.SwitchStatement switchStatement) {
1145 Map<ir.Expression, ConstantValue> constants =
1146 buildSwitchCaseConstants(switchStatement);
1147
1148 // The switch case indices must match those computed in
1149 // [KernelSwitchCaseJumpHandler].
1150 bool hasContinue = false;
1151 Map<ir.SwitchCase, int> caseIndex = new Map<ir.SwitchCase, int>();
1152 int switchIndex = 1;
1153 bool hasDefault = false;
1154 for (ir.SwitchCase switchCase in switchStatement.cases) {
1155 if ((new ContinueVisitor(switchCase.body)).containsContinue) {
sra1 2017/01/14 03:18:22 Maybe make the visitor have a static method and pr
Emily Fortuna 2017/01/17 23:33:09 Done.
1156 hasContinue = true;
1157 }
1158 if (switchCase.isDefault) {
1159 hasDefault = true;
1160 }
1161 caseIndex[switchCase] = switchIndex;
1162 switchIndex++;
1163 }
1164
1165 JumpHandler jumpHandler = createJumpHandler(switchStatement);
1166 if (!hasContinue) {
1167 // If the switch statement has no switch cases targeted by continue
1168 // statements we encode the switch statement directly.
1169 _buildSimpleSwitchStatement(switchStatement, jumpHandler, constants);
1170 } else {
1171 throw 'Complex switch statement with continue label not implemented yet.';
1172 }
1173 }
1174
1175 /// Helper for building switch statements.
1176 bool _isDefaultCase(ir.SwitchCase switchCase) =>
sra1 2017/01/14 03:18:22 could be static
Emily Fortuna 2017/01/17 23:33:09 Done.
1177 switchCase == null || switchCase.isDefault;
1178
1179 /// Builds a simple switch statement which does not handle uses of continue
1180 /// statements to labeled switch cases.
1181 void _buildSimpleSwitchStatement(ir.SwitchStatement switchStatement,
1182 JumpHandler jumpHandler, Map<ir.Expression, ConstantValue> constants) {
1183 void buildSwitchCase(ir.SwitchCase switchCase) {
1184 switchCase.body.accept(this);
1185 }
1186
1187 handleSwitch(switchStatement, jumpHandler, switchStatement.cases,
1188 _isDefaultCase, buildSwitchCase, constants);
1189 jumpHandler.close();
1190 }
1191
1192 /// Creates a switch statement.
1193 ///
1194 /// [jumpHandler] is the [JumpHandler] for the created switch statement.
1195 /// [buildSwitchCase] creates the statements for the switch case.
1196 void handleSwitch(
1197 ir.SwitchStatement switchStatement,
1198 JumpHandler jumpHandler,
1199 List<ir.SwitchCase> switchCases,
1200 bool isDefaultCase(ir.SwitchCase switchCase),
1201 void buildSwitchCase(ir.SwitchCase switchCase),
1202 Map<ir.Expression, ConstantValue> constantsLookup) {
1203 HBasicBlock expressionStart = openNewBlock();
1204 switchStatement.expression.accept(this);
1205 HInstruction expression = pop();
1206
1207 List<ConstantValue> getConstants(ir.SwitchCase switchCase) {
1208 List<ConstantValue> constantList = <ConstantValue>[];
1209 if (switchCase != null) {
1210 for (var expression in switchCase.expressions) {
1211 constantList.add(constantsLookup[expression]);
1212 }
1213 }
1214 return constantList;
1215 }
1216
1217 if (switchCases.isEmpty) {
1218 return;
1219 }
1220
1221 HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]);
1222 HBasicBlock expressionEnd = close(switchInstruction);
1223 LocalsHandler savedLocals = localsHandler;
1224
1225 List<HStatementInformation> statements = <HStatementInformation>[];
1226 bool hasDefault = false;
1227 for (ir.SwitchCase switchCase in switchCases) {
1228 HBasicBlock block = graph.addNewBlock();
1229 for (ConstantValue constant in getConstants(switchCase)) {
1230 HConstant hConstant = graph.addConstant(constant, closedWorld);
1231 switchInstruction.inputs.add(hConstant);
1232 hConstant.usedBy.add(switchInstruction);
1233 expressionEnd.addSuccessor(block);
1234 }
1235
1236 if (isDefaultCase(switchCase)) {
1237 // An HSwitch has n inputs and n+1 successors, the last being the
1238 // default case.
1239 expressionEnd.addSuccessor(block);
1240 hasDefault = true;
1241 }
1242 open(block);
1243 localsHandler = new LocalsHandler.from(savedLocals);
1244 buildSwitchCase(switchCase);
1245 statements.add(
1246 new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock)));
1247 }
1248
1249 // Add a join-block if necessary.
1250 // We create [joinBlock] early, and then go through the cases that might
1251 // want to jump to it. In each case, if we add [joinBlock] as a successor
1252 // of another block, we also add an element to [caseHandlers] that is used
1253 // to create the phis in [joinBlock].
1254 // If we never jump to the join block, [caseHandlers] will stay empty, and
1255 // the join block is never added to the graph.
1256 HBasicBlock joinBlock = new HBasicBlock();
1257 List<LocalsHandler> caseHandlers = <LocalsHandler>[];
1258 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) {
1259 instruction.block.addSuccessor(joinBlock);
1260 caseHandlers.add(locals);
1261 });
1262 jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) {
1263 assert(invariant(astAdapter.getNode(switchStatement), false,
1264 message: 'Continue cannot target a switch.'));
1265 });
1266 if (!isAborted()) {
1267 current.close(new HGoto());
1268 lastOpenedBlock.addSuccessor(joinBlock);
1269 caseHandlers.add(localsHandler);
1270 }
1271 if (!hasDefault) {
1272 // Always create a default case, to avoid a critical edge in the
1273 // graph.
1274 HBasicBlock defaultCase = addNewBlock();
1275 expressionEnd.addSuccessor(defaultCase);
1276 open(defaultCase);
1277 close(new HGoto());
1278 defaultCase.addSuccessor(joinBlock);
1279 caseHandlers.add(savedLocals);
1280 statements.add(new HSubGraphBlockInformation(
1281 new SubGraph(defaultCase, defaultCase)));
1282 }
1283 assert(caseHandlers.length == joinBlock.predecessors.length);
1284 if (caseHandlers.length != 0) {
1285 graph.addBlock(joinBlock);
1286 open(joinBlock);
1287 if (caseHandlers.length == 1) {
1288 localsHandler = caseHandlers[0];
1289 } else {
1290 localsHandler = savedLocals.mergeMultiple(caseHandlers, joinBlock);
1291 }
1292 } else {
1293 // The joinblock is not used.
1294 joinBlock = null;
1295 }
1296
1297 HSubExpressionBlockInformation expressionInfo =
1298 new HSubExpressionBlockInformation(
1299 new SubExpression(expressionStart, expressionEnd));
1300 expressionStart.setBlockFlow(
1301 new HSwitchBlockInformation(
1302 expressionInfo, statements, jumpHandler.target, jumpHandler.labels),
1303 joinBlock);
1304
1305 jumpHandler.close();
1306 }
1307
1077 @override 1308 @override
1078 void visitConditionalExpression(ir.ConditionalExpression conditional) { 1309 void visitConditionalExpression(ir.ConditionalExpression conditional) {
1079 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler); 1310 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler);
1080 brancher.handleConditional( 1311 brancher.handleConditional(
1081 () => conditional.condition.accept(this), 1312 () => conditional.condition.accept(this),
1082 () => conditional.then.accept(this), 1313 () => conditional.then.accept(this),
1083 () => conditional.otherwise.accept(this)); 1314 () => conditional.otherwise.accept(this));
1084 } 1315 }
1085 1316
1086 @override 1317 @override
(...skipping 1126 matching lines...) Expand 10 before | Expand all | Expand 10 after
2213 (ir.DartType typeArgType) => 2444 (ir.DartType typeArgType) =>
2214 typeArgType is! ir.DynamicType && 2445 typeArgType is! ir.DynamicType &&
2215 typeArgType is! ir.InvalidType && 2446 typeArgType is! ir.InvalidType &&
2216 !isMethodTypeVariableType(type)); 2447 !isMethodTypeVariableType(type));
2217 } 2448 }
2218 2449
2219 @override 2450 @override
2220 void visitThrow(ir.Throw throwNode) { 2451 void visitThrow(ir.Throw throwNode) {
2221 _visitThrowExpression(throwNode.expression); 2452 _visitThrowExpression(throwNode.expression);
2222 if (isReachable) { 2453 if (isReachable) {
2454 handleInTryStatement();
2223 push(new HThrowExpression(pop(), null)); 2455 push(new HThrowExpression(pop(), null));
2224 isReachable = false; 2456 isReachable = false;
2225 } 2457 }
2226 } 2458 }
2227 2459
2228 void _visitThrowExpression(ir.Expression expression) { 2460 void _visitThrowExpression(ir.Expression expression) {
2229 bool old = _inExpressionOfThrow; 2461 bool old = _inExpressionOfThrow;
2230 try { 2462 try {
2231 _inExpressionOfThrow = true; 2463 _inExpressionOfThrow = true;
2232 expression.accept(this); 2464 expression.accept(this);
2233 } finally { 2465 } finally {
2234 _inExpressionOfThrow = old; 2466 _inExpressionOfThrow = old;
2235 } 2467 }
2236 } 2468 }
2237 2469
2238 @override 2470 @override
2239 void visitRethrow(ir.Rethrow rethrowNode) { 2471 void visitRethrow(ir.Rethrow rethrowNode) {
2240 HInstruction exception = rethrowableException; 2472 HInstruction exception = rethrowableException;
2241 if (exception == null) { 2473 if (exception == null) {
2242 exception = graph.addConstantNull(closedWorld); 2474 exception = graph.addConstantNull(closedWorld);
2243 compiler.reporter.internalError(astAdapter.getNode(rethrowNode), 2475 compiler.reporter.internalError(astAdapter.getNode(rethrowNode),
2244 'rethrowableException should not be null.'); 2476 'rethrowableException should not be null.');
2245 } 2477 }
2478 handleInTryStatement();
2246 SourceInformation sourceInformation = null; 2479 SourceInformation sourceInformation = null;
2247 closeAndGotoExit(new HThrow(exception, sourceInformation, isRethrow: true)); 2480 closeAndGotoExit(new HThrow(exception, sourceInformation, isRethrow: true));
2248 // ir.Rethrow is an expression so we need to push a value - a constant with 2481 // ir.Rethrow is an expression so we need to push a value - a constant with
2249 // no type. 2482 // no type.
2250 stack.add(graph.addConstantUnreachable(closedWorld)); 2483 stack.add(graph.addConstantUnreachable(closedWorld));
2251 } 2484 }
2252 2485
2253 @override 2486 @override
2254 void visitThisExpression(ir.ThisExpression thisExpression) { 2487 void visitThisExpression(ir.ThisExpression thisExpression) {
2255 stack.add(localsHandler.readThis()); 2488 stack.add(localsHandler.readThis());
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
2318 HBasicBlock endTryBlock; 2551 HBasicBlock endTryBlock;
2319 HBasicBlock startCatchBlock; 2552 HBasicBlock startCatchBlock;
2320 HBasicBlock endCatchBlock; 2553 HBasicBlock endCatchBlock;
2321 HBasicBlock startFinallyBlock; 2554 HBasicBlock startFinallyBlock;
2322 HBasicBlock endFinallyBlock; 2555 HBasicBlock endFinallyBlock;
2323 HBasicBlock exitBlock; 2556 HBasicBlock exitBlock;
2324 HTry tryInstruction; 2557 HTry tryInstruction;
2325 HLocalValue exception; 2558 HLocalValue exception;
2326 KernelSsaBuilder kernelBuilder; 2559 KernelSsaBuilder kernelBuilder;
2327 2560
2561 /// True if the code surrounding this try statement was also part of a
2562 /// try/catch/finally statement.
2563 bool previouslyInTrySequence;
2564
2328 SubGraph bodyGraph; 2565 SubGraph bodyGraph;
2329 SubGraph catchGraph; 2566 SubGraph catchGraph;
2330 SubGraph finallyGraph; 2567 SubGraph finallyGraph;
2331 2568
2332 // The original set of locals that were defined before this try block. 2569 // The original set of locals that were defined before this try block.
2333 // The catch block and the finally block must not reuse the existing locals 2570 // The catch block and the finally block must not reuse the existing locals
2334 // handler. None of the variables that have been defined in the body-block 2571 // handler. None of the variables that have been defined in the body-block
2335 // will be used, but for loops we will add (unnecessary) phis that will 2572 // will be used, but for loops we will add (unnecessary) phis that will
2336 // reference the body variables. This makes it look as if the variables were 2573 // reference the body variables. This makes it look as if the variables were
2337 // used in a non-dominated block. 2574 // used in a non-dominated block.
2338 LocalsHandler originalSavedLocals; 2575 LocalsHandler originalSavedLocals;
2339 2576
2340 TryCatchFinallyBuilder(this.kernelBuilder) { 2577 TryCatchFinallyBuilder(this.kernelBuilder) {
2341 tryInstruction = new HTry(); 2578 tryInstruction = new HTry();
2342 originalSavedLocals = new LocalsHandler.from(kernelBuilder.localsHandler); 2579 originalSavedLocals = new LocalsHandler.from(kernelBuilder.localsHandler);
2343 enterBlock = kernelBuilder.openNewBlock(); 2580 enterBlock = kernelBuilder.openNewBlock();
2344 kernelBuilder.close(tryInstruction); 2581 kernelBuilder.close(tryInstruction);
2582 previouslyInTrySequence = kernelBuilder.inTryStatement;
2583 kernelBuilder.inTryStatement = true;
2345 2584
2346 startTryBlock = kernelBuilder.graph.addNewBlock(); 2585 startTryBlock = kernelBuilder.graph.addNewBlock();
2347 kernelBuilder.open(startTryBlock); 2586 kernelBuilder.open(startTryBlock);
2348 } 2587 }
2349 2588
2350 void _addExitTrySuccessor(successor) { 2589 void _addExitTrySuccessor(successor) {
2351 if (successor == null) return; 2590 if (successor == null) return;
2352 // Iterate over all blocks created inside this try/catch, and 2591 // Iterate over all blocks created inside this try/catch, and
2353 // attach successor information to blocks that end with 2592 // attach successor information to blocks that end with
2354 // [HExitTry]. 2593 // [HExitTry].
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
2521 // blocks. 2760 // blocks.
2522 kernelBuilder.localsHandler = originalSavedLocals; 2761 kernelBuilder.localsHandler = originalSavedLocals;
2523 kernelBuilder.open(exitBlock); 2762 kernelBuilder.open(exitBlock);
2524 enterBlock.setBlockFlow( 2763 enterBlock.setBlockFlow(
2525 new HTryBlockInformation( 2764 new HTryBlockInformation(
2526 kernelBuilder.wrapStatementGraph(bodyGraph), 2765 kernelBuilder.wrapStatementGraph(bodyGraph),
2527 exception, 2766 exception,
2528 kernelBuilder.wrapStatementGraph(catchGraph), 2767 kernelBuilder.wrapStatementGraph(catchGraph),
2529 kernelBuilder.wrapStatementGraph(finallyGraph)), 2768 kernelBuilder.wrapStatementGraph(finallyGraph)),
2530 exitBlock); 2769 exitBlock);
2770 kernelBuilder.inTryStatement = previouslyInTrySequence;
2531 } 2771 }
2532 } 2772 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698