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

Side by Side Diff: pkg/compiler/lib/src/ssa/jump_handler.dart

Issue 2360673003: kernel->ssa: Implement for-loops and while-loops (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 import '../common.dart';
6 import '../elements/elements.dart';
7 import '../tree/tree.dart' as ast;
8
9 import 'builder.dart';
10 import 'graph_builder.dart';
11 import 'locals_handler.dart';
12 import 'nodes.dart';
13
14 /// A single break/continue instruction.
15 class JumpHandlerEntry {
16 final HJump jumpInstruction;
17 final LocalsHandler locals;
18 bool isBreak() => jumpInstruction is HBreak;
19 bool isContinue() => jumpInstruction is HContinue;
20 JumpHandlerEntry(this.jumpInstruction, this.locals);
21 }
22
23 abstract class JumpHandler {
24 factory JumpHandler(GraphBuilder builder, JumpTarget target) {
25 return new TargetJumpHandler(builder, target);
26 }
27 void generateBreak([LabelDefinition label]);
28 void generateContinue([LabelDefinition label]);
29 void forEachBreak(void action(HBreak instruction, LocalsHandler locals));
30 void forEachContinue(
31 void action(HContinue instruction, LocalsHandler locals));
32 bool hasAnyContinue();
33 bool hasAnyBreak();
34 void close();
35 final JumpTarget target;
36 List<LabelDefinition> labels();
37 }
38
39 /// Jump handler used to avoid null checks when a target isn't used as the
40 /// target of a break, and therefore doesn't need a break handler associated
41 /// with it.
42 class NullJumpHandler implements JumpHandler {
43 final DiagnosticReporter reporter;
44
45 NullJumpHandler(this.reporter);
46
47 void generateBreak([LabelDefinition label]) {
48 reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
49 'NullJumpHandler.generateBreak should not be called.');
50 }
51
52 void generateContinue([LabelDefinition label]) {
53 reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
54 'NullJumpHandler.generateContinue should not be called.');
55 }
56
57 void forEachBreak(Function ignored) {}
58 void forEachContinue(Function ignored) {}
59 void close() {}
60 bool hasAnyContinue() => false;
61 bool hasAnyBreak() => false;
62
63 List<LabelDefinition> labels() => const <LabelDefinition>[];
64 JumpTarget get target => null;
65 }
66
67 /// Jump handler that records breaks until a target block is available.
68 ///
69 /// Breaks are always forward jumps. Continues in loops are implemented as
70 /// breaks of the body. Continues in switches is currently not handled.
71 class TargetJumpHandler implements JumpHandler {
72 final GraphBuilder builder;
73 final JumpTarget target;
74 final List<JumpHandlerEntry> jumps;
75
76 TargetJumpHandler(GraphBuilder builder, this.target)
77 : this.builder = builder,
78 jumps = <JumpHandlerEntry>[] {
79 assert(builder.jumpTargets[target] == null);
80 builder.jumpTargets[target] = this;
81 }
82
83 void generateBreak([LabelDefinition label]) {
84 HInstruction breakInstruction;
85 if (label == null) {
86 breakInstruction = new HBreak(target);
87 } else {
88 breakInstruction = new HBreak.toLabel(label);
89 }
90 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler);
91 builder.close(breakInstruction);
92 jumps.add(new JumpHandlerEntry(breakInstruction, locals));
93 }
94
95 void generateContinue([LabelDefinition label]) {
96 HInstruction continueInstruction;
97 if (label == null) {
98 continueInstruction = new HContinue(target);
99 } else {
100 continueInstruction = new HContinue.toLabel(label);
101 // Switch case continue statements must be handled by the
102 // [SwitchCaseJumpHandler].
103 assert(label.target.statement is! ast.SwitchCase);
104 }
105 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler);
106 builder.close(continueInstruction);
107 jumps.add(new JumpHandlerEntry(continueInstruction, locals));
108 }
109
110 void forEachBreak(Function action) {
111 for (JumpHandlerEntry entry in jumps) {
112 if (entry.isBreak()) action(entry.jumpInstruction, entry.locals);
113 }
114 }
115
116 void forEachContinue(Function action) {
117 for (JumpHandlerEntry entry in jumps) {
118 if (entry.isContinue()) action(entry.jumpInstruction, entry.locals);
119 }
120 }
121
122 bool hasAnyContinue() {
123 for (JumpHandlerEntry entry in jumps) {
124 if (entry.isContinue()) return true;
125 }
126 return false;
127 }
128
129 bool hasAnyBreak() {
130 for (JumpHandlerEntry entry in jumps) {
131 if (entry.isBreak()) return true;
132 }
133 return false;
134 }
135
136 void close() {
137 // The mapping from TargetElement to JumpHandler is no longer needed.
138 builder.jumpTargets.remove(target);
139 }
140
141 List<LabelDefinition> labels() {
142 List<LabelDefinition> result = null;
143 for (LabelDefinition element in target.labels) {
144 if (result == null) result = <LabelDefinition>[];
145 result.add(element);
146 }
147 return (result == null) ? const <LabelDefinition>[] : result;
148 }
149 }
150
151 /// Special [JumpHandler] implementation used to handle continue statements
152 /// targeting switch cases.
153 class SwitchCaseJumpHandler extends TargetJumpHandler {
154 /// Map from switch case targets to indices used to encode the flow of the
155 /// switch case loop.
156 final Map<JumpTarget, int> targetIndexMap = new Map<JumpTarget, int>();
157
158 SwitchCaseJumpHandler(
159 GraphBuilder builder, JumpTarget target, ast.SwitchStatement node)
160 : super(builder, target) {
161 // The switch case indices must match those computed in
162 // [SsaFromAstMixin.buildSwitchCaseConstants].
163 // Switch indices are 1-based so we can bypass the synthetic loop when no
164 // cases match simply by branching on the index (which defaults to null).
165 int switchIndex = 1;
166 for (ast.SwitchCase switchCase in node.cases) {
167 for (ast.Node labelOrCase in switchCase.labelsAndCases) {
168 ast.Node label = labelOrCase.asLabel();
169 if (label != null) {
170 LabelDefinition labelElement =
171 builder.elements.getLabelDefinition(label);
172 if (labelElement != null && labelElement.isContinueTarget) {
173 JumpTarget continueTarget = labelElement.target;
174 targetIndexMap[continueTarget] = switchIndex;
175 assert(builder.jumpTargets[continueTarget] == null);
176 builder.jumpTargets[continueTarget] = this;
177 }
178 }
179 }
180 switchIndex++;
181 }
182 }
183
184 void generateBreak([LabelDefinition label]) {
185 if (label == null) {
186 // Creates a special break instruction for the synthetic loop generated
187 // for a switch statement with continue statements. See
188 // [SsaFromAstMixin.buildComplexSwitchStatement] for detail.
189
190 HInstruction breakInstruction =
191 new HBreak(target, breakSwitchContinueLoop: true);
192 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler);
193 builder.close(breakInstruction);
194 jumps.add(new JumpHandlerEntry(breakInstruction, locals));
195 } else {
196 super.generateBreak(label);
197 }
198 }
199
200 bool isContinueToSwitchCase(LabelDefinition label) {
201 return label != null && targetIndexMap.containsKey(label.target);
202 }
203
204 void generateContinue([LabelDefinition label]) {
205 if (isContinueToSwitchCase(label)) {
206 // Creates the special instructions 'label = i; continue l;' used in
207 // switch statements with continue statements. See
208 // [SsaFromAstMixin.buildComplexSwitchStatement] for detail.
209
210 assert(label != null);
211 // TODO(het): change the graph 'addConstantXXX' to take a ConstantSystem
212 // instead of a Compiler.
213 HInstruction value = builder.graph
214 .addConstantInt(targetIndexMap[label.target], builder.compiler);
215 builder.localsHandler.updateLocal(target, value);
216
217 assert(label.target.labels.contains(label));
218 HInstruction continueInstruction = new HContinue(target);
219 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler);
220 builder.close(continueInstruction);
221 jumps.add(new JumpHandlerEntry(continueInstruction, locals));
222 } else {
223 super.generateContinue(label);
224 }
225 }
226
227 void close() {
228 // The mapping from TargetElement to JumpHandler is no longer needed.
229 for (JumpTarget target in targetIndexMap.keys) {
230 builder.jumpTargets.remove(target);
231 }
232 super.close();
233 }
234 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/graph_builder.dart ('k') | pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698