Chromium Code Reviews| 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 @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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |