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

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_continue_analysis.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 978
966 if (asExpression.type is ir.InvalidType) { 979 if (asExpression.type is ir.InvalidType) {
967 generateTypeError(asExpression, 'invalid type'); 980 generateTypeError(asExpression, 'invalid type');
968 stack.add(expressionInstruction); 981 stack.add(expressionInstruction);
969 return; 982 return;
970 } 983 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
1024 void fail() { 1037 void fail() {
1025 assertStatement.message.accept(this); 1038 assertStatement.message.accept(this);
1026 _pushStaticInvocation(astAdapter.assertThrow, <HInstruction>[pop()], 1039 _pushStaticInvocation(astAdapter.assertThrow, <HInstruction>[pop()],
1027 astAdapter.assertThrowReturnType); 1040 astAdapter.assertThrowReturnType);
1028 pop(); 1041 pop();
1029 } 1042 }
1030 1043
1031 handleIf(visitCondition: buildCondition, visitThen: fail); 1044 handleIf(visitCondition: buildCondition, visitThen: fail);
1032 } 1045 }
1033 1046
1047 /// Creates a [JumpHandler] for a statement. The node must be a jump
1048 /// target. If there are no breaks or continues targeting the statement,
1049 /// a special "null handler" is returned.
1050 ///
1051 /// [isLoopJump] is true when the jump handler is for a loop. This is used
1052 /// to distinguish the synthesized loop created for a switch statement with
1053 /// continue statements from simple switch statements.
1054 JumpHandler createJumpHandler(ir.TreeNode node, {bool isLoopJump: false}) {
1055 JumpTarget target = astAdapter.getJumpTarget(node);
1056 assert(target is KernelJumpTarget);
1057 if (target == null) {
1058 // No breaks or continues to this node.
1059 return new NullJumpHandler(compiler.reporter);
1060 }
1061 if (isLoopJump && node is ir.SwitchStatement) {
1062 throw 'Kernel Switch Statement handler not yet implemented.';
1063 }
1064
1065 return new JumpHandler(this, target);
1066 }
1067
1034 @override 1068 @override
1035 void visitBreakStatement(ir.BreakStatement breakStatement) { 1069 void visitBreakStatement(ir.BreakStatement breakStatement) {
1036 assert(!isAborted()); 1070 assert(!isAborted());
1071 handleInTryStatement();
1037 JumpTarget target = astAdapter.getJumpTarget(breakStatement.target); 1072 JumpTarget target = astAdapter.getJumpTarget(breakStatement.target);
1038 assert(target != null); 1073 assert(target != null);
1039 JumpHandler handler = jumpTargets[target]; 1074 JumpHandler handler = jumpTargets[target];
1040 assert(handler != null); 1075 assert(handler != null);
1041 handler.generateBreak(handler.labels.first); 1076 if (handler.labels.isNotEmpty) {
1077 handler.generateBreak(handler.labels.first);
1078 } else {
1079 handler.generateBreak();
1080 }
1042 } 1081 }
1043 1082
1044 @override 1083 @override
1045 void visitLabeledStatement(ir.LabeledStatement labeledStatement) { 1084 void visitLabeledStatement(ir.LabeledStatement labeledStatement) {
1046 JumpTarget target = astAdapter.getJumpTarget(labeledStatement);
1047 JumpHandler handler = new JumpHandler(this, target);
1048
1049 ir.Statement body = labeledStatement.body; 1085 ir.Statement body = labeledStatement.body;
1050 if (body is ir.WhileStatement || 1086 if (body is ir.WhileStatement ||
1051 body is ir.DoStatement || 1087 body is ir.DoStatement ||
1052 body is ir.ForStatement || 1088 body is ir.ForStatement ||
1053 body is ir.ForInStatement) { 1089 body is ir.ForInStatement ||
1054 // loops handle breaks on their own 1090 body is ir.SwitchStatement) {
1091 // loops and switches handle breaks on their own
1055 body.accept(this); 1092 body.accept(this);
1056 return; 1093 return;
1057 } 1094 }
1095 JumpHandler handler = createJumpHandler(labeledStatement);
1096
1058 LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler); 1097 LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler);
1059 1098
1060 HBasicBlock newBlock = openNewBlock(); 1099 HBasicBlock newBlock = openNewBlock();
1061 body.accept(this); 1100 body.accept(this);
1062 SubGraph bodyGraph = new SubGraph(newBlock, lastOpenedBlock); 1101 SubGraph bodyGraph = new SubGraph(newBlock, lastOpenedBlock);
1063 1102
1064 HBasicBlock joinBlock = graph.addNewBlock(); 1103 HBasicBlock joinBlock = graph.addNewBlock();
1065 List<LocalsHandler> breakHandlers = <LocalsHandler>[]; 1104 List<LocalsHandler> breakHandlers = <LocalsHandler>[];
1066 handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { 1105 handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) {
1067 breakInstruction.block.addSuccessor(joinBlock); 1106 breakInstruction.block.addSuccessor(joinBlock);
1068 breakHandlers.add(locals); 1107 breakHandlers.add(locals);
1069 }); 1108 });
1070 1109
1071 if (!isAborted()) { 1110 if (!isAborted()) {
1072 goto(current, joinBlock); 1111 goto(current, joinBlock);
1073 breakHandlers.add(localsHandler); 1112 breakHandlers.add(localsHandler);
1074 } 1113 }
1075 1114
1076 open(joinBlock); 1115 open(joinBlock);
1077 localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock); 1116 localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock);
1078 1117
1079 // There was at least one reachable break, so the label is needed. 1118 // There was at least one reachable break, so the label is needed.
1080 newBlock.setBlockFlow( 1119 newBlock.setBlockFlow(
1081 new HLabeledBlockInformation( 1120 new HLabeledBlockInformation(
1082 new HSubGraphBlockInformation(bodyGraph), handler.labels), 1121 new HSubGraphBlockInformation(bodyGraph), handler.labels),
1083 joinBlock); 1122 joinBlock);
1084 handler.close(); 1123 handler.close();
1085 } 1124 }
1086 1125
1126 /// Loop through the cases in a switch and create a mapping of case
1127 /// expressions to constants.
1128 Map<ir.Expression, ConstantValue> buildSwitchCaseConstants(
sra1 2017/01/18 23:31:28 can this be private?
Emily Fortuna 2017/01/19 00:21:22 you bet.
1129 ir.SwitchStatement switchStatement) {
1130 Map<ir.Expression, ConstantValue> constants =
1131 new Map<ir.Expression, ConstantValue>();
1132 for (ir.SwitchCase switchCase in switchStatement.cases) {
1133 for (ir.Expression caseExpression in switchCase.expressions) {
1134 ConstantValue constant = astAdapter.getConstantFor(caseExpression);
1135 constants[caseExpression] = constant;
1136 }
1137 }
1138 return constants;
1139 }
1140
1141 @override
1142 void visitContinueSwitchStatement(
1143 ir.ContinueSwitchStatement switchStatement) {
1144 handleInTryStatement();
1145 JumpTarget target = astAdapter.getJumpTarget(switchStatement.target);
1146 assert(target != null);
1147 JumpHandler handler = jumpTargets[target];
1148 assert(handler != null);
1149 assert(target.labels.isNotEmpty);
1150 handler.generateContinue(target.labels.first);
1151 }
1152
1153 @override
1154 void visitSwitchStatement(ir.SwitchStatement switchStatement) {
1155 Map<ir.Expression, ConstantValue> constants =
1156 buildSwitchCaseConstants(switchStatement);
1157
1158 // The switch case indices must match those computed in
1159 // [KernelSwitchCaseJumpHandler].
1160 bool hasContinue = false;
1161 Map<ir.SwitchCase, int> caseIndex = new Map<ir.SwitchCase, int>();
1162 int switchIndex = 1;
1163 bool hasDefault = false;
1164 for (ir.SwitchCase switchCase in switchStatement.cases) {
1165 if (SwitchContinueAnalysis.containsContinue(switchCase.body)) {
1166 hasContinue = true;
1167 }
1168 if (switchCase.isDefault) {
1169 hasDefault = true;
1170 }
1171 caseIndex[switchCase] = switchIndex;
1172 switchIndex++;
1173 }
1174
1175 JumpHandler jumpHandler = createJumpHandler(switchStatement);
1176 if (!hasContinue) {
1177 // If the switch statement has no switch cases targeted by continue
1178 // statements we encode the switch statement directly.
1179 _buildSimpleSwitchStatement(switchStatement, jumpHandler, constants);
1180 } else {
1181 throw 'Complex switch statement with continue label not implemented yet.';
1182 }
1183 }
1184
1185 /// Helper for building switch statements.
1186 static bool _isDefaultCase(ir.SwitchCase switchCase) =>
1187 switchCase == null || switchCase.isDefault;
1188
1189 /// Builds a simple switch statement which does not handle uses of continue
1190 /// statements to labeled switch cases.
1191 void _buildSimpleSwitchStatement(ir.SwitchStatement switchStatement,
1192 JumpHandler jumpHandler, Map<ir.Expression, ConstantValue> constants) {
1193 void buildSwitchCase(ir.SwitchCase switchCase) {
1194 switchCase.body.accept(this);
1195 }
1196
1197 handleSwitch(switchStatement, jumpHandler, switchStatement.cases,
1198 _isDefaultCase, buildSwitchCase, constants);
1199 jumpHandler.close();
1200 }
1201
1202 /// Creates a switch statement.
1203 ///
1204 /// [jumpHandler] is the [JumpHandler] for the created switch statement.
1205 /// [buildSwitchCase] creates the statements for the switch case.
1206 void handleSwitch(
1207 ir.SwitchStatement switchStatement,
1208 JumpHandler jumpHandler,
1209 List<ir.SwitchCase> switchCases,
1210 bool isDefaultCase(ir.SwitchCase switchCase),
1211 void buildSwitchCase(ir.SwitchCase switchCase),
1212 Map<ir.Expression, ConstantValue> constantsLookup) {
1213 HBasicBlock expressionStart = openNewBlock();
1214 switchStatement.expression.accept(this);
1215 HInstruction expression = pop();
1216
1217 List<ConstantValue> getConstants(ir.SwitchCase switchCase) {
1218 List<ConstantValue> constantList = <ConstantValue>[];
1219 if (switchCase != null) {
1220 for (var expression in switchCase.expressions) {
1221 constantList.add(constantsLookup[expression]);
1222 }
1223 }
1224 return constantList;
1225 }
1226
1227 if (switchCases.isEmpty) {
1228 return;
1229 }
1230
1231 HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]);
1232 HBasicBlock expressionEnd = close(switchInstruction);
1233 LocalsHandler savedLocals = localsHandler;
1234
1235 List<HStatementInformation> statements = <HStatementInformation>[];
1236 bool hasDefault = false;
1237 for (ir.SwitchCase switchCase in switchCases) {
1238 HBasicBlock block = graph.addNewBlock();
1239 for (ConstantValue constant in getConstants(switchCase)) {
1240 HConstant hConstant = graph.addConstant(constant, closedWorld);
1241 switchInstruction.inputs.add(hConstant);
1242 hConstant.usedBy.add(switchInstruction);
1243 expressionEnd.addSuccessor(block);
1244 }
1245
1246 if (isDefaultCase(switchCase)) {
1247 // An HSwitch has n inputs and n+1 successors, the last being the
1248 // default case.
1249 expressionEnd.addSuccessor(block);
1250 hasDefault = true;
1251 }
1252 open(block);
1253 localsHandler = new LocalsHandler.from(savedLocals);
1254 buildSwitchCase(switchCase);
1255 statements.add(
1256 new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock)));
1257 }
1258
1259 // Add a join-block if necessary.
1260 // We create [joinBlock] early, and then go through the cases that might
1261 // want to jump to it. In each case, if we add [joinBlock] as a successor
1262 // of another block, we also add an element to [caseHandlers] that is used
1263 // to create the phis in [joinBlock].
1264 // If we never jump to the join block, [caseHandlers] will stay empty, and
1265 // the join block is never added to the graph.
1266 HBasicBlock joinBlock = new HBasicBlock();
1267 List<LocalsHandler> caseHandlers = <LocalsHandler>[];
1268 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) {
1269 instruction.block.addSuccessor(joinBlock);
1270 caseHandlers.add(locals);
1271 });
1272 jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) {
1273 assert(invariant(astAdapter.getNode(switchStatement), false,
1274 message: 'Continue cannot target a switch.'));
1275 });
1276 if (!isAborted()) {
1277 current.close(new HGoto());
1278 lastOpenedBlock.addSuccessor(joinBlock);
1279 caseHandlers.add(localsHandler);
1280 }
1281 if (!hasDefault) {
1282 // Always create a default case, to avoid a critical edge in the
1283 // graph.
1284 HBasicBlock defaultCase = addNewBlock();
1285 expressionEnd.addSuccessor(defaultCase);
1286 open(defaultCase);
1287 close(new HGoto());
1288 defaultCase.addSuccessor(joinBlock);
1289 caseHandlers.add(savedLocals);
1290 statements.add(new HSubGraphBlockInformation(
1291 new SubGraph(defaultCase, defaultCase)));
1292 }
1293 assert(caseHandlers.length == joinBlock.predecessors.length);
1294 if (caseHandlers.length != 0) {
1295 graph.addBlock(joinBlock);
1296 open(joinBlock);
1297 if (caseHandlers.length == 1) {
1298 localsHandler = caseHandlers[0];
1299 } else {
1300 localsHandler = savedLocals.mergeMultiple(caseHandlers, joinBlock);
1301 }
1302 } else {
1303 // The joinblock is not used.
1304 joinBlock = null;
1305 }
1306
1307 HSubExpressionBlockInformation expressionInfo =
1308 new HSubExpressionBlockInformation(
1309 new SubExpression(expressionStart, expressionEnd));
1310 expressionStart.setBlockFlow(
1311 new HSwitchBlockInformation(
1312 expressionInfo, statements, jumpHandler.target, jumpHandler.labels),
1313 joinBlock);
1314
1315 jumpHandler.close();
1316 }
1317
1087 @override 1318 @override
1088 void visitConditionalExpression(ir.ConditionalExpression conditional) { 1319 void visitConditionalExpression(ir.ConditionalExpression conditional) {
1089 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler); 1320 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler);
1090 brancher.handleConditional( 1321 brancher.handleConditional(
1091 () => conditional.condition.accept(this), 1322 () => conditional.condition.accept(this),
1092 () => conditional.then.accept(this), 1323 () => conditional.then.accept(this),
1093 () => conditional.otherwise.accept(this)); 1324 () => conditional.otherwise.accept(this));
1094 } 1325 }
1095 1326
1096 @override 1327 @override
(...skipping 1138 matching lines...) Expand 10 before | Expand all | Expand 10 after
2235 (ir.DartType typeArgType) => 2466 (ir.DartType typeArgType) =>
2236 typeArgType is! ir.DynamicType && 2467 typeArgType is! ir.DynamicType &&
2237 typeArgType is! ir.InvalidType && 2468 typeArgType is! ir.InvalidType &&
2238 !isMethodTypeVariableType(type)); 2469 !isMethodTypeVariableType(type));
2239 } 2470 }
2240 2471
2241 @override 2472 @override
2242 void visitThrow(ir.Throw throwNode) { 2473 void visitThrow(ir.Throw throwNode) {
2243 _visitThrowExpression(throwNode.expression); 2474 _visitThrowExpression(throwNode.expression);
2244 if (isReachable) { 2475 if (isReachable) {
2476 handleInTryStatement();
2245 push(new HThrowExpression(pop(), null)); 2477 push(new HThrowExpression(pop(), null));
2246 isReachable = false; 2478 isReachable = false;
2247 } 2479 }
2248 } 2480 }
2249 2481
2250 void _visitThrowExpression(ir.Expression expression) { 2482 void _visitThrowExpression(ir.Expression expression) {
2251 bool old = _inExpressionOfThrow; 2483 bool old = _inExpressionOfThrow;
2252 try { 2484 try {
2253 _inExpressionOfThrow = true; 2485 _inExpressionOfThrow = true;
2254 expression.accept(this); 2486 expression.accept(this);
2255 } finally { 2487 } finally {
2256 _inExpressionOfThrow = old; 2488 _inExpressionOfThrow = old;
2257 } 2489 }
2258 } 2490 }
2259 2491
2260 @override 2492 @override
2261 void visitRethrow(ir.Rethrow rethrowNode) { 2493 void visitRethrow(ir.Rethrow rethrowNode) {
2262 HInstruction exception = rethrowableException; 2494 HInstruction exception = rethrowableException;
2263 if (exception == null) { 2495 if (exception == null) {
2264 exception = graph.addConstantNull(closedWorld); 2496 exception = graph.addConstantNull(closedWorld);
2265 compiler.reporter.internalError(astAdapter.getNode(rethrowNode), 2497 compiler.reporter.internalError(astAdapter.getNode(rethrowNode),
2266 'rethrowableException should not be null.'); 2498 'rethrowableException should not be null.');
2267 } 2499 }
2500 handleInTryStatement();
2268 SourceInformation sourceInformation = null; 2501 SourceInformation sourceInformation = null;
2269 closeAndGotoExit(new HThrow(exception, sourceInformation, isRethrow: true)); 2502 closeAndGotoExit(new HThrow(exception, sourceInformation, isRethrow: true));
2270 // ir.Rethrow is an expression so we need to push a value - a constant with 2503 // ir.Rethrow is an expression so we need to push a value - a constant with
2271 // no type. 2504 // no type.
2272 stack.add(graph.addConstantUnreachable(closedWorld)); 2505 stack.add(graph.addConstantUnreachable(closedWorld));
2273 } 2506 }
2274 2507
2275 @override 2508 @override
2276 void visitThisExpression(ir.ThisExpression thisExpression) { 2509 void visitThisExpression(ir.ThisExpression thisExpression) {
2277 stack.add(localsHandler.readThis()); 2510 stack.add(localsHandler.readThis());
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
2340 HBasicBlock endTryBlock; 2573 HBasicBlock endTryBlock;
2341 HBasicBlock startCatchBlock; 2574 HBasicBlock startCatchBlock;
2342 HBasicBlock endCatchBlock; 2575 HBasicBlock endCatchBlock;
2343 HBasicBlock startFinallyBlock; 2576 HBasicBlock startFinallyBlock;
2344 HBasicBlock endFinallyBlock; 2577 HBasicBlock endFinallyBlock;
2345 HBasicBlock exitBlock; 2578 HBasicBlock exitBlock;
2346 HTry tryInstruction; 2579 HTry tryInstruction;
2347 HLocalValue exception; 2580 HLocalValue exception;
2348 KernelSsaBuilder kernelBuilder; 2581 KernelSsaBuilder kernelBuilder;
2349 2582
2583 /// True if the code surrounding this try statement was also part of a
2584 /// try/catch/finally statement.
2585 bool previouslyInTrySequence;
sra1 2017/01/18 23:31:28 Keep 'saved' names consistent, e.g. previousInTryS
Emily Fortuna 2017/01/19 00:21:22 Done.
2586
2350 SubGraph bodyGraph; 2587 SubGraph bodyGraph;
2351 SubGraph catchGraph; 2588 SubGraph catchGraph;
2352 SubGraph finallyGraph; 2589 SubGraph finallyGraph;
2353 2590
2354 // The original set of locals that were defined before this try block. 2591 // The original set of locals that were defined before this try block.
2355 // The catch block and the finally block must not reuse the existing locals 2592 // The catch block and the finally block must not reuse the existing locals
2356 // handler. None of the variables that have been defined in the body-block 2593 // handler. None of the variables that have been defined in the body-block
2357 // will be used, but for loops we will add (unnecessary) phis that will 2594 // will be used, but for loops we will add (unnecessary) phis that will
2358 // reference the body variables. This makes it look as if the variables were 2595 // reference the body variables. This makes it look as if the variables were
2359 // used in a non-dominated block. 2596 // used in a non-dominated block.
2360 LocalsHandler originalSavedLocals; 2597 LocalsHandler originalSavedLocals;
2361 2598
2362 TryCatchFinallyBuilder(this.kernelBuilder) { 2599 TryCatchFinallyBuilder(this.kernelBuilder) {
2363 tryInstruction = new HTry(); 2600 tryInstruction = new HTry();
2364 originalSavedLocals = new LocalsHandler.from(kernelBuilder.localsHandler); 2601 originalSavedLocals = new LocalsHandler.from(kernelBuilder.localsHandler);
2365 enterBlock = kernelBuilder.openNewBlock(); 2602 enterBlock = kernelBuilder.openNewBlock();
2366 kernelBuilder.close(tryInstruction); 2603 kernelBuilder.close(tryInstruction);
2604 previouslyInTrySequence = kernelBuilder.inTryStatement;
2605 kernelBuilder.inTryStatement = true;
2367 2606
2368 startTryBlock = kernelBuilder.graph.addNewBlock(); 2607 startTryBlock = kernelBuilder.graph.addNewBlock();
2369 kernelBuilder.open(startTryBlock); 2608 kernelBuilder.open(startTryBlock);
2370 } 2609 }
2371 2610
2372 void _addExitTrySuccessor(successor) { 2611 void _addExitTrySuccessor(successor) {
2373 if (successor == null) return; 2612 if (successor == null) return;
2374 // Iterate over all blocks created inside this try/catch, and 2613 // Iterate over all blocks created inside this try/catch, and
2375 // attach successor information to blocks that end with 2614 // attach successor information to blocks that end with
2376 // [HExitTry]. 2615 // [HExitTry].
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
2538 // blocks. 2777 // blocks.
2539 kernelBuilder.localsHandler = originalSavedLocals; 2778 kernelBuilder.localsHandler = originalSavedLocals;
2540 kernelBuilder.open(exitBlock); 2779 kernelBuilder.open(exitBlock);
2541 enterBlock.setBlockFlow( 2780 enterBlock.setBlockFlow(
2542 new HTryBlockInformation( 2781 new HTryBlockInformation(
2543 kernelBuilder.wrapStatementGraph(bodyGraph), 2782 kernelBuilder.wrapStatementGraph(bodyGraph),
2544 exception, 2783 exception,
2545 kernelBuilder.wrapStatementGraph(catchGraph), 2784 kernelBuilder.wrapStatementGraph(catchGraph),
2546 kernelBuilder.wrapStatementGraph(finallyGraph)), 2785 kernelBuilder.wrapStatementGraph(finallyGraph)),
2547 exitBlock); 2786 exitBlock);
2787 kernelBuilder.inTryStatement = previouslyInTrySequence;
2548 } 2788 }
2549 } 2789 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698