001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.lang.cfg.pseudocode;
018
019 import com.intellij.util.containers.Stack;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.lang.cfg.*;
023 import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
024 import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
025 import org.jetbrains.jet.lang.psi.*;
026 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
027 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
028
029 import java.util.ArrayList;
030 import java.util.HashMap;
031 import java.util.List;
032 import java.util.Map;
033
034 public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAdapter {
035
036 private JetControlFlowBuilder builder = null;
037
038 private final Stack<BreakableBlockInfo> loopInfo = new Stack<BreakableBlockInfo>();
039 private final Map<JetElement, BreakableBlockInfo> elementToBlockInfo = new HashMap<JetElement, BreakableBlockInfo>();
040 private int labelCount = 0;
041 private int allowDeadLabelCount = 0;
042
043 private final Stack<JetControlFlowInstructionsGeneratorWorker> builders = new Stack<JetControlFlowInstructionsGeneratorWorker>();
044
045 private final Stack<BlockInfo> allBlocks = new Stack<BlockInfo>();
046
047 @NotNull
048 @Override
049 protected JetControlFlowBuilder getDelegateBuilder() {
050 return builder;
051 }
052
053 private void pushBuilder(JetElement scopingElement, JetElement subroutine) {
054 JetControlFlowInstructionsGeneratorWorker worker = new JetControlFlowInstructionsGeneratorWorker(scopingElement, subroutine);
055 builders.push(worker);
056 builder = worker;
057 }
058
059 private JetControlFlowInstructionsGeneratorWorker popBuilder(@NotNull JetElement element) {
060 JetControlFlowInstructionsGeneratorWorker worker = builders.pop();
061 if (!builders.isEmpty()) {
062 builder = builders.peek();
063 }
064 else {
065 builder = null;
066 }
067 return worker;
068 }
069
070 @Override
071 public void enterSubroutine(@NotNull JetElement subroutine) {
072 if (builder != null && subroutine instanceof JetFunctionLiteral) {
073 pushBuilder(subroutine, builder.getReturnSubroutine());
074 }
075 else {
076 pushBuilder(subroutine, subroutine);
077 }
078 assert builder != null;
079 builder.enterSubroutine(subroutine);
080 }
081
082 @NotNull
083 @Override
084 public Pseudocode exitSubroutine(@NotNull JetElement subroutine) {
085 super.exitSubroutine(subroutine);
086 JetControlFlowInstructionsGeneratorWorker worker = popBuilder(subroutine);
087 if (!builders.empty()) {
088 JetControlFlowInstructionsGeneratorWorker builder = builders.peek();
089 builder.declareFunction(subroutine, worker.getPseudocode());
090 }
091 return worker.getPseudocode();
092 }
093
094 private class JetControlFlowInstructionsGeneratorWorker implements JetControlFlowBuilder {
095
096 private final PseudocodeImpl pseudocode;
097 private final Label error;
098 private final Label sink;
099 private final JetElement returnSubroutine;
100
101 private JetControlFlowInstructionsGeneratorWorker(@NotNull JetElement scopingElement, @NotNull JetElement returnSubroutine) {
102 this.pseudocode = new PseudocodeImpl(scopingElement);
103 this.error = pseudocode.createLabel("error");
104 this.sink = pseudocode.createLabel("sink");
105 this.returnSubroutine = returnSubroutine;
106 }
107
108 public PseudocodeImpl getPseudocode() {
109 return pseudocode;
110 }
111
112 private void add(@NotNull Instruction instruction) {
113 pseudocode.addInstruction(instruction);
114 }
115
116 @NotNull
117 @Override
118 public final Label createUnboundLabel() {
119 return pseudocode.createLabel("L" + labelCount++);
120 }
121
122 @NotNull
123 @Override
124 public Label createUnboundLabel(@NotNull String name) {
125 return pseudocode.createLabel("L" + labelCount++ + " [" + name + "]");
126 }
127
128 @Override
129 public final LoopInfo enterLoop(@NotNull JetExpression expression, @Nullable Label loopExitPoint, Label conditionEntryPoint) {
130 Label loopEntryLabel = createUnboundLabel("loop entry point");
131 bindLabel(loopEntryLabel);
132 LoopInfo blockInfo = new LoopInfo(
133 expression,
134 loopEntryLabel,
135 loopExitPoint != null ? loopExitPoint : createUnboundLabel("loop exit point"),
136 createUnboundLabel("body entry point"),
137 conditionEntryPoint != null ? conditionEntryPoint : createUnboundLabel("condition entry point"));
138 loopInfo.push(blockInfo);
139 elementToBlockInfo.put(expression, blockInfo);
140 allBlocks.push(blockInfo);
141 pseudocode.recordLoopInfo(expression, blockInfo);
142 return blockInfo;
143 }
144
145 @Override
146 public final void exitLoop(@NotNull JetExpression expression) {
147 BreakableBlockInfo info = loopInfo.pop();
148 elementToBlockInfo.remove(expression);
149 allBlocks.pop();
150 bindLabel(info.getExitPoint());
151 }
152
153 @Override
154 public JetElement getCurrentLoop() {
155 return loopInfo.empty() ? null : loopInfo.peek().getElement();
156 }
157
158 @Override
159 public void enterSubroutine(@NotNull JetElement subroutine) {
160 Label entryPoint = createUnboundLabel();
161 BreakableBlockInfo blockInfo = new BreakableBlockInfo(subroutine, entryPoint, createUnboundLabel());
162 // subroutineInfo.push(blockInfo);
163 elementToBlockInfo.put(subroutine, blockInfo);
164 allBlocks.push(blockInfo);
165 bindLabel(entryPoint);
166 add(new SubroutineEnterInstruction(subroutine));
167 }
168
169 @NotNull
170 @Override
171 public JetElement getCurrentSubroutine() {
172 return pseudocode.getCorrespondingElement();
173 }
174
175 @Override
176 public JetElement getReturnSubroutine() {
177 return returnSubroutine;// subroutineInfo.empty() ? null : subroutineInfo.peek().getElement();
178 }
179
180 @NotNull
181 @Override
182 public Label getEntryPoint(@NotNull JetElement labelElement) {
183 return elementToBlockInfo.get(labelElement).getEntryPoint();
184 }
185
186 @NotNull
187 @Override
188 public Label getExitPoint(@NotNull JetElement labelElement) {
189 BreakableBlockInfo blockInfo = elementToBlockInfo.get(labelElement);
190 assert blockInfo != null : labelElement.getText();
191 return blockInfo.getExitPoint();
192 }
193
194 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
195
196 private void handleJumpInsideTryFinally(Label jumpTarget) {
197 List<TryFinallyBlockInfo> finallyBlocks = new ArrayList<TryFinallyBlockInfo>();
198
199 for (int i = allBlocks.size() - 1; i >= 0; i--) {
200 BlockInfo blockInfo = allBlocks.get(i);
201 if (blockInfo instanceof BreakableBlockInfo) {
202 BreakableBlockInfo breakableBlockInfo = (BreakableBlockInfo) blockInfo;
203 if (jumpTarget == breakableBlockInfo.getExitPoint() || jumpTarget == breakableBlockInfo.getEntryPoint()
204 || jumpTarget == error) {
205 for (int j = finallyBlocks.size() - 1; j >= 0; j--) {
206 finallyBlocks.get(j).generateFinallyBlock();
207 }
208 break;
209 }
210 }
211 else if (blockInfo instanceof TryFinallyBlockInfo) {
212 TryFinallyBlockInfo tryFinallyBlockInfo = (TryFinallyBlockInfo) blockInfo;
213 finallyBlocks.add(tryFinallyBlockInfo);
214 }
215 }
216 }
217
218 @NotNull
219 @Override
220 public Pseudocode exitSubroutine(@NotNull JetElement subroutine) {
221 bindLabel(getExitPoint(subroutine));
222 pseudocode.addExitInstruction(new SubroutineExitInstruction(subroutine, false));
223 bindLabel(error);
224 pseudocode.addErrorInstruction(new SubroutineExitInstruction(subroutine, true));
225 bindLabel(sink);
226 pseudocode.addSinkInstruction(new SubroutineSinkInstruction(subroutine, "<SINK>"));
227 elementToBlockInfo.remove(subroutine);
228 allBlocks.pop();
229 return pseudocode;
230 }
231
232 @Override
233 public void mark(@NotNull JetElement element) {
234 add(new MarkInstruction(element));
235 }
236
237 @Override
238 public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) {
239 Label exitPoint = getExitPoint(subroutine);
240 handleJumpInsideTryFinally(exitPoint);
241 add(new ReturnValueInstruction(returnExpression, exitPoint));
242 }
243
244 @Override
245 public void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine) {
246 Label exitPoint = getExitPoint(subroutine);
247 handleJumpInsideTryFinally(exitPoint);
248 add(new ReturnNoValueInstruction(returnExpression, exitPoint));
249 }
250
251 @Override
252 public void write(@NotNull JetElement assignment, @NotNull JetElement lValue) {
253 add(new WriteValueInstruction(assignment, lValue));
254 }
255
256 @Override
257 public void declareParameter(@NotNull JetParameter parameter) {
258 add(new VariableDeclarationInstruction(parameter));
259 }
260
261 @Override
262 public void declareVariable(@NotNull JetVariableDeclaration property) {
263 add(new VariableDeclarationInstruction(property));
264 }
265
266 @Override
267 public void declareFunction(@NotNull JetElement subroutine, @NotNull Pseudocode pseudocode) {
268 add(new LocalFunctionDeclarationInstruction(subroutine, pseudocode));
269 }
270
271 @Override
272 public void loadUnit(@NotNull JetExpression expression) {
273 add(new LoadUnitValueInstruction(expression));
274 }
275
276 @Override
277 public void jump(@NotNull Label label) {
278 handleJumpInsideTryFinally(label);
279 add(new UnconditionalJumpInstruction(label));
280 }
281
282 @Override
283 public void jumpOnFalse(@NotNull Label label) {
284 handleJumpInsideTryFinally(label);
285 add(new ConditionalJumpInstruction(false, label));
286 }
287
288 @Override
289 public void jumpOnTrue(@NotNull Label label) {
290 handleJumpInsideTryFinally(label);
291 add(new ConditionalJumpInstruction(true, label));
292 }
293
294 @Override
295 public void bindLabel(@NotNull Label label) {
296 pseudocode.bindLabel(label);
297 }
298
299 @Override
300 public void nondeterministicJump(@NotNull Label label) {
301 handleJumpInsideTryFinally(label);
302 add(new NondeterministicJumpInstruction(label));
303 }
304
305 @Override
306 public void nondeterministicJump(@NotNull List<Label> labels) {
307 //todo
308 //handleJumpInsideTryFinally(label);
309 add(new NondeterministicJumpInstruction(labels));
310 }
311
312 @Override
313 public void jumpToError() {
314 handleJumpInsideTryFinally(error);
315 add(new UnconditionalJumpInstruction(error));
316 }
317
318 @Override
319 public void enterTryFinally(@NotNull GenerationTrigger generationTrigger) {
320 allBlocks.push(new TryFinallyBlockInfo(generationTrigger));
321 }
322
323 @Override
324 public void throwException(@NotNull JetThrowExpression expression) {
325 handleJumpInsideTryFinally(error);
326 add(new ThrowExceptionInstruction(expression, error));
327 }
328
329 public void exitTryFinally() {
330 BlockInfo pop = allBlocks.pop();
331 assert pop instanceof TryFinallyBlockInfo;
332 }
333
334 @Override
335 public void unsupported(JetElement element) {
336 add(new UnsupportedElementInstruction(element));
337 }
338
339 @Override
340 public void repeatPseudocode(@NotNull Label startLabel, @NotNull Label finishLabel) {
341 pseudocode.repeatPart(startLabel, finishLabel);
342 }
343
344 @Override
345 public void loadConstant(@NotNull JetExpression expression, @Nullable CompileTimeConstant<?> constant) {
346 read(expression);
347 }
348
349 @Override
350 public void createAnonymousObject(@NotNull JetObjectLiteralExpression expression) {
351 read(expression);
352 }
353
354 @Override
355 public void createFunctionLiteral(@NotNull JetFunctionLiteralExpression expression) {
356 read(expression);
357 }
358
359 @Override
360 public void loadStringTemplate(@NotNull JetStringTemplateExpression expression) {
361 read(expression);
362 }
363
364 @Override
365 public void readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
366 read(expression);
367 }
368
369 @Override
370 public void readVariable(@NotNull JetExpression expression, @Nullable VariableDescriptor variableDescriptor) {
371 read(expression);
372 }
373
374 @Override
375 public void call(@NotNull JetExpression expression, @NotNull ResolvedCall<?> resolvedCall) {
376 add(new CallInstruction(expression, resolvedCall));
377 }
378
379 @Override
380 public void predefinedOperation(@NotNull JetExpression expression, @Nullable PredefinedOperation operation) {
381 read(expression);
382 }
383
384 @Override
385 public void compilationError(@NotNull JetElement element, @NotNull String message) {
386 add(new CompilationErrorInstruction(element, message));
387 }
388
389 private void read(@NotNull JetElement element) {
390 add(new ReadValueInstruction(element));
391 }
392 }
393
394 public static class TryFinallyBlockInfo extends BlockInfo {
395 private final GenerationTrigger finallyBlock;
396
397 private TryFinallyBlockInfo(GenerationTrigger finallyBlock) {
398 this.finallyBlock = finallyBlock;
399 }
400
401 public void generateFinallyBlock() {
402 finallyBlock.generate();
403 }
404 }
405
406 }