| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |