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

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
« no previous file with comments | « pkg/compiler/lib/src/ssa/builder.dart ('k') | pkg/compiler/lib/src/ssa/graph_builder.dart » ('j') | 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) 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 /// Returns true if the [type] is a valid return type for an asynchronous 570 /// Returns true if the [type] is a valid return type for an asynchronous
569 /// function. 571 /// function.
570 /// 572 ///
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 " was declared to return a ${_targetFunction.returnType}."); 606 " was declared to return a ${_targetFunction.returnType}.");
605 pop(); 607 pop();
606 return; 608 return;
607 } 609 }
608 } else { 610 } else {
609 value = typeBuilder.potentiallyCheckOrTrustType( 611 value = typeBuilder.potentiallyCheckOrTrustType(
610 value, astAdapter.getFunctionReturnType(_targetFunction)); 612 value, astAdapter.getFunctionReturnType(_targetFunction));
611 } 613 }
612 } 614 }
613 // TODO(het): Add source information 615 // TODO(het): Add source information
616 handleInTryStatement();
614 // TODO(het): Set a return value instead of closing the function when we 617 // TODO(het): Set a return value instead of closing the function when we
615 // support inlining. 618 // support inlining.
616 closeAndGotoExit(new HReturn(value, null)); 619 closeAndGotoExit(new HReturn(value, null));
617 } 620 }
618 621
619 @override 622 @override
620 void visitForStatement(ir.ForStatement forStatement) { 623 void visitForStatement(ir.ForStatement forStatement) {
621 assert(isReachable); 624 assert(isReachable);
622 assert(forStatement.body != null); 625 assert(forStatement.body != null);
623 void buildInitializer() { 626 void buildInitializer() {
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
897 @override 900 @override
898 visitDoStatement(ir.DoStatement doStatement) { 901 visitDoStatement(ir.DoStatement doStatement) {
899 // TODO(efortuna): I think this can be rewritten using 902 // TODO(efortuna): I think this can be rewritten using
900 // LoopHandler.handleLoop with some tricks about when the "update" happens. 903 // LoopHandler.handleLoop with some tricks about when the "update" happens.
901 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); 904 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler);
902 localsHandler.startLoop(astAdapter.getNode(doStatement)); 905 localsHandler.startLoop(astAdapter.getNode(doStatement));
903 JumpHandler jumpHandler = loopHandler.beginLoopHeader(doStatement); 906 JumpHandler jumpHandler = loopHandler.beginLoopHeader(doStatement);
904 HLoopInformation loopInfo = current.loopInformation; 907 HLoopInformation loopInfo = current.loopInformation;
905 HBasicBlock loopEntryBlock = current; 908 HBasicBlock loopEntryBlock = current;
906 HBasicBlock bodyEntryBlock = current; 909 HBasicBlock bodyEntryBlock = current;
907 JumpTarget target = astAdapter.elements 910 JumpTarget target = astAdapter.getJumpTarget(doStatement);
908 .getTargetDefinition(astAdapter.getNode(doStatement));
909 bool hasContinues = target != null && target.isContinueTarget; 911 bool hasContinues = target != null && target.isContinueTarget;
910 if (hasContinues) { 912 if (hasContinues) {
911 // Add extra block to hang labels on. 913 // Add extra block to hang labels on.
912 // It doesn't currently work if they are on the same block as the 914 // It doesn't currently work if they are on the same block as the
913 // HLoopInfo. The handling of HLabeledBlockInformation will visit a 915 // HLoopInfo. The handling of HLabeledBlockInformation will visit a
914 // SubGraph that starts at the same block again, so the HLoopInfo is 916 // SubGraph that starts at the same block again, so the HLoopInfo is
915 // either handled twice, or it's handled after the labeled block info, 917 // either handled twice, or it's handled after the labeled block info,
916 // both of which generate the wrong code. 918 // both of which generate the wrong code.
917 // Using a separate block is just a simple workaround. 919 // Using a separate block is just a simple workaround.
918 bodyEntryBlock = openNewBlock(); 920 bodyEntryBlock = openNewBlock();
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
1010 loopEntryBlock.loopInformation = null; 1012 loopEntryBlock.loopInformation = null;
1011 1013
1012 if (jumpHandler.hasAnyBreak()) { 1014 if (jumpHandler.hasAnyBreak()) {
1013 // Null branchBlock because the body of the do-while loop always aborts, 1015 // Null branchBlock because the body of the do-while loop always aborts,
1014 // so we never get to the condition. 1016 // so we never get to the condition.
1015 loopHandler.endLoop(loopEntryBlock, null, jumpHandler, localsHandler); 1017 loopHandler.endLoop(loopEntryBlock, null, jumpHandler, localsHandler);
1016 1018
1017 // Since the body of the loop has a break, we attach a synthesized label 1019 // Since the body of the loop has a break, we attach a synthesized label
1018 // to the body. 1020 // to the body.
1019 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); 1021 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock);
1020 JumpTarget target = astAdapter.elements 1022 JumpTarget target = astAdapter.getJumpTarget(doStatement);
1021 .getTargetDefinition(astAdapter.getNode(doStatement));
1022 LabelDefinition label = target.addLabel(null, 'loop'); 1023 LabelDefinition label = target.addLabel(null, 'loop');
1023 label.setBreakTarget(); 1024 label.setBreakTarget();
1024 HLabeledBlockInformation info = new HLabeledBlockInformation( 1025 HLabeledBlockInformation info = new HLabeledBlockInformation(
1025 new HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]); 1026 new HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]);
1026 loopEntryBlock.setBlockFlow(info, current); 1027 loopEntryBlock.setBlockFlow(info, current);
1027 jumpHandler.forEachBreak((HBreak breakInstruction, _) { 1028 jumpHandler.forEachBreak((HBreak breakInstruction, _) {
1028 HBasicBlock block = breakInstruction.block; 1029 HBasicBlock block = breakInstruction.block;
1029 block.addAtExit(new HBreak.toLabel(label)); 1030 block.addAtExit(new HBreak.toLabel(label));
1030 block.remove(breakInstruction); 1031 block.remove(breakInstruction);
1031 }); 1032 });
1032 } 1033 }
1033 } 1034 }
1034 jumpHandler.close(); 1035 jumpHandler.close();
1035 } 1036 }
1036 1037
1037 @override 1038 @override
1038 void visitIfStatement(ir.IfStatement ifStatement) { 1039 void visitIfStatement(ir.IfStatement ifStatement) {
1039 handleIf( 1040 handleIf(
1040 visitCondition: () => ifStatement.condition.accept(this), 1041 visitCondition: () => ifStatement.condition.accept(this),
1041 visitThen: () => ifStatement.then.accept(this), 1042 visitThen: () => ifStatement.then.accept(this),
1042 visitElse: () => ifStatement.otherwise?.accept(this)); 1043 visitElse: () => ifStatement.otherwise?.accept(this));
1043 } 1044 }
1044 1045
1046 void handleIf(
1047 {ir.Node node,
1048 void visitCondition(),
1049 void visitThen(),
1050 void visitElse(),
1051 SourceInformation sourceInformation}) {
1052 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(
1053 this, compiler, node == null ? node : astAdapter.getNode(node));
1054 branchBuilder.handleIf(visitCondition, visitThen, visitElse,
1055 sourceInformation: sourceInformation);
1056 }
1057
1045 @override 1058 @override
1046 void visitAsExpression(ir.AsExpression asExpression) { 1059 void visitAsExpression(ir.AsExpression asExpression) {
1047 asExpression.operand.accept(this); 1060 asExpression.operand.accept(this);
1048 HInstruction expressionInstruction = pop(); 1061 HInstruction expressionInstruction = pop();
1049 1062
1050 if (asExpression.type is ir.InvalidType) { 1063 if (asExpression.type is ir.InvalidType) {
1051 generateTypeError(asExpression, 'invalid type'); 1064 generateTypeError(asExpression, 'invalid type');
1052 stack.add(expressionInstruction); 1065 stack.add(expressionInstruction);
1053 return; 1066 return;
1054 } 1067 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
1108 void fail() { 1121 void fail() {
1109 assertStatement.message.accept(this); 1122 assertStatement.message.accept(this);
1110 _pushStaticInvocation(astAdapter.assertThrow, <HInstruction>[pop()], 1123 _pushStaticInvocation(astAdapter.assertThrow, <HInstruction>[pop()],
1111 astAdapter.assertThrowReturnType); 1124 astAdapter.assertThrowReturnType);
1112 pop(); 1125 pop();
1113 } 1126 }
1114 1127
1115 handleIf(visitCondition: buildCondition, visitThen: fail); 1128 handleIf(visitCondition: buildCondition, visitThen: fail);
1116 } 1129 }
1117 1130
1131 /// Creates a [JumpHandler] for a statement. The node must be a jump
1132 /// target. If there are no breaks or continues targeting the statement,
1133 /// a special "null handler" is returned.
1134 ///
1135 /// [isLoopJump] is true when the jump handler is for a loop. This is used
1136 /// to distinguish the synthesized loop created for a switch statement with
1137 /// continue statements from simple switch statements.
1138 JumpHandler createJumpHandler(ir.TreeNode node, {bool isLoopJump: false}) {
1139 JumpTarget target = astAdapter.getJumpTarget(node);
1140 assert(target is KernelJumpTarget);
1141 if (target == null) {
1142 // No breaks or continues to this node.
1143 return new NullJumpHandler(compiler.reporter);
1144 }
1145 if (isLoopJump && node is ir.SwitchStatement) {
1146 throw 'Kernel Switch Statement handler not yet implemented.';
1147 }
1148
1149 return new JumpHandler(this, target);
1150 }
1151
1118 @override 1152 @override
1119 void visitBreakStatement(ir.BreakStatement breakStatement) { 1153 void visitBreakStatement(ir.BreakStatement breakStatement) {
1120 assert(!isAborted()); 1154 assert(!isAborted());
1155 handleInTryStatement();
1121 JumpTarget target = astAdapter.getJumpTarget(breakStatement.target); 1156 JumpTarget target = astAdapter.getJumpTarget(breakStatement.target);
1122 assert(target != null); 1157 assert(target != null);
1123 JumpHandler handler = jumpTargets[target]; 1158 JumpHandler handler = jumpTargets[target];
1124 assert(handler != null); 1159 assert(handler != null);
1125 handler.generateBreak(handler.labels.first); 1160 if (handler.labels.isNotEmpty) {
1161 handler.generateBreak(handler.labels.first);
1162 } else {
1163 handler.generateBreak();
1164 }
1126 } 1165 }
1127 1166
1128 @override 1167 @override
1129 void visitLabeledStatement(ir.LabeledStatement labeledStatement) { 1168 void visitLabeledStatement(ir.LabeledStatement labeledStatement) {
1130 JumpTarget target = astAdapter.getJumpTarget(labeledStatement);
1131 JumpHandler handler = new JumpHandler(this, target);
1132
1133 ir.Statement body = labeledStatement.body; 1169 ir.Statement body = labeledStatement.body;
1134 if (body is ir.WhileStatement || 1170 if (body is ir.WhileStatement ||
1135 body is ir.DoStatement || 1171 body is ir.DoStatement ||
1136 body is ir.ForStatement || 1172 body is ir.ForStatement ||
1137 body is ir.ForInStatement) { 1173 body is ir.ForInStatement ||
1138 // loops handle breaks on their own 1174 body is ir.SwitchStatement) {
1175 // loops and switches handle breaks on their own
1139 body.accept(this); 1176 body.accept(this);
1140 return; 1177 return;
1141 } 1178 }
1179 JumpHandler handler = createJumpHandler(labeledStatement);
1180
1142 LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler); 1181 LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler);
1143 1182
1144 HBasicBlock newBlock = openNewBlock(); 1183 HBasicBlock newBlock = openNewBlock();
1145 body.accept(this); 1184 body.accept(this);
1146 SubGraph bodyGraph = new SubGraph(newBlock, lastOpenedBlock); 1185 SubGraph bodyGraph = new SubGraph(newBlock, lastOpenedBlock);
1147 1186
1148 HBasicBlock joinBlock = graph.addNewBlock(); 1187 HBasicBlock joinBlock = graph.addNewBlock();
1149 List<LocalsHandler> breakHandlers = <LocalsHandler>[]; 1188 List<LocalsHandler> breakHandlers = <LocalsHandler>[];
1150 handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { 1189 handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) {
1151 breakInstruction.block.addSuccessor(joinBlock); 1190 breakInstruction.block.addSuccessor(joinBlock);
1152 breakHandlers.add(locals); 1191 breakHandlers.add(locals);
1153 }); 1192 });
1154 1193
1155 if (!isAborted()) { 1194 if (!isAborted()) {
1156 goto(current, joinBlock); 1195 goto(current, joinBlock);
1157 breakHandlers.add(localsHandler); 1196 breakHandlers.add(localsHandler);
1158 } 1197 }
1159 1198
1160 open(joinBlock); 1199 open(joinBlock);
1161 localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock); 1200 localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock);
1162 1201
1163 // There was at least one reachable break, so the label is needed. 1202 // There was at least one reachable break, so the label is needed.
1164 newBlock.setBlockFlow( 1203 newBlock.setBlockFlow(
1165 new HLabeledBlockInformation( 1204 new HLabeledBlockInformation(
1166 new HSubGraphBlockInformation(bodyGraph), handler.labels), 1205 new HSubGraphBlockInformation(bodyGraph), handler.labels),
1167 joinBlock); 1206 joinBlock);
1168 handler.close(); 1207 handler.close();
1169 } 1208 }
1170 1209
1210 /// Loop through the cases in a switch and create a mapping of case
1211 /// expressions to constants.
1212 Map<ir.Expression, ConstantValue> _buildSwitchCaseConstants(
1213 ir.SwitchStatement switchStatement) {
1214 Map<ir.Expression, ConstantValue> constants =
1215 new Map<ir.Expression, ConstantValue>();
1216 for (ir.SwitchCase switchCase in switchStatement.cases) {
1217 for (ir.Expression caseExpression in switchCase.expressions) {
1218 ConstantValue constant = astAdapter.getConstantFor(caseExpression);
1219 constants[caseExpression] = constant;
1220 }
1221 }
1222 return constants;
1223 }
1224
1225 @override
1226 void visitContinueSwitchStatement(
1227 ir.ContinueSwitchStatement switchStatement) {
1228 handleInTryStatement();
1229 JumpTarget target = astAdapter.getJumpTarget(switchStatement.target);
1230 assert(target != null);
1231 JumpHandler handler = jumpTargets[target];
1232 assert(handler != null);
1233 assert(target.labels.isNotEmpty);
1234 handler.generateContinue(target.labels.first);
1235 }
1236
1237 @override
1238 void visitSwitchStatement(ir.SwitchStatement switchStatement) {
1239 Map<ir.Expression, ConstantValue> constants =
1240 _buildSwitchCaseConstants(switchStatement);
1241
1242 // The switch case indices must match those computed in
1243 // [KernelSwitchCaseJumpHandler].
1244 bool hasContinue = false;
1245 Map<ir.SwitchCase, int> caseIndex = new Map<ir.SwitchCase, int>();
1246 int switchIndex = 1;
1247 bool hasDefault = false;
1248 for (ir.SwitchCase switchCase in switchStatement.cases) {
1249 if (SwitchContinueAnalysis.containsContinue(switchCase.body)) {
1250 hasContinue = true;
1251 }
1252 if (switchCase.isDefault) {
1253 hasDefault = true;
1254 }
1255 caseIndex[switchCase] = switchIndex;
1256 switchIndex++;
1257 }
1258
1259 JumpHandler jumpHandler = createJumpHandler(switchStatement);
1260 if (!hasContinue) {
1261 // If the switch statement has no switch cases targeted by continue
1262 // statements we encode the switch statement directly.
1263 _buildSimpleSwitchStatement(switchStatement, jumpHandler, constants);
1264 } else {
1265 throw 'Complex switch statement with continue label not implemented yet.';
1266 }
1267 }
1268
1269 /// Helper for building switch statements.
1270 static bool _isDefaultCase(ir.SwitchCase switchCase) =>
1271 switchCase == null || switchCase.isDefault;
1272
1273 /// Builds a simple switch statement which does not handle uses of continue
1274 /// statements to labeled switch cases.
1275 void _buildSimpleSwitchStatement(ir.SwitchStatement switchStatement,
1276 JumpHandler jumpHandler, Map<ir.Expression, ConstantValue> constants) {
1277 void buildSwitchCase(ir.SwitchCase switchCase) {
1278 switchCase.body.accept(this);
1279 }
1280
1281 handleSwitch(switchStatement, jumpHandler, switchStatement.cases,
1282 _isDefaultCase, buildSwitchCase, constants);
1283 jumpHandler.close();
1284 }
1285
1286 /// Creates a switch statement.
1287 ///
1288 /// [jumpHandler] is the [JumpHandler] for the created switch statement.
1289 /// [buildSwitchCase] creates the statements for the switch case.
1290 void handleSwitch(
1291 ir.SwitchStatement switchStatement,
1292 JumpHandler jumpHandler,
1293 List<ir.SwitchCase> switchCases,
1294 bool isDefaultCase(ir.SwitchCase switchCase),
1295 void buildSwitchCase(ir.SwitchCase switchCase),
1296 Map<ir.Expression, ConstantValue> constantsLookup) {
1297 HBasicBlock expressionStart = openNewBlock();
1298 switchStatement.expression.accept(this);
1299 HInstruction expression = pop();
1300
1301 List<ConstantValue> getConstants(ir.SwitchCase switchCase) {
1302 List<ConstantValue> constantList = <ConstantValue>[];
1303 if (switchCase != null) {
1304 for (var expression in switchCase.expressions) {
1305 constantList.add(constantsLookup[expression]);
1306 }
1307 }
1308 return constantList;
1309 }
1310
1311 if (switchCases.isEmpty) {
1312 return;
1313 }
1314
1315 HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]);
1316 HBasicBlock expressionEnd = close(switchInstruction);
1317 LocalsHandler savedLocals = localsHandler;
1318
1319 List<HStatementInformation> statements = <HStatementInformation>[];
1320 bool hasDefault = false;
1321 for (ir.SwitchCase switchCase in switchCases) {
1322 HBasicBlock block = graph.addNewBlock();
1323 for (ConstantValue constant in getConstants(switchCase)) {
1324 HConstant hConstant = graph.addConstant(constant, closedWorld);
1325 switchInstruction.inputs.add(hConstant);
1326 hConstant.usedBy.add(switchInstruction);
1327 expressionEnd.addSuccessor(block);
1328 }
1329
1330 if (isDefaultCase(switchCase)) {
1331 // An HSwitch has n inputs and n+1 successors, the last being the
1332 // default case.
1333 expressionEnd.addSuccessor(block);
1334 hasDefault = true;
1335 }
1336 open(block);
1337 localsHandler = new LocalsHandler.from(savedLocals);
1338 buildSwitchCase(switchCase);
1339 statements.add(
1340 new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock)));
1341 }
1342
1343 // Add a join-block if necessary.
1344 // We create [joinBlock] early, and then go through the cases that might
1345 // want to jump to it. In each case, if we add [joinBlock] as a successor
1346 // of another block, we also add an element to [caseHandlers] that is used
1347 // to create the phis in [joinBlock].
1348 // If we never jump to the join block, [caseHandlers] will stay empty, and
1349 // the join block is never added to the graph.
1350 HBasicBlock joinBlock = new HBasicBlock();
1351 List<LocalsHandler> caseHandlers = <LocalsHandler>[];
1352 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) {
1353 instruction.block.addSuccessor(joinBlock);
1354 caseHandlers.add(locals);
1355 });
1356 jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) {
1357 assert(invariant(astAdapter.getNode(switchStatement), false,
1358 message: 'Continue cannot target a switch.'));
1359 });
1360 if (!isAborted()) {
1361 current.close(new HGoto());
1362 lastOpenedBlock.addSuccessor(joinBlock);
1363 caseHandlers.add(localsHandler);
1364 }
1365 if (!hasDefault) {
1366 // Always create a default case, to avoid a critical edge in the
1367 // graph.
1368 HBasicBlock defaultCase = addNewBlock();
1369 expressionEnd.addSuccessor(defaultCase);
1370 open(defaultCase);
1371 close(new HGoto());
1372 defaultCase.addSuccessor(joinBlock);
1373 caseHandlers.add(savedLocals);
1374 statements.add(new HSubGraphBlockInformation(
1375 new SubGraph(defaultCase, defaultCase)));
1376 }
1377 assert(caseHandlers.length == joinBlock.predecessors.length);
1378 if (caseHandlers.length != 0) {
1379 graph.addBlock(joinBlock);
1380 open(joinBlock);
1381 if (caseHandlers.length == 1) {
1382 localsHandler = caseHandlers[0];
1383 } else {
1384 localsHandler = savedLocals.mergeMultiple(caseHandlers, joinBlock);
1385 }
1386 } else {
1387 // The joinblock is not used.
1388 joinBlock = null;
1389 }
1390
1391 HSubExpressionBlockInformation expressionInfo =
1392 new HSubExpressionBlockInformation(
1393 new SubExpression(expressionStart, expressionEnd));
1394 expressionStart.setBlockFlow(
1395 new HSwitchBlockInformation(
1396 expressionInfo, statements, jumpHandler.target, jumpHandler.labels),
1397 joinBlock);
1398
1399 jumpHandler.close();
1400 }
1401
1171 @override 1402 @override
1172 void visitConditionalExpression(ir.ConditionalExpression conditional) { 1403 void visitConditionalExpression(ir.ConditionalExpression conditional) {
1173 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler); 1404 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler);
1174 brancher.handleConditional( 1405 brancher.handleConditional(
1175 () => conditional.condition.accept(this), 1406 () => conditional.condition.accept(this),
1176 () => conditional.then.accept(this), 1407 () => conditional.then.accept(this),
1177 () => conditional.otherwise.accept(this)); 1408 () => conditional.otherwise.accept(this));
1178 } 1409 }
1179 1410
1180 @override 1411 @override
(...skipping 1138 matching lines...) Expand 10 before | Expand all | Expand 10 after
2319 (ir.DartType typeArgType) => 2550 (ir.DartType typeArgType) =>
2320 typeArgType is! ir.DynamicType && 2551 typeArgType is! ir.DynamicType &&
2321 typeArgType is! ir.InvalidType && 2552 typeArgType is! ir.InvalidType &&
2322 !isMethodTypeVariableType(type)); 2553 !isMethodTypeVariableType(type));
2323 } 2554 }
2324 2555
2325 @override 2556 @override
2326 void visitThrow(ir.Throw throwNode) { 2557 void visitThrow(ir.Throw throwNode) {
2327 _visitThrowExpression(throwNode.expression); 2558 _visitThrowExpression(throwNode.expression);
2328 if (isReachable) { 2559 if (isReachable) {
2560 handleInTryStatement();
2329 push(new HThrowExpression(pop(), null)); 2561 push(new HThrowExpression(pop(), null));
2330 isReachable = false; 2562 isReachable = false;
2331 } 2563 }
2332 } 2564 }
2333 2565
2334 void _visitThrowExpression(ir.Expression expression) { 2566 void _visitThrowExpression(ir.Expression expression) {
2335 bool old = _inExpressionOfThrow; 2567 bool old = _inExpressionOfThrow;
2336 try { 2568 try {
2337 _inExpressionOfThrow = true; 2569 _inExpressionOfThrow = true;
2338 expression.accept(this); 2570 expression.accept(this);
(...skipping 16 matching lines...) Expand all
2355 } 2587 }
2356 2588
2357 @override 2589 @override
2358 void visitRethrow(ir.Rethrow rethrowNode) { 2590 void visitRethrow(ir.Rethrow rethrowNode) {
2359 HInstruction exception = rethrowableException; 2591 HInstruction exception = rethrowableException;
2360 if (exception == null) { 2592 if (exception == null) {
2361 exception = graph.addConstantNull(closedWorld); 2593 exception = graph.addConstantNull(closedWorld);
2362 compiler.reporter.internalError(astAdapter.getNode(rethrowNode), 2594 compiler.reporter.internalError(astAdapter.getNode(rethrowNode),
2363 'rethrowableException should not be null.'); 2595 'rethrowableException should not be null.');
2364 } 2596 }
2597 handleInTryStatement();
2365 SourceInformation sourceInformation = null; 2598 SourceInformation sourceInformation = null;
2366 closeAndGotoExit(new HThrow(exception, sourceInformation, isRethrow: true)); 2599 closeAndGotoExit(new HThrow(exception, sourceInformation, isRethrow: true));
2367 // ir.Rethrow is an expression so we need to push a value - a constant with 2600 // ir.Rethrow is an expression so we need to push a value - a constant with
2368 // no type. 2601 // no type.
2369 stack.add(graph.addConstantUnreachable(closedWorld)); 2602 stack.add(graph.addConstantUnreachable(closedWorld));
2370 } 2603 }
2371 2604
2372 @override 2605 @override
2373 void visitThisExpression(ir.ThisExpression thisExpression) { 2606 void visitThisExpression(ir.ThisExpression thisExpression) {
2374 stack.add(localsHandler.readThis()); 2607 stack.add(localsHandler.readThis());
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
2439 HBasicBlock endTryBlock; 2672 HBasicBlock endTryBlock;
2440 HBasicBlock startCatchBlock; 2673 HBasicBlock startCatchBlock;
2441 HBasicBlock endCatchBlock; 2674 HBasicBlock endCatchBlock;
2442 HBasicBlock startFinallyBlock; 2675 HBasicBlock startFinallyBlock;
2443 HBasicBlock endFinallyBlock; 2676 HBasicBlock endFinallyBlock;
2444 HBasicBlock exitBlock; 2677 HBasicBlock exitBlock;
2445 HTry tryInstruction; 2678 HTry tryInstruction;
2446 HLocalValue exception; 2679 HLocalValue exception;
2447 KernelSsaBuilder kernelBuilder; 2680 KernelSsaBuilder kernelBuilder;
2448 2681
2682 /// True if the code surrounding this try statement was also part of a
2683 /// try/catch/finally statement.
2684 bool previouslyInTryStatement;
2685
2449 SubGraph bodyGraph; 2686 SubGraph bodyGraph;
2450 SubGraph catchGraph; 2687 SubGraph catchGraph;
2451 SubGraph finallyGraph; 2688 SubGraph finallyGraph;
2452 2689
2453 // The original set of locals that were defined before this try block. 2690 // The original set of locals that were defined before this try block.
2454 // The catch block and the finally block must not reuse the existing locals 2691 // The catch block and the finally block must not reuse the existing locals
2455 // handler. None of the variables that have been defined in the body-block 2692 // handler. None of the variables that have been defined in the body-block
2456 // will be used, but for loops we will add (unnecessary) phis that will 2693 // will be used, but for loops we will add (unnecessary) phis that will
2457 // reference the body variables. This makes it look as if the variables were 2694 // reference the body variables. This makes it look as if the variables were
2458 // used in a non-dominated block. 2695 // used in a non-dominated block.
2459 LocalsHandler originalSavedLocals; 2696 LocalsHandler originalSavedLocals;
2460 2697
2461 TryCatchFinallyBuilder(this.kernelBuilder) { 2698 TryCatchFinallyBuilder(this.kernelBuilder) {
2462 tryInstruction = new HTry(); 2699 tryInstruction = new HTry();
2463 originalSavedLocals = new LocalsHandler.from(kernelBuilder.localsHandler); 2700 originalSavedLocals = new LocalsHandler.from(kernelBuilder.localsHandler);
2464 enterBlock = kernelBuilder.openNewBlock(); 2701 enterBlock = kernelBuilder.openNewBlock();
2465 kernelBuilder.close(tryInstruction); 2702 kernelBuilder.close(tryInstruction);
2703 previouslyInTrySequence = kernelBuilder.inTryStatement;
2704 kernelBuilder.inTryStatement = true;
2466 2705
2467 startTryBlock = kernelBuilder.graph.addNewBlock(); 2706 startTryBlock = kernelBuilder.graph.addNewBlock();
2468 kernelBuilder.open(startTryBlock); 2707 kernelBuilder.open(startTryBlock);
2469 } 2708 }
2470 2709
2471 void _addExitTrySuccessor(successor) { 2710 void _addExitTrySuccessor(successor) {
2472 if (successor == null) return; 2711 if (successor == null) return;
2473 // Iterate over all blocks created inside this try/catch, and 2712 // Iterate over all blocks created inside this try/catch, and
2474 // attach successor information to blocks that end with 2713 // attach successor information to blocks that end with
2475 // [HExitTry]. 2714 // [HExitTry].
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
2637 // blocks. 2876 // blocks.
2638 kernelBuilder.localsHandler = originalSavedLocals; 2877 kernelBuilder.localsHandler = originalSavedLocals;
2639 kernelBuilder.open(exitBlock); 2878 kernelBuilder.open(exitBlock);
2640 enterBlock.setBlockFlow( 2879 enterBlock.setBlockFlow(
2641 new HTryBlockInformation( 2880 new HTryBlockInformation(
2642 kernelBuilder.wrapStatementGraph(bodyGraph), 2881 kernelBuilder.wrapStatementGraph(bodyGraph),
2643 exception, 2882 exception,
2644 kernelBuilder.wrapStatementGraph(catchGraph), 2883 kernelBuilder.wrapStatementGraph(catchGraph),
2645 kernelBuilder.wrapStatementGraph(finallyGraph)), 2884 kernelBuilder.wrapStatementGraph(finallyGraph)),
2646 exitBlock); 2885 exitBlock);
2886 kernelBuilder.inTryStatement = previouslyInTrySequence;
2647 } 2887 }
2648 } 2888 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/builder.dart ('k') | pkg/compiler/lib/src/ssa/graph_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698