PseudocodeImpl.java 14.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright 2010-2012 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

A
Andrey Breslav 已提交
17 18
package org.jetbrains.jet.lang.cfg.pseudocode;

19
import com.google.common.collect.Lists;
S
Svetlana Isakova 已提交
20
import com.google.common.collect.Maps;
21
import com.google.common.collect.Sets;
A
Andrey Breslav 已提交
22
import org.jetbrains.annotations.NotNull;
A
Andrey Breslav 已提交
23
import org.jetbrains.annotations.Nullable;
A
Andrey Breslav 已提交
24
import org.jetbrains.jet.lang.cfg.Label;
S
Svetlana Isakova 已提交
25
import org.jetbrains.jet.lang.cfg.LoopInfo;
A
Andrey Breslav 已提交
26
import org.jetbrains.jet.lang.psi.JetElement;
S
Svetlana Isakova 已提交
27
import org.jetbrains.jet.lang.psi.JetExpression;
A
Andrey Breslav 已提交
28

S
Svetlana Isakova 已提交
29
import java.util.*;
A
Andrey Breslav 已提交
30 31 32

/**
* @author abreslav
S
Svetlana Isakova 已提交
33
* @author svtk
A
Andrey Breslav 已提交
34
*/
S
Svetlana Isakova 已提交
35
public class PseudocodeImpl implements IPseudocode {
36

A
Andrey Breslav 已提交
37 38
    public class PseudocodeLabel implements Label {
        private final String name;
39 40
        private Integer targetInstructionIndex;

A
Andrey Breslav 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

        private PseudocodeLabel(String name) {
            this.name = name;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return name;
        }

56
        public Integer getTargetInstructionIndex() {
57 58 59 60 61 62 63
            return targetInstructionIndex;
        }

        public void setTargetInstructionIndex(int targetInstructionIndex) {
            this.targetInstructionIndex = targetInstructionIndex;
        }

A
Andrey Breslav 已提交
64 65
        @Nullable
        private List<Instruction> resolve() {
66
            assert targetInstructionIndex != null;
S
svtk 已提交
67
            return mutableInstructionList.subList(getTargetInstructionIndex(), mutableInstructionList.size());
A
Andrey Breslav 已提交
68 69
        }

70 71
        public Instruction resolveToInstruction() {
            assert targetInstructionIndex != null;
S
svtk 已提交
72
            return mutableInstructionList.get(targetInstructionIndex);
73 74
        }

A
Andrey Breslav 已提交
75 76
    }

S
svtk 已提交
77
    private final List<Instruction> mutableInstructionList = new ArrayList<Instruction>();
A
Andrey Breslav 已提交
78
    private final List<Instruction> instructions = new ArrayList<Instruction>();
79
    private List<Instruction> deadInstructions;
S
Svetlana Isakova 已提交
80 81 82

    final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
    final Map<JetExpression, LoopInfo> loopInfo = Maps.newHashMap();
83
    
84
    private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
S
svtk 已提交
85
    private final List<PseudocodeLabel> allowedDeadLabels = new ArrayList<PseudocodeLabel>();
86
    private final List<PseudocodeLabel> stopAllowDeadLabels = new ArrayList<PseudocodeLabel>();
A
Andrey Breslav 已提交
87

A
Andrey Breslav 已提交
88
    private final JetElement correspondingElement;
89
    private SubroutineExitInstruction exitInstruction;
S
svtk 已提交
90
    private SubroutineSinkInstruction sinkInstruction;
91
    private SubroutineExitInstruction errorInstruction;
92
    private boolean postPrecessed = false;
A
Andrey Breslav 已提交
93

S
Svetlana Isakova 已提交
94
    public PseudocodeImpl(JetElement correspondingElement) {
A
Andrey Breslav 已提交
95 96 97
        this.correspondingElement = correspondingElement;
    }

S
Svetlana Isakova 已提交
98 99
    @NotNull
    @Override
A
Andrey Breslav 已提交
100 101 102 103
    public JetElement getCorrespondingElement() {
        return correspondingElement;
    }

S
Svetlana Isakova 已提交
104 105 106 107
    @NotNull
    @Override
    public Set<IPseudocode> getLocalDeclarations() {
        Set<IPseudocode> localDeclarations = Sets.newLinkedHashSet();
S
Svetlana Isakova 已提交
108 109 110 111 112 113 114 115 116
        //todo look recursively inside local declarations
        for (Instruction instruction : instructions) {
            if (instruction instanceof LocalDeclarationInstruction) {
                localDeclarations.add(((LocalDeclarationInstruction) instruction).getBody());
            }
        }
        return localDeclarations;
    }

A
Andrey Breslav 已提交
117
    public PseudocodeLabel createLabel(String name) {
118 119 120
        PseudocodeLabel label = new PseudocodeLabel(name);
        labels.add(label);
        return label;
A
Andrey Breslav 已提交
121
    }
S
svtk 已提交
122 123 124 125
    
    public void allowDead(Label label) {
        allowedDeadLabels.add((PseudocodeLabel) label);
    }
126 127 128 129
    
    public void stopAllowDead(Label label) {
        stopAllowDeadLabels.add((PseudocodeLabel) label);
    }
A
Andrey Breslav 已提交
130

S
Svetlana Isakova 已提交
131
    @Override
132
    @NotNull
133
    public List<Instruction> getInstructions() {
134 135
        return instructions;
    }
S
svtk 已提交
136 137 138 139 140 141

    @Deprecated //for tests only
    @NotNull
    public List<Instruction> getMutableInstructionList() {
        return mutableInstructionList;
    }
S
Svetlana Isakova 已提交
142 143

    @Override
144 145
    @NotNull
    public List<Instruction> getDeadInstructions() {
146 147 148 149 150 151 152 153 154 155 156
        if (deadInstructions != null) {
            return deadInstructions;
        }
        deadInstructions = Lists.newArrayList();
        Collection<Instruction> allowedDeadInstructions = collectAllowedDeadInstructions();

        for (Instruction instruction : mutableInstructionList) {
            if (((InstructionImpl)instruction).isDead()) {
                if (!allowedDeadInstructions.contains(instruction)) {
                    deadInstructions.add(instruction);
                }
157 158 159 160
            }
        }
        return deadInstructions;
    }
161 162

    @Deprecated //for tests only
S
svtk 已提交
163
    @NotNull
164 165 166
    public List<PseudocodeLabel> getLabels() {
        return labels;
    }
167

A
Andrey Breslav 已提交
168 169 170 171 172
    public void addExitInstruction(SubroutineExitInstruction exitInstruction) {
        addInstruction(exitInstruction);
        assert this.exitInstruction == null;
        this.exitInstruction = exitInstruction;
    }
S
svtk 已提交
173 174 175 176 177 178
    
    public void addSinkInstruction(SubroutineSinkInstruction sinkInstruction) {
        addInstruction(sinkInstruction);
        assert this.sinkInstruction == null;
        this.sinkInstruction = sinkInstruction;
    }
A
Andrey Breslav 已提交
179

180 181 182 183 184 185
    public void addErrorInstruction(SubroutineExitInstruction errorInstruction) {
        addInstruction(errorInstruction);
        assert this.errorInstruction == null;
        this.errorInstruction = errorInstruction;
    }

A
Andrey Breslav 已提交
186
    public void addInstruction(Instruction instruction) {
S
svtk 已提交
187
        mutableInstructionList.add(instruction);
A
Andrey Breslav 已提交
188
        instruction.setOwner(this);
S
Svetlana Isakova 已提交
189 190 191 192 193

        if (instruction instanceof JetElementInstruction) {
            JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
            representativeInstructions.put(elementInstruction.getElement(), instruction);
        }
194 195
    }

S
Svetlana Isakova 已提交
196 197 198 199 200
    public void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) {
        loopInfo.put(expression, blockInfo);
    }

    @Override
201 202 203
    @NotNull
    public SubroutineExitInstruction getExitInstruction() {
        return exitInstruction;
A
Andrey Breslav 已提交
204 205
    }

S
Svetlana Isakova 已提交
206
    @Override
S
svtk 已提交
207 208 209 210 211
    @NotNull
    public SubroutineSinkInstruction getSinkInstruction() {
        return sinkInstruction;
    }

S
Svetlana Isakova 已提交
212
    @Override
213 214
    @NotNull
    public SubroutineEnterInstruction getEnterInstruction() {
S
svtk 已提交
215
        return (SubroutineEnterInstruction) mutableInstructionList.get(0);
216 217
    }

218
    public void bindLabel(Label label) {
S
svtk 已提交
219
        ((PseudocodeLabel) label).setTargetInstructionIndex(mutableInstructionList.size());
A
Andrey Breslav 已提交
220 221 222
    }

    public void postProcess() {
223 224
        if (postPrecessed) return;
        postPrecessed = true;
S
Svetlana Isakova 已提交
225 226
        errorInstruction.setSink(getSinkInstruction());
        exitInstruction.setSink(getSinkInstruction());
S
svtk 已提交
227
        for (int i = 0, instructionsSize = mutableInstructionList.size(); i < instructionsSize; i++) {
228 229 230 231 232 233 234 235 236 237
            processInstruction(mutableInstructionList.get(i), i);
        }
        Set<Instruction> reachableInstructions = collectReachableInstructions();
        for (Instruction instruction : mutableInstructionList) {
            if (reachableInstructions.contains(instruction)) {
                instructions.add(instruction);
            }
        }
        markDeadInstructions();
    }
A
Andrey Breslav 已提交
238

239 240 241 242 243 244
    private void processInstruction(Instruction instruction, final int currentPosition) {
        instruction.accept(new InstructionVisitor() {
            @Override
            public void visitInstructionWithNext(InstructionWithNext instruction) {
                instruction.setNext(getNextPosition(currentPosition));
            }
A
Andrey Breslav 已提交
245

246 247 248 249
            @Override
            public void visitJump(AbstractJumpInstruction instruction) {
                instruction.setResolvedTarget(getJumpTarget(instruction.getTargetLabel()));
            }
A
Andrey Breslav 已提交
250

251 252 253 254 255 256
            @Override
            public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) {
                instruction.setNext(getNextPosition(currentPosition));
                List<Label> targetLabels = instruction.getTargetLabels();
                for (Label targetLabel : targetLabels) {
                    instruction.setResolvedTarget(targetLabel, getJumpTarget(targetLabel));
A
Andrey Breslav 已提交
257
                }
258
            }
A
Andrey Breslav 已提交
259

260 261 262 263 264 265 266
            @Override
            public void visitConditionalJump(ConditionalJumpInstruction instruction) {
                Instruction nextInstruction = getNextPosition(currentPosition);
                Instruction jumpTarget = getJumpTarget(instruction.getTargetLabel());
                if (instruction.onTrue()) {
                    instruction.setNextOnFalse(nextInstruction);
                    instruction.setNextOnTrue(jumpTarget);
A
Andrey Breslav 已提交
267
                }
268 269 270
                else {
                    instruction.setNextOnFalse(jumpTarget);
                    instruction.setNextOnTrue(nextInstruction);
A
Andrey Breslav 已提交
271
                }
272 273
                visitJump(instruction);
            }
A
Andrey Breslav 已提交
274

275 276
            @Override
            public void visitLocalDeclarationInstruction(LocalDeclarationInstruction instruction) {
S
Svetlana Isakova 已提交
277
                ((PseudocodeImpl)instruction.getBody()).postProcess();
278 279
                instruction.setNext(getSinkInstruction());
            }
S
svtk 已提交
280

281 282 283 284
            @Override
            public void visitSubroutineExit(SubroutineExitInstruction instruction) {
                // Nothing
            }
S
svtk 已提交
285

286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
            @Override
            public void visitSubroutineSink(SubroutineSinkInstruction instruction) {
                // Nothing
            }

            @Override
            public void visitInstruction(Instruction instruction) {
                throw new UnsupportedOperationException(instruction.toString());
            }
        });
    }

    private Set<Instruction> collectReachableInstructions() {
        Set<Instruction> visited = Sets.newHashSet();
        traverseNextInstructions(getEnterInstruction(), visited);
        if (!visited.contains(getExitInstruction())) {
            visited.add(getExitInstruction());
        }
        if (!visited.contains(errorInstruction)) {
            visited.add(errorInstruction);
        }
        if (!visited.contains(getSinkInstruction())) {
            visited.add(getSinkInstruction());
        }
        return visited;
    }
    
313
    private void traverseNextInstructions(@NotNull Instruction instruction, @NotNull Set<Instruction> visited) {
314 315 316
        if (visited.contains(instruction)) return;
        visited.add(instruction);
        for (Instruction nextInstruction : instruction.getNextInstructions()) {
317
            if (nextInstruction == null) continue; //todo it might be null on incomplete code
318 319
            traverseNextInstructions(nextInstruction, visited);
        }
320 321
    }

S
svtk 已提交
322
    private void markDeadInstructions() {
323 324 325 326 327 328
        Set<Instruction> instructionSet = Sets.newHashSet(instructions);
        for (Instruction instruction : mutableInstructionList) {
            if (!instructionSet.contains(instruction)) {
                ((InstructionImpl)instruction).die();
                for (Instruction nextInstruction : instruction.getNextInstructions()) {
                    nextInstruction.getPreviousInstructions().remove(instruction);
329 330 331
                }
            }
        }
A
Andrey Breslav 已提交
332 333
    }

S
svtk 已提交
334 335 336 337 338
    @NotNull
    private Set<Instruction> prepareAllowedDeadInstructions() {
        Set<Instruction> allowedDeadStartInstructions = Sets.newHashSet();
        for (PseudocodeLabel allowedDeadLabel : allowedDeadLabels) {
            Instruction allowedDeadInstruction = getJumpTarget(allowedDeadLabel);
339
            if (((InstructionImpl)allowedDeadInstruction).isDead()) {
S
svtk 已提交
340 341 342 343 344
                allowedDeadStartInstructions.add(allowedDeadInstruction);
            }
        }
        return allowedDeadStartInstructions;
    }
345 346 347 348 349 350 351 352 353 354 355 356
    
    @NotNull
    private Set<Instruction> prepareStopAllowedDeadInstructions() {
        Set<Instruction> stopAllowedDeadInstructions = Sets.newHashSet();
        for (PseudocodeLabel stopAllowedDeadLabel : stopAllowDeadLabels) {
            Instruction stopAllowDeadInsruction = getJumpTarget(stopAllowedDeadLabel);
            if (((InstructionImpl)stopAllowDeadInsruction).isDead()) {
                stopAllowedDeadInstructions.add(stopAllowDeadInsruction);
            }
        }
        return stopAllowedDeadInstructions;
    }
S
svtk 已提交
357 358

    @NotNull
359 360 361
    private Collection<Instruction> collectAllowedDeadInstructions() {
        Set<Instruction> allowedDeadStartInstructions = prepareAllowedDeadInstructions();
        Set<Instruction> stopAllowDeadInstructions = prepareStopAllowedDeadInstructions();
S
svtk 已提交
362
        Set<Instruction> allowedDeadInstructions = Sets.newHashSet();
363

S
svtk 已提交
364
        for (Instruction allowedDeadStartInstruction : allowedDeadStartInstructions) {
365
            collectAllowedDeadInstructions(allowedDeadStartInstruction, allowedDeadInstructions, stopAllowDeadInstructions);
S
svtk 已提交
366 367 368 369
        }
        return allowedDeadInstructions;
    }
    
370
    private void collectAllowedDeadInstructions(Instruction allowedDeadInstruction, Set<Instruction> instructionSet, Set<Instruction> stopAllowDeadInstructions) {
S
svtk 已提交
371
        if (instructionSet.contains(allowedDeadInstruction) || stopAllowDeadInstructions.contains(allowedDeadInstruction)) return;
372
        if (((InstructionImpl)allowedDeadInstruction).isDead()) {
S
svtk 已提交
373 374
            instructionSet.add(allowedDeadInstruction);
            for (Instruction instruction : allowedDeadInstruction.getNextInstructions()) {
375
                collectAllowedDeadInstructions(instruction, instructionSet, stopAllowDeadInstructions);
S
svtk 已提交
376 377 378 379
            }
        }
    }

A
Andrey Breslav 已提交
380 381
    @NotNull
    private Instruction getJumpTarget(@NotNull Label targetLabel) {
382
        return ((PseudocodeLabel)targetLabel).resolveToInstruction();
383
    }
A
Andrey Breslav 已提交
384 385 386 387

    @NotNull
    private Instruction getNextPosition(int currentPosition) {
        int targetPosition = currentPosition + 1;
S
svtk 已提交
388 389
        assert targetPosition < mutableInstructionList.size() : currentPosition;
        return mutableInstructionList.get(targetPosition);
A
Andrey Breslav 已提交
390 391
    }
}