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_handler.dart'; | |
| 43 import 'type_builder.dart'; | 44 import 'type_builder.dart'; |
| 44 import 'types.dart' show TypeMaskFactory; | 45 import 'types.dart' show TypeMaskFactory; |
| 45 | 46 |
| 46 class SsaKernelBuilderTask extends CompilerTask { | 47 class SsaKernelBuilderTask extends CompilerTask { |
| 47 final JavaScriptBackend backend; | 48 final JavaScriptBackend backend; |
| 48 final SourceInformationStrategy sourceInformationFactory; | 49 final SourceInformationStrategy sourceInformationFactory; |
| 49 | 50 |
| 50 String get name => 'SSA kernel builder'; | 51 String get name => 'SSA kernel builder'; |
| 51 | 52 |
| 52 SsaKernelBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) | 53 SsaKernelBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) |
| (...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after 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 ResolutionDartType type = astAdapter.getDartType(asExpression.type); | 978 ResolutionDartType type = astAdapter.getDartType(asExpression.type); |
| 966 if (type.isMalformed) { | 979 if (type.isMalformed) { |
| 967 if (type is MalformedType) { | 980 if (type is MalformedType) { |
| 968 ErroneousElement element = type.element; | 981 ErroneousElement element = type.element; |
| 969 generateTypeError(asExpression, element.message); | 982 generateTypeError(asExpression, element.message); |
| 970 } else { | 983 } else { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1014 void fail() { | 1027 void fail() { |
| 1015 assertStatement.message.accept(this); | 1028 assertStatement.message.accept(this); |
| 1016 _pushStaticInvocation(astAdapter.assertThrow, <HInstruction>[pop()], | 1029 _pushStaticInvocation(astAdapter.assertThrow, <HInstruction>[pop()], |
| 1017 astAdapter.assertThrowReturnType); | 1030 astAdapter.assertThrowReturnType); |
| 1018 pop(); | 1031 pop(); |
| 1019 } | 1032 } |
| 1020 | 1033 |
| 1021 handleIf(visitCondition: buildCondition, visitThen: fail); | 1034 handleIf(visitCondition: buildCondition, visitThen: fail); |
| 1022 } | 1035 } |
| 1023 | 1036 |
| 1037 /// Creates a [JumpHandler] for a statement. The node must be a jump | |
| 1038 /// target. If there are no breaks or continues targeting the statement, | |
| 1039 /// a special "null handler" is returned. | |
| 1040 /// | |
| 1041 /// [isLoopJump] is [:true:] when the jump handler is for a loop. This is used | |
|
sra1
2017/01/14 03:18:22
[:x:] --> `x`
Emily Fortuna
2017/01/17 23:33:09
Done.
| |
| 1042 /// to distinguish the synthesized loop created for a switch statement with | |
| 1043 /// continue statements from simple switch statements. | |
| 1044 JumpHandler createJumpHandler(ir.TreeNode node, {bool isLoopJump: false}) { | |
| 1045 JumpTarget target = astAdapter.getJumpTarget(node); | |
| 1046 assert(target is KernelJumpTarget); | |
| 1047 if (target == null) { | |
| 1048 // No breaks or continues to this node. | |
| 1049 return new NullJumpHandler(compiler.reporter); | |
| 1050 } | |
| 1051 if (isLoopJump && node is ir.SwitchStatement) { | |
| 1052 throw 'Kernel Switch Statement handler not yet implemented.'; | |
| 1053 } | |
| 1054 | |
| 1055 return new JumpHandler(this, target); | |
| 1056 } | |
| 1057 | |
| 1024 @override | 1058 @override |
| 1025 void visitBreakStatement(ir.BreakStatement breakStatement) { | 1059 void visitBreakStatement(ir.BreakStatement breakStatement) { |
| 1026 assert(!isAborted()); | 1060 assert(!isAborted()); |
| 1061 handleInTryStatement(); | |
| 1027 JumpTarget target = astAdapter.getJumpTarget(breakStatement.target); | 1062 JumpTarget target = astAdapter.getJumpTarget(breakStatement.target); |
| 1028 assert(target != null); | 1063 assert(target != null); |
| 1029 JumpHandler handler = jumpTargets[target]; | 1064 JumpHandler handler = jumpTargets[target]; |
| 1030 assert(handler != null); | 1065 assert(handler != null); |
| 1031 handler.generateBreak(handler.labels.first); | 1066 if (handler.labels.isNotEmpty) { |
| 1067 handler.generateBreak(handler.labels.first); | |
| 1068 } else { | |
| 1069 handler.generateBreak(); | |
| 1070 } | |
| 1032 } | 1071 } |
| 1033 | 1072 |
| 1034 @override | 1073 @override |
| 1035 void visitLabeledStatement(ir.LabeledStatement labeledStatement) { | 1074 void visitLabeledStatement(ir.LabeledStatement labeledStatement) { |
| 1036 JumpTarget target = astAdapter.getJumpTarget(labeledStatement); | |
| 1037 JumpHandler handler = new JumpHandler(this, target); | |
| 1038 | |
| 1039 ir.Statement body = labeledStatement.body; | 1075 ir.Statement body = labeledStatement.body; |
| 1040 if (body is ir.WhileStatement || | 1076 if (body is ir.WhileStatement || |
| 1041 body is ir.DoStatement || | 1077 body is ir.DoStatement || |
| 1042 body is ir.ForStatement || | 1078 body is ir.ForStatement || |
| 1043 body is ir.ForInStatement) { | 1079 body is ir.ForInStatement || |
| 1044 // loops handle breaks on their own | 1080 body is ir.SwitchStatement) { |
| 1081 // loops and switches handle breaks on their own | |
| 1045 body.accept(this); | 1082 body.accept(this); |
| 1046 return; | 1083 return; |
| 1047 } | 1084 } |
| 1085 JumpHandler handler = createJumpHandler(labeledStatement); | |
| 1086 | |
| 1048 LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler); | 1087 LocalsHandler beforeLocals = new LocalsHandler.from(localsHandler); |
| 1049 | 1088 |
| 1050 HBasicBlock newBlock = openNewBlock(); | 1089 HBasicBlock newBlock = openNewBlock(); |
| 1051 body.accept(this); | 1090 body.accept(this); |
| 1052 SubGraph bodyGraph = new SubGraph(newBlock, lastOpenedBlock); | 1091 SubGraph bodyGraph = new SubGraph(newBlock, lastOpenedBlock); |
| 1053 | 1092 |
| 1054 HBasicBlock joinBlock = graph.addNewBlock(); | 1093 HBasicBlock joinBlock = graph.addNewBlock(); |
| 1055 List<LocalsHandler> breakHandlers = <LocalsHandler>[]; | 1094 List<LocalsHandler> breakHandlers = <LocalsHandler>[]; |
| 1056 handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { | 1095 handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { |
| 1057 breakInstruction.block.addSuccessor(joinBlock); | 1096 breakInstruction.block.addSuccessor(joinBlock); |
| 1058 breakHandlers.add(locals); | 1097 breakHandlers.add(locals); |
| 1059 }); | 1098 }); |
| 1060 | 1099 |
| 1061 if (!isAborted()) { | 1100 if (!isAborted()) { |
| 1062 goto(current, joinBlock); | 1101 goto(current, joinBlock); |
| 1063 breakHandlers.add(localsHandler); | 1102 breakHandlers.add(localsHandler); |
| 1064 } | 1103 } |
| 1065 | 1104 |
| 1066 open(joinBlock); | 1105 open(joinBlock); |
| 1067 localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock); | 1106 localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock); |
| 1068 | 1107 |
| 1069 // There was at least one reachable break, so the label is needed. | 1108 // There was at least one reachable break, so the label is needed. |
| 1070 newBlock.setBlockFlow( | 1109 newBlock.setBlockFlow( |
| 1071 new HLabeledBlockInformation( | 1110 new HLabeledBlockInformation( |
| 1072 new HSubGraphBlockInformation(bodyGraph), handler.labels), | 1111 new HSubGraphBlockInformation(bodyGraph), handler.labels), |
| 1073 joinBlock); | 1112 joinBlock); |
| 1074 handler.close(); | 1113 handler.close(); |
| 1075 } | 1114 } |
| 1076 | 1115 |
| 1116 /// Loop through the cases in a switch and create a mapping of case | |
| 1117 /// expressions to constants. | |
| 1118 Map<ir.Expression, ConstantValue> buildSwitchCaseConstants( | |
| 1119 ir.SwitchStatement switchStatement) { | |
| 1120 Map<ir.Expression, ConstantValue> constants = | |
| 1121 new Map<ir.Expression, ConstantValue>(); | |
| 1122 for (ir.SwitchCase switchCase in switchStatement.cases) { | |
| 1123 for (ir.Expression caseExpression in switchCase.expressions) { | |
| 1124 ConstantValue constant = astAdapter.getConstantFor(caseExpression); | |
| 1125 constants[caseExpression] = constant; | |
| 1126 } | |
| 1127 } | |
| 1128 return constants; | |
| 1129 } | |
| 1130 | |
| 1131 @override | |
| 1132 void visitContinueSwitchStatement( | |
| 1133 ir.ContinueSwitchStatement switchStatement) { | |
| 1134 handleInTryStatement(); | |
| 1135 JumpTarget target = astAdapter.getJumpTarget(switchStatement.target); | |
| 1136 assert(target != null); | |
| 1137 JumpHandler handler = jumpTargets[target]; | |
| 1138 assert(handler != null); | |
| 1139 assert(target.labels.isNotEmpty); | |
| 1140 handler.generateContinue(target.labels.first); | |
| 1141 } | |
| 1142 | |
| 1143 @override | |
| 1144 void visitSwitchStatement(ir.SwitchStatement switchStatement) { | |
| 1145 Map<ir.Expression, ConstantValue> constants = | |
| 1146 buildSwitchCaseConstants(switchStatement); | |
| 1147 | |
| 1148 // The switch case indices must match those computed in | |
| 1149 // [KernelSwitchCaseJumpHandler]. | |
| 1150 bool hasContinue = false; | |
| 1151 Map<ir.SwitchCase, int> caseIndex = new Map<ir.SwitchCase, int>(); | |
| 1152 int switchIndex = 1; | |
| 1153 bool hasDefault = false; | |
| 1154 for (ir.SwitchCase switchCase in switchStatement.cases) { | |
| 1155 if ((new ContinueVisitor(switchCase.body)).containsContinue) { | |
|
sra1
2017/01/14 03:18:22
Maybe make the visitor have a static method and pr
Emily Fortuna
2017/01/17 23:33:09
Done.
| |
| 1156 hasContinue = true; | |
| 1157 } | |
| 1158 if (switchCase.isDefault) { | |
| 1159 hasDefault = true; | |
| 1160 } | |
| 1161 caseIndex[switchCase] = switchIndex; | |
| 1162 switchIndex++; | |
| 1163 } | |
| 1164 | |
| 1165 JumpHandler jumpHandler = createJumpHandler(switchStatement); | |
| 1166 if (!hasContinue) { | |
| 1167 // If the switch statement has no switch cases targeted by continue | |
| 1168 // statements we encode the switch statement directly. | |
| 1169 _buildSimpleSwitchStatement(switchStatement, jumpHandler, constants); | |
| 1170 } else { | |
| 1171 throw 'Complex switch statement with continue label not implemented yet.'; | |
| 1172 } | |
| 1173 } | |
| 1174 | |
| 1175 /// Helper for building switch statements. | |
| 1176 bool _isDefaultCase(ir.SwitchCase switchCase) => | |
|
sra1
2017/01/14 03:18:22
could be static
Emily Fortuna
2017/01/17 23:33:09
Done.
| |
| 1177 switchCase == null || switchCase.isDefault; | |
| 1178 | |
| 1179 /// Builds a simple switch statement which does not handle uses of continue | |
| 1180 /// statements to labeled switch cases. | |
| 1181 void _buildSimpleSwitchStatement(ir.SwitchStatement switchStatement, | |
| 1182 JumpHandler jumpHandler, Map<ir.Expression, ConstantValue> constants) { | |
| 1183 void buildSwitchCase(ir.SwitchCase switchCase) { | |
| 1184 switchCase.body.accept(this); | |
| 1185 } | |
| 1186 | |
| 1187 handleSwitch(switchStatement, jumpHandler, switchStatement.cases, | |
| 1188 _isDefaultCase, buildSwitchCase, constants); | |
| 1189 jumpHandler.close(); | |
| 1190 } | |
| 1191 | |
| 1192 /// Creates a switch statement. | |
| 1193 /// | |
| 1194 /// [jumpHandler] is the [JumpHandler] for the created switch statement. | |
| 1195 /// [buildSwitchCase] creates the statements for the switch case. | |
| 1196 void handleSwitch( | |
| 1197 ir.SwitchStatement switchStatement, | |
| 1198 JumpHandler jumpHandler, | |
| 1199 List<ir.SwitchCase> switchCases, | |
| 1200 bool isDefaultCase(ir.SwitchCase switchCase), | |
| 1201 void buildSwitchCase(ir.SwitchCase switchCase), | |
| 1202 Map<ir.Expression, ConstantValue> constantsLookup) { | |
| 1203 HBasicBlock expressionStart = openNewBlock(); | |
| 1204 switchStatement.expression.accept(this); | |
| 1205 HInstruction expression = pop(); | |
| 1206 | |
| 1207 List<ConstantValue> getConstants(ir.SwitchCase switchCase) { | |
| 1208 List<ConstantValue> constantList = <ConstantValue>[]; | |
| 1209 if (switchCase != null) { | |
| 1210 for (var expression in switchCase.expressions) { | |
| 1211 constantList.add(constantsLookup[expression]); | |
| 1212 } | |
| 1213 } | |
| 1214 return constantList; | |
| 1215 } | |
| 1216 | |
| 1217 if (switchCases.isEmpty) { | |
| 1218 return; | |
| 1219 } | |
| 1220 | |
| 1221 HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]); | |
| 1222 HBasicBlock expressionEnd = close(switchInstruction); | |
| 1223 LocalsHandler savedLocals = localsHandler; | |
| 1224 | |
| 1225 List<HStatementInformation> statements = <HStatementInformation>[]; | |
| 1226 bool hasDefault = false; | |
| 1227 for (ir.SwitchCase switchCase in switchCases) { | |
| 1228 HBasicBlock block = graph.addNewBlock(); | |
| 1229 for (ConstantValue constant in getConstants(switchCase)) { | |
| 1230 HConstant hConstant = graph.addConstant(constant, closedWorld); | |
| 1231 switchInstruction.inputs.add(hConstant); | |
| 1232 hConstant.usedBy.add(switchInstruction); | |
| 1233 expressionEnd.addSuccessor(block); | |
| 1234 } | |
| 1235 | |
| 1236 if (isDefaultCase(switchCase)) { | |
| 1237 // An HSwitch has n inputs and n+1 successors, the last being the | |
| 1238 // default case. | |
| 1239 expressionEnd.addSuccessor(block); | |
| 1240 hasDefault = true; | |
| 1241 } | |
| 1242 open(block); | |
| 1243 localsHandler = new LocalsHandler.from(savedLocals); | |
| 1244 buildSwitchCase(switchCase); | |
| 1245 statements.add( | |
| 1246 new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock))); | |
| 1247 } | |
| 1248 | |
| 1249 // Add a join-block if necessary. | |
| 1250 // We create [joinBlock] early, and then go through the cases that might | |
| 1251 // want to jump to it. In each case, if we add [joinBlock] as a successor | |
| 1252 // of another block, we also add an element to [caseHandlers] that is used | |
| 1253 // to create the phis in [joinBlock]. | |
| 1254 // If we never jump to the join block, [caseHandlers] will stay empty, and | |
| 1255 // the join block is never added to the graph. | |
| 1256 HBasicBlock joinBlock = new HBasicBlock(); | |
| 1257 List<LocalsHandler> caseHandlers = <LocalsHandler>[]; | |
| 1258 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { | |
| 1259 instruction.block.addSuccessor(joinBlock); | |
| 1260 caseHandlers.add(locals); | |
| 1261 }); | |
| 1262 jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) { | |
| 1263 assert(invariant(astAdapter.getNode(switchStatement), false, | |
| 1264 message: 'Continue cannot target a switch.')); | |
| 1265 }); | |
| 1266 if (!isAborted()) { | |
| 1267 current.close(new HGoto()); | |
| 1268 lastOpenedBlock.addSuccessor(joinBlock); | |
| 1269 caseHandlers.add(localsHandler); | |
| 1270 } | |
| 1271 if (!hasDefault) { | |
| 1272 // Always create a default case, to avoid a critical edge in the | |
| 1273 // graph. | |
| 1274 HBasicBlock defaultCase = addNewBlock(); | |
| 1275 expressionEnd.addSuccessor(defaultCase); | |
| 1276 open(defaultCase); | |
| 1277 close(new HGoto()); | |
| 1278 defaultCase.addSuccessor(joinBlock); | |
| 1279 caseHandlers.add(savedLocals); | |
| 1280 statements.add(new HSubGraphBlockInformation( | |
| 1281 new SubGraph(defaultCase, defaultCase))); | |
| 1282 } | |
| 1283 assert(caseHandlers.length == joinBlock.predecessors.length); | |
| 1284 if (caseHandlers.length != 0) { | |
| 1285 graph.addBlock(joinBlock); | |
| 1286 open(joinBlock); | |
| 1287 if (caseHandlers.length == 1) { | |
| 1288 localsHandler = caseHandlers[0]; | |
| 1289 } else { | |
| 1290 localsHandler = savedLocals.mergeMultiple(caseHandlers, joinBlock); | |
| 1291 } | |
| 1292 } else { | |
| 1293 // The joinblock is not used. | |
| 1294 joinBlock = null; | |
| 1295 } | |
| 1296 | |
| 1297 HSubExpressionBlockInformation expressionInfo = | |
| 1298 new HSubExpressionBlockInformation( | |
| 1299 new SubExpression(expressionStart, expressionEnd)); | |
| 1300 expressionStart.setBlockFlow( | |
| 1301 new HSwitchBlockInformation( | |
| 1302 expressionInfo, statements, jumpHandler.target, jumpHandler.labels), | |
| 1303 joinBlock); | |
| 1304 | |
| 1305 jumpHandler.close(); | |
| 1306 } | |
| 1307 | |
| 1077 @override | 1308 @override |
| 1078 void visitConditionalExpression(ir.ConditionalExpression conditional) { | 1309 void visitConditionalExpression(ir.ConditionalExpression conditional) { |
| 1079 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler); | 1310 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler); |
| 1080 brancher.handleConditional( | 1311 brancher.handleConditional( |
| 1081 () => conditional.condition.accept(this), | 1312 () => conditional.condition.accept(this), |
| 1082 () => conditional.then.accept(this), | 1313 () => conditional.then.accept(this), |
| 1083 () => conditional.otherwise.accept(this)); | 1314 () => conditional.otherwise.accept(this)); |
| 1084 } | 1315 } |
| 1085 | 1316 |
| 1086 @override | 1317 @override |
| (...skipping 1126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2213 (ir.DartType typeArgType) => | 2444 (ir.DartType typeArgType) => |
| 2214 typeArgType is! ir.DynamicType && | 2445 typeArgType is! ir.DynamicType && |
| 2215 typeArgType is! ir.InvalidType && | 2446 typeArgType is! ir.InvalidType && |
| 2216 !isMethodTypeVariableType(type)); | 2447 !isMethodTypeVariableType(type)); |
| 2217 } | 2448 } |
| 2218 | 2449 |
| 2219 @override | 2450 @override |
| 2220 void visitThrow(ir.Throw throwNode) { | 2451 void visitThrow(ir.Throw throwNode) { |
| 2221 _visitThrowExpression(throwNode.expression); | 2452 _visitThrowExpression(throwNode.expression); |
| 2222 if (isReachable) { | 2453 if (isReachable) { |
| 2454 handleInTryStatement(); | |
| 2223 push(new HThrowExpression(pop(), null)); | 2455 push(new HThrowExpression(pop(), null)); |
| 2224 isReachable = false; | 2456 isReachable = false; |
| 2225 } | 2457 } |
| 2226 } | 2458 } |
| 2227 | 2459 |
| 2228 void _visitThrowExpression(ir.Expression expression) { | 2460 void _visitThrowExpression(ir.Expression expression) { |
| 2229 bool old = _inExpressionOfThrow; | 2461 bool old = _inExpressionOfThrow; |
| 2230 try { | 2462 try { |
| 2231 _inExpressionOfThrow = true; | 2463 _inExpressionOfThrow = true; |
| 2232 expression.accept(this); | 2464 expression.accept(this); |
| 2233 } finally { | 2465 } finally { |
| 2234 _inExpressionOfThrow = old; | 2466 _inExpressionOfThrow = old; |
| 2235 } | 2467 } |
| 2236 } | 2468 } |
| 2237 | 2469 |
| 2238 @override | 2470 @override |
| 2239 void visitRethrow(ir.Rethrow rethrowNode) { | 2471 void visitRethrow(ir.Rethrow rethrowNode) { |
| 2240 HInstruction exception = rethrowableException; | 2472 HInstruction exception = rethrowableException; |
| 2241 if (exception == null) { | 2473 if (exception == null) { |
| 2242 exception = graph.addConstantNull(closedWorld); | 2474 exception = graph.addConstantNull(closedWorld); |
| 2243 compiler.reporter.internalError(astAdapter.getNode(rethrowNode), | 2475 compiler.reporter.internalError(astAdapter.getNode(rethrowNode), |
| 2244 'rethrowableException should not be null.'); | 2476 'rethrowableException should not be null.'); |
| 2245 } | 2477 } |
| 2478 handleInTryStatement(); | |
| 2246 SourceInformation sourceInformation = null; | 2479 SourceInformation sourceInformation = null; |
| 2247 closeAndGotoExit(new HThrow(exception, sourceInformation, isRethrow: true)); | 2480 closeAndGotoExit(new HThrow(exception, sourceInformation, isRethrow: true)); |
| 2248 // ir.Rethrow is an expression so we need to push a value - a constant with | 2481 // ir.Rethrow is an expression so we need to push a value - a constant with |
| 2249 // no type. | 2482 // no type. |
| 2250 stack.add(graph.addConstantUnreachable(closedWorld)); | 2483 stack.add(graph.addConstantUnreachable(closedWorld)); |
| 2251 } | 2484 } |
| 2252 | 2485 |
| 2253 @override | 2486 @override |
| 2254 void visitThisExpression(ir.ThisExpression thisExpression) { | 2487 void visitThisExpression(ir.ThisExpression thisExpression) { |
| 2255 stack.add(localsHandler.readThis()); | 2488 stack.add(localsHandler.readThis()); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2318 HBasicBlock endTryBlock; | 2551 HBasicBlock endTryBlock; |
| 2319 HBasicBlock startCatchBlock; | 2552 HBasicBlock startCatchBlock; |
| 2320 HBasicBlock endCatchBlock; | 2553 HBasicBlock endCatchBlock; |
| 2321 HBasicBlock startFinallyBlock; | 2554 HBasicBlock startFinallyBlock; |
| 2322 HBasicBlock endFinallyBlock; | 2555 HBasicBlock endFinallyBlock; |
| 2323 HBasicBlock exitBlock; | 2556 HBasicBlock exitBlock; |
| 2324 HTry tryInstruction; | 2557 HTry tryInstruction; |
| 2325 HLocalValue exception; | 2558 HLocalValue exception; |
| 2326 KernelSsaBuilder kernelBuilder; | 2559 KernelSsaBuilder kernelBuilder; |
| 2327 | 2560 |
| 2561 /// True if the code surrounding this try statement was also part of a | |
| 2562 /// try/catch/finally statement. | |
| 2563 bool previouslyInTrySequence; | |
| 2564 | |
| 2328 SubGraph bodyGraph; | 2565 SubGraph bodyGraph; |
| 2329 SubGraph catchGraph; | 2566 SubGraph catchGraph; |
| 2330 SubGraph finallyGraph; | 2567 SubGraph finallyGraph; |
| 2331 | 2568 |
| 2332 // The original set of locals that were defined before this try block. | 2569 // The original set of locals that were defined before this try block. |
| 2333 // The catch block and the finally block must not reuse the existing locals | 2570 // The catch block and the finally block must not reuse the existing locals |
| 2334 // handler. None of the variables that have been defined in the body-block | 2571 // handler. None of the variables that have been defined in the body-block |
| 2335 // will be used, but for loops we will add (unnecessary) phis that will | 2572 // will be used, but for loops we will add (unnecessary) phis that will |
| 2336 // reference the body variables. This makes it look as if the variables were | 2573 // reference the body variables. This makes it look as if the variables were |
| 2337 // used in a non-dominated block. | 2574 // used in a non-dominated block. |
| 2338 LocalsHandler originalSavedLocals; | 2575 LocalsHandler originalSavedLocals; |
| 2339 | 2576 |
| 2340 TryCatchFinallyBuilder(this.kernelBuilder) { | 2577 TryCatchFinallyBuilder(this.kernelBuilder) { |
| 2341 tryInstruction = new HTry(); | 2578 tryInstruction = new HTry(); |
| 2342 originalSavedLocals = new LocalsHandler.from(kernelBuilder.localsHandler); | 2579 originalSavedLocals = new LocalsHandler.from(kernelBuilder.localsHandler); |
| 2343 enterBlock = kernelBuilder.openNewBlock(); | 2580 enterBlock = kernelBuilder.openNewBlock(); |
| 2344 kernelBuilder.close(tryInstruction); | 2581 kernelBuilder.close(tryInstruction); |
| 2582 previouslyInTrySequence = kernelBuilder.inTryStatement; | |
| 2583 kernelBuilder.inTryStatement = true; | |
| 2345 | 2584 |
| 2346 startTryBlock = kernelBuilder.graph.addNewBlock(); | 2585 startTryBlock = kernelBuilder.graph.addNewBlock(); |
| 2347 kernelBuilder.open(startTryBlock); | 2586 kernelBuilder.open(startTryBlock); |
| 2348 } | 2587 } |
| 2349 | 2588 |
| 2350 void _addExitTrySuccessor(successor) { | 2589 void _addExitTrySuccessor(successor) { |
| 2351 if (successor == null) return; | 2590 if (successor == null) return; |
| 2352 // Iterate over all blocks created inside this try/catch, and | 2591 // Iterate over all blocks created inside this try/catch, and |
| 2353 // attach successor information to blocks that end with | 2592 // attach successor information to blocks that end with |
| 2354 // [HExitTry]. | 2593 // [HExitTry]. |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2521 // blocks. | 2760 // blocks. |
| 2522 kernelBuilder.localsHandler = originalSavedLocals; | 2761 kernelBuilder.localsHandler = originalSavedLocals; |
| 2523 kernelBuilder.open(exitBlock); | 2762 kernelBuilder.open(exitBlock); |
| 2524 enterBlock.setBlockFlow( | 2763 enterBlock.setBlockFlow( |
| 2525 new HTryBlockInformation( | 2764 new HTryBlockInformation( |
| 2526 kernelBuilder.wrapStatementGraph(bodyGraph), | 2765 kernelBuilder.wrapStatementGraph(bodyGraph), |
| 2527 exception, | 2766 exception, |
| 2528 kernelBuilder.wrapStatementGraph(catchGraph), | 2767 kernelBuilder.wrapStatementGraph(catchGraph), |
| 2529 kernelBuilder.wrapStatementGraph(finallyGraph)), | 2768 kernelBuilder.wrapStatementGraph(finallyGraph)), |
| 2530 exitBlock); | 2769 exitBlock); |
| 2770 kernelBuilder.inTryStatement = previouslyInTrySequence; | |
| 2531 } | 2771 } |
| 2532 } | 2772 } |
| OLD | NEW |