PseudocodeImpl: converted to Kotlin

This commit is contained in:
Mikhail Glukhikh
2016-01-26 13:00:17 +03:00
parent 381c1c4bba
commit 1ddaf465cd
@@ -14,561 +14,455 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.cfg.pseudocode; package org.jetbrains.kotlin.cfg.pseudocode
import com.google.common.collect.*; import com.google.common.collect.*
import com.intellij.util.containers.BidirectionalMap; import com.intellij.util.containers.BidirectionalMap
import kotlin.collections.MapsKt; import org.jetbrains.kotlin.cfg.Label
import kotlin.jvm.functions.Function0; import org.jetbrains.kotlin.cfg.pseudocode.instructions.*
import kotlin.jvm.functions.Function1; import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicInstruction
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind
import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MergeInstruction
import org.jetbrains.kotlin.cfg.Label; import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.AbstractJumpInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.*; import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ConditionalJumpInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicInstruction; import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.NondeterministicJumpInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind; import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MergeInstruction; import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineEnterInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.AbstractJumpInstruction; import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineExitInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ConditionalJumpInstruction; import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineSinkInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.NondeterministicJumpInstruction; import org.jetbrains.kotlin.cfg.pseudocodeTraverser.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction; import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraverseInstructionResult
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineEnterInstruction; import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineExitInstruction;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineSinkInstruction;
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.PseudocodeTraverserKt;
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraverseInstructionResult;
import org.jetbrains.kotlin.psi.KtElement;
import java.util.*; import java.util.*
import static org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder.BACKWARD; import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder.BACKWARD
import static org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder.FORWARD; import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder.FORWARD
public class PseudocodeImpl implements Pseudocode { class PseudocodeImpl(override val correspondingElement: KtElement) : Pseudocode {
public class PseudocodeLabel implements Label { inner class PseudocodeLabel internal constructor(private val name: String, private val comment: String?) : Label {
private final String name; var targetInstructionIndex: Int? = null
private final String comment; private set
private Integer targetInstructionIndex;
override fun getName(): String {
private PseudocodeLabel(@NotNull String name, @Nullable String comment) { return name
this.name = name;
this.comment = comment;
} }
@NotNull override fun toString(): String {
@Override return if (comment == null) name else "$name [$comment]"
public String getName() {
return name;
} }
@Override fun setTargetInstructionIndex(targetInstructionIndex: Int) {
public String toString() { this.targetInstructionIndex = targetInstructionIndex
return comment == null ? name : (name + " [" + comment + "]");
} }
public Integer getTargetInstructionIndex() { fun resolveToInstruction(): Instruction {
return targetInstructionIndex; assert(targetInstructionIndex != null)
return mutableInstructionList[targetInstructionIndex!!]
} }
public void setTargetInstructionIndex(int targetInstructionIndex) { fun copy(newLabelIndex: Int): PseudocodeLabel {
this.targetInstructionIndex = targetInstructionIndex; return PseudocodeLabel("L" + newLabelIndex, "copy of $name, $comment")
} }
@Nullable val pseudocode: PseudocodeImpl
private List<Instruction> resolve() { get() = this@PseudocodeImpl
assert targetInstructionIndex != null;
return mutableInstructionList.subList(getTargetInstructionIndex(), mutableInstructionList.size());
}
public Instruction resolveToInstruction() {
assert targetInstructionIndex != null;
return mutableInstructionList.get(targetInstructionIndex);
}
public PseudocodeLabel copy(int newLabelIndex) {
return new PseudocodeLabel("L" + newLabelIndex, "copy of " + name + ", " + comment);
}
public PseudocodeImpl getPseudocode() {
return PseudocodeImpl.this;
}
} }
private final List<Instruction> mutableInstructionList = new ArrayList<Instruction>(); private val mutableInstructionList = ArrayList<Instruction>()
private final List<Instruction> instructions = new ArrayList<Instruction>(); override val instructions = ArrayList<Instruction>()
private final BidirectionalMap<KtElement, PseudoValue> elementsToValues = new BidirectionalMap<KtElement, PseudoValue>(); private val elementsToValues = BidirectionalMap<KtElement, PseudoValue>()
private final Map<PseudoValue, List<Instruction>> valueUsages = Maps.newHashMap(); private val valueUsages = Maps.newHashMap<PseudoValue, MutableList<Instruction>>()
private final Map<PseudoValue, Set<PseudoValue>> mergedValues = Maps.newHashMap(); private val mergedValues = Maps.newHashMap<PseudoValue, Set<PseudoValue>>()
private final Set<Instruction> sideEffectFree = Sets.newHashSet(); private val sideEffectFree = Sets.newHashSet<Instruction>()
private Pseudocode parent = null; override var parent: Pseudocode? = null
private Set<LocalFunctionDeclarationInstruction> localDeclarations = null; private set
override val localDeclarations: Set<LocalFunctionDeclarationInstruction> by lazy {
getLocalDeclarations(this)
}
//todo getters //todo getters
private final Map<KtElement, Instruction> representativeInstructions = new HashMap<KtElement, Instruction>(); private val representativeInstructions = HashMap<KtElement, Instruction>()
private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>(); private val labels = ArrayList<PseudocodeLabel>()
private final KtElement correspondingElement; private var internalExitInstruction: SubroutineExitInstruction? = null
private SubroutineExitInstruction exitInstruction;
private SubroutineSinkInstruction sinkInstruction;
private SubroutineExitInstruction errorInstruction;
private boolean postPrecessed = false;
public PseudocodeImpl(KtElement correspondingElement) { override val exitInstruction: SubroutineExitInstruction
this.correspondingElement = correspondingElement; get() = internalExitInstruction ?: throw AssertionError("Exit instruction is read before initialization")
}
@NotNull private var internalSinkInstruction: SubroutineSinkInstruction? = null
@Override
public KtElement getCorrespondingElement() {
return correspondingElement;
}
@NotNull override val sinkInstruction: SubroutineSinkInstruction
@Override get() = internalSinkInstruction ?: throw AssertionError("Sink instruction is read before initialization")
public Set<LocalFunctionDeclarationInstruction> getLocalDeclarations() {
if (localDeclarations == null) {
localDeclarations = getLocalDeclarations(this);
}
return localDeclarations;
}
@NotNull private var internalErrorInstruction: SubroutineExitInstruction? = null
private static Set<LocalFunctionDeclarationInstruction> getLocalDeclarations(@NotNull Pseudocode pseudocode) {
Set<LocalFunctionDeclarationInstruction> localDeclarations = Sets.newLinkedHashSet(); private val errorInstruction: SubroutineExitInstruction
for (Instruction instruction : ((PseudocodeImpl)pseudocode).mutableInstructionList) { get() = internalErrorInstruction ?: throw AssertionError("Error instruction is read before initialization")
if (instruction instanceof LocalFunctionDeclarationInstruction) {
localDeclarations.add((LocalFunctionDeclarationInstruction) instruction); private var postPrecessed = false
localDeclarations.addAll(getLocalDeclarations(((LocalFunctionDeclarationInstruction)instruction).getBody()));
private fun getLocalDeclarations(pseudocode: Pseudocode): Set<LocalFunctionDeclarationInstruction> {
val localDeclarations = Sets.newLinkedHashSet<LocalFunctionDeclarationInstruction>()
for (instruction in (pseudocode as PseudocodeImpl).mutableInstructionList) {
if (instruction is LocalFunctionDeclarationInstruction) {
localDeclarations.add(instruction)
localDeclarations.addAll(getLocalDeclarations(instruction.body))
} }
} }
return localDeclarations; return localDeclarations
} }
@Override val rootPseudocode: Pseudocode
@Nullable get() {
public Pseudocode getParent() { var parent = parent
return parent; while (parent != null) {
} if (parent.parent == null) return parent
parent = parent.parent
private void setParent(Pseudocode parent) {
this.parent = parent;
}
@NotNull
public Pseudocode getRootPseudocode() {
Pseudocode parent = getParent();
while (parent != null) {
if (parent.getParent() == null) return parent;
parent = parent.getParent();
}
return this;
}
/*package*/ PseudocodeLabel createLabel(@NotNull String name, @Nullable String comment) {
PseudocodeLabel label = new PseudocodeLabel(name, comment);
labels.add(label);
return label;
}
@Override
@NotNull
public List<Instruction> getInstructions() {
return instructions;
}
@NotNull
@Override
public List<Instruction> getReversedInstructions() {
LinkedHashSet<Instruction> traversedInstructions = Sets.newLinkedHashSet();
PseudocodeTraverserKt.traverseFollowingInstructions(sinkInstruction, traversedInstructions, BACKWARD, null);
if (traversedInstructions.size() < instructions.size()) {
List<Instruction> simplyReversedInstructions = Lists.newArrayList(instructions);
Collections.reverse(simplyReversedInstructions);
for (Instruction instruction : simplyReversedInstructions) {
if (!traversedInstructions.contains(instruction)) {
PseudocodeTraverserKt.traverseFollowingInstructions(instruction, traversedInstructions, BACKWARD, null);
}
} }
} return this
return Lists.newArrayList(traversedInstructions);
}
@Override
@NotNull
public List<Instruction> getInstructionsIncludingDeadCode() {
return mutableInstructionList;
}
//for tests only
@NotNull
public List<PseudocodeLabel> getLabels() {
return labels;
}
/*package*/ void addExitInstruction(SubroutineExitInstruction exitInstruction) {
addInstruction(exitInstruction);
assert this.exitInstruction == null;
this.exitInstruction = exitInstruction;
}
/*package*/ void addSinkInstruction(SubroutineSinkInstruction sinkInstruction) {
addInstruction(sinkInstruction);
assert this.sinkInstruction == null;
this.sinkInstruction = sinkInstruction;
}
/*package*/ void addErrorInstruction(SubroutineExitInstruction errorInstruction) {
addInstruction(errorInstruction);
assert this.errorInstruction == null;
this.errorInstruction = errorInstruction;
}
/*package*/ void addInstruction(Instruction instruction) {
mutableInstructionList.add(instruction);
instruction.setOwner(this);
if (instruction instanceof KtElementInstruction) {
KtElementInstruction elementInstruction = (KtElementInstruction) instruction;
representativeInstructions.put(elementInstruction.getElement(), instruction);
} }
if (instruction instanceof MergeInstruction) { fun createLabel(name: String, comment: String?): PseudocodeLabel {
addMergedValues((MergeInstruction) instruction); val label = PseudocodeLabel(name, comment)
} labels.add(label)
return label
for (PseudoValue inputValue : instruction.getInputValues()) {
addValueUsage(inputValue, instruction);
for (PseudoValue mergedValue : getMergedValues(inputValue)) {
addValueUsage(mergedValue, instruction);
}
}
if (PseudocodeUtilsKt.calcSideEffectFree(instruction)) {
sideEffectFree.add(instruction);
}
} }
@Override override val reversedInstructions: List<Instruction>
@NotNull get() {
public SubroutineExitInstruction getExitInstruction() { val traversedInstructions = Sets.newLinkedHashSet<Instruction>()
return exitInstruction; traverseFollowingInstructions(sinkInstruction, traversedInstructions, BACKWARD, null)
} if (traversedInstructions.size < instructions.size) {
val simplyReversedInstructions = Lists.newArrayList(instructions)
@Override Collections.reverse(simplyReversedInstructions)
@NotNull for (instruction in simplyReversedInstructions) {
public SubroutineSinkInstruction getSinkInstruction() { if (!traversedInstructions.contains(instruction)) {
return sinkInstruction; traverseFollowingInstructions(instruction, traversedInstructions, BACKWARD, null)
}
@Override
@NotNull
public SubroutineEnterInstruction getEnterInstruction() {
return (SubroutineEnterInstruction) mutableInstructionList.get(0);
}
@Nullable
@Override
public PseudoValue getElementValue(@Nullable KtElement element) {
return elementsToValues.get(element);
}
@NotNull
@Override
public List<KtElement> getValueElements(@Nullable PseudoValue value) {
List<KtElement> result = elementsToValues.getKeysByValue(value);
return result != null ? result : Collections.<KtElement>emptyList();
}
@NotNull
@Override
public List<Instruction> getUsages(@Nullable PseudoValue value) {
List<Instruction> result = valueUsages.get(value);
return result != null ? result : Collections.<Instruction>emptyList();
}
@Override
public boolean isSideEffectFree(@NotNull Instruction instruction) {
return sideEffectFree.contains(instruction);
}
/*package*/ void bindElementToValue(@NotNull KtElement element, @NotNull PseudoValue value) {
elementsToValues.put(element, value);
}
/*package*/ void bindLabel(Label label) {
((PseudocodeLabel) label).setTargetInstructionIndex(mutableInstructionList.size());
}
private Set<PseudoValue> getMergedValues(@NotNull PseudoValue value) {
Set<PseudoValue> result = mergedValues.get(value);
return result != null ? result : Collections.<PseudoValue>emptySet();
}
private void addMergedValues(@NotNull MergeInstruction instruction) {
Set<PseudoValue> result = new LinkedHashSet<PseudoValue>();
for (PseudoValue value : instruction.getInputValues()) {
result.addAll(getMergedValues(value));
result.add(value);
}
mergedValues.put(instruction.getOutputValue(), result);
}
private void addValueUsage(PseudoValue value, Instruction usage) {
if (usage instanceof MergeInstruction) return;
MapsKt.getOrPut(
valueUsages,
value,
new Function0<List<Instruction>>() {
@Override
public List<Instruction> invoke() {
return Lists.newArrayList();
} }
} }
).add(usage); }
return Lists.newArrayList(traversedInstructions)
}
override val instructionsIncludingDeadCode: List<Instruction>
get() = mutableInstructionList
//for tests only
fun getLabels(): List<PseudocodeLabel> {
return labels
} }
public void postProcess() { fun addExitInstruction(exitInstruction: SubroutineExitInstruction) {
if (postPrecessed) return; addInstruction(exitInstruction)
postPrecessed = true; assert(internalExitInstruction == null) {
errorInstruction.setSink(getSinkInstruction()); "Repeated initialization of exit instruction: $internalExitInstruction --> $exitInstruction"
exitInstruction.setSink(getSinkInstruction());
int index = 0;
for (Instruction instruction : mutableInstructionList) {
//recursively invokes 'postProcess' for local declarations
processInstruction(instruction, index);
index++;
} }
if (getParent() != null) return; internalExitInstruction = exitInstruction
}
fun addSinkInstruction(sinkInstruction: SubroutineSinkInstruction) {
addInstruction(sinkInstruction)
assert(internalSinkInstruction == null) {
"Repeated initialization of sink instruction: $internalSinkInstruction --> $sinkInstruction"
}
internalSinkInstruction = sinkInstruction
}
fun addErrorInstruction(errorInstruction: SubroutineExitInstruction) {
addInstruction(errorInstruction)
assert(internalErrorInstruction == null) {
"Repeated initialization of error instruction: $internalErrorInstruction --> $errorInstruction"
}
internalErrorInstruction = errorInstruction
}
fun addInstruction(instruction: Instruction) {
mutableInstructionList.add(instruction)
instruction.owner = this
if (instruction is KtElementInstruction) {
representativeInstructions.put(instruction.element, instruction)
}
if (instruction is MergeInstruction) {
addMergedValues(instruction)
}
for (inputValue in instruction.inputValues) {
addValueUsage(inputValue, instruction)
for (mergedValue in getMergedValues(inputValue)) {
addValueUsage(mergedValue, instruction)
}
}
if (instruction.calcSideEffectFree()) {
sideEffectFree.add(instruction)
}
}
override val enterInstruction: SubroutineEnterInstruction
get() = mutableInstructionList[0] as SubroutineEnterInstruction
override fun getElementValue(element: KtElement?) = elementsToValues[element]
override fun getValueElements(value: PseudoValue?) = elementsToValues.getKeysByValue(value) ?: emptyList()
override fun getUsages(value: PseudoValue?) = valueUsages[value] ?: mutableListOf()
override fun isSideEffectFree(instruction: Instruction) = sideEffectFree.contains(instruction)
fun bindElementToValue(element: KtElement, value: PseudoValue) {
elementsToValues.put(element, value)
}
fun bindLabel(label: Label) {
(label as PseudocodeLabel).setTargetInstructionIndex(mutableInstructionList.size)
}
private fun getMergedValues(value: PseudoValue) = mergedValues[value] ?: emptySet()
private fun addMergedValues(instruction: MergeInstruction) {
val result = LinkedHashSet<PseudoValue>()
for (value in instruction.inputValues) {
result.addAll(getMergedValues(value))
result.add(value)
}
mergedValues.put(instruction.outputValue, result)
}
private fun addValueUsage(value: PseudoValue, usage: Instruction) {
if (usage is MergeInstruction) return
valueUsages.getOrPut(
value
) { Lists.newArrayList<Instruction>() }.add(usage)
}
fun postProcess() {
if (postPrecessed) return
postPrecessed = true
errorInstruction.sink = sinkInstruction
exitInstruction.sink = sinkInstruction
var index = 0
for (instruction in mutableInstructionList) {
//recursively invokes 'postProcess' for local declarations
processInstruction(instruction, index)
index++
}
if (parent != null) return
// Collecting reachable instructions should be done after processing all instructions // Collecting reachable instructions should be done after processing all instructions
// (including instructions in local declarations) to avoid being in incomplete state. // (including instructions in local declarations) to avoid being in incomplete state.
collectAndCacheReachableInstructions(); collectAndCacheReachableInstructions()
for (LocalFunctionDeclarationInstruction localFunctionDeclarationInstruction : getLocalDeclarations()) { for (localFunctionDeclarationInstruction in localDeclarations) {
((PseudocodeImpl) localFunctionDeclarationInstruction.getBody()).collectAndCacheReachableInstructions(); (localFunctionDeclarationInstruction.body as PseudocodeImpl).collectAndCacheReachableInstructions()
} }
} }
private void collectAndCacheReachableInstructions() { private fun collectAndCacheReachableInstructions() {
Set<Instruction> reachableInstructions = collectReachableInstructions(); val reachableInstructions = collectReachableInstructions()
for (Instruction instruction : mutableInstructionList) { for (instruction in mutableInstructionList) {
if (reachableInstructions.contains(instruction)) { if (reachableInstructions.contains(instruction)) {
instructions.add(instruction); instructions.add(instruction)
} }
} }
markDeadInstructions(); markDeadInstructions()
} }
private void processInstruction(Instruction instruction, final int currentPosition) { private fun processInstruction(instruction: Instruction, currentPosition: Int) {
instruction.accept(new InstructionVisitor() { instruction.accept(object : InstructionVisitor() {
@Override override fun visitInstructionWithNext(instruction: InstructionWithNext) {
public void visitInstructionWithNext(@NotNull InstructionWithNext instruction) { instruction.next = getNextPosition(currentPosition)
instruction.setNext(getNextPosition(currentPosition));
} }
@Override override fun visitJump(instruction: AbstractJumpInstruction) {
public void visitJump(@NotNull AbstractJumpInstruction instruction) { instruction.resolvedTarget = getJumpTarget(instruction.targetLabel)
instruction.setResolvedTarget(getJumpTarget(instruction.getTargetLabel()));
} }
@Override override fun visitNondeterministicJump(instruction: NondeterministicJumpInstruction) {
public void visitNondeterministicJump(@NotNull NondeterministicJumpInstruction instruction) { instruction.next = getNextPosition(currentPosition)
instruction.setNext(getNextPosition(currentPosition)); val targetLabels = instruction.targetLabels
List<Label> targetLabels = instruction.getTargetLabels(); for (targetLabel in targetLabels) {
for (Label targetLabel : targetLabels) { instruction.setResolvedTarget(targetLabel, getJumpTarget(targetLabel))
instruction.setResolvedTarget(targetLabel, getJumpTarget(targetLabel));
} }
} }
@Override override fun visitConditionalJump(instruction: ConditionalJumpInstruction) {
public void visitConditionalJump(@NotNull ConditionalJumpInstruction instruction) { val nextInstruction = getNextPosition(currentPosition)
Instruction nextInstruction = getNextPosition(currentPosition); val jumpTarget = getJumpTarget(instruction.targetLabel)
Instruction jumpTarget = getJumpTarget(instruction.getTargetLabel()); if (instruction.onTrue) {
if (instruction.getOnTrue()) { instruction.nextOnFalse = nextInstruction
instruction.setNextOnFalse(nextInstruction); instruction.nextOnTrue = jumpTarget
instruction.setNextOnTrue(jumpTarget);
} }
else { else {
instruction.setNextOnFalse(jumpTarget); instruction.nextOnFalse = jumpTarget
instruction.setNextOnTrue(nextInstruction); instruction.nextOnTrue = nextInstruction
} }
visitJump(instruction); visitJump(instruction)
} }
@Override override fun visitLocalFunctionDeclarationInstruction(instruction: LocalFunctionDeclarationInstruction) {
public void visitLocalFunctionDeclarationInstruction(@NotNull LocalFunctionDeclarationInstruction instruction) { val body = instruction.body as PseudocodeImpl
PseudocodeImpl body = (PseudocodeImpl) instruction.getBody(); body.parent = this@PseudocodeImpl
body.setParent(PseudocodeImpl.this); body.postProcess()
body.postProcess(); instruction.next = sinkInstruction
instruction.setNext(getSinkInstruction());
} }
@Override override fun visitSubroutineExit(instruction: SubroutineExitInstruction) {
public void visitSubroutineExit(@NotNull SubroutineExitInstruction instruction) {
// Nothing // Nothing
} }
@Override override fun visitSubroutineSink(instruction: SubroutineSinkInstruction) {
public void visitSubroutineSink(@NotNull SubroutineSinkInstruction instruction) {
// Nothing // Nothing
} }
@Override override fun visitInstruction(instruction: Instruction) {
public void visitInstruction(@NotNull Instruction instruction) { throw UnsupportedOperationException(instruction.toString())
throw new UnsupportedOperationException(instruction.toString());
} }
}); })
} }
private Set<Instruction> collectReachableInstructions() { private fun collectReachableInstructions(): Set<Instruction> {
Set<Instruction> visited = Sets.newHashSet(); val visited = Sets.newHashSet<Instruction>()
PseudocodeTraverserKt.traverseFollowingInstructions(getEnterInstruction(), visited, FORWARD, traverseFollowingInstructions(enterInstruction, visited, FORWARD
new Function1<Instruction, TraverseInstructionResult>() { ) { instruction ->
@Override if (instruction is MagicInstruction && instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
public TraverseInstructionResult invoke(Instruction instruction) { return@traverseFollowingInstructions TraverseInstructionResult.SKIP
if (instruction instanceof MagicInstruction &&
((MagicInstruction) instruction).getKind() == MagicKind.EXHAUSTIVE_WHEN_ELSE) {
return TraverseInstructionResult.SKIP;
}
return TraverseInstructionResult.CONTINUE;
} }
}); TraverseInstructionResult.CONTINUE
if (!visited.contains(getExitInstruction())) { }
visited.add(getExitInstruction()); if (!visited.contains(exitInstruction)) {
visited.add(exitInstruction)
} }
if (!visited.contains(errorInstruction)) { if (!visited.contains(errorInstruction)) {
visited.add(errorInstruction); visited.add(errorInstruction)
} }
if (!visited.contains(getSinkInstruction())) { if (!visited.contains(sinkInstruction)) {
visited.add(getSinkInstruction()); visited.add(sinkInstruction)
} }
return visited; return visited
} }
private void markDeadInstructions() { private fun markDeadInstructions() {
Set<Instruction> instructionSet = Sets.newHashSet(instructions); val instructionSet = Sets.newHashSet(instructions)
for (Instruction instruction : mutableInstructionList) { for (instruction in mutableInstructionList) {
if (!instructionSet.contains(instruction)) { if (!instructionSet.contains(instruction)) {
((InstructionImpl)instruction).setMarkedAsDead(true); (instruction as? InstructionImpl)?.markedAsDead = true
for (Instruction nextInstruction : instruction.getNextInstructions()) { for (nextInstruction in instruction.nextInstructions) {
nextInstruction.getPreviousInstructions().remove(instruction); (nextInstruction as? InstructionImpl)?.previousInstructions?.remove(instruction)
} }
} }
} }
} }
@NotNull private fun getJumpTarget(targetLabel: Label): Instruction {
private Instruction getJumpTarget(@NotNull Label targetLabel) { return (targetLabel as PseudocodeLabel).resolveToInstruction()
return ((PseudocodeLabel)targetLabel).resolveToInstruction();
} }
@NotNull private fun getNextPosition(currentPosition: Int): Instruction {
private Instruction getNextPosition(int currentPosition) { val targetPosition = currentPosition + 1
int targetPosition = currentPosition + 1; assert(targetPosition < mutableInstructionList.size) { currentPosition }
assert targetPosition < mutableInstructionList.size() : currentPosition; return mutableInstructionList[targetPosition]
return mutableInstructionList.get(targetPosition);
} }
@Override override fun copy(): PseudocodeImpl {
public PseudocodeImpl copy() { val result = PseudocodeImpl(correspondingElement)
PseudocodeImpl result = new PseudocodeImpl(correspondingElement); result.repeatWhole(this)
result.repeatWhole(this); return result
return result;
} }
private void repeatWhole(@NotNull PseudocodeImpl originalPseudocode) { private fun repeatWhole(originalPseudocode: PseudocodeImpl) {
repeatInternal(originalPseudocode, null, null, 0); repeatInternal(originalPseudocode, null, null, 0)
parent = originalPseudocode.parent; parent = originalPseudocode.parent
} }
public int repeatPart(@NotNull Label startLabel, @NotNull Label finishLabel, int labelCount) { fun repeatPart(startLabel: Label, finishLabel: Label, labelCount: Int): Int {
return repeatInternal(((PseudocodeLabel) startLabel).getPseudocode(), startLabel, finishLabel, labelCount); return repeatInternal((startLabel as PseudocodeLabel).pseudocode, startLabel, finishLabel, labelCount)
} }
private int repeatInternal( private fun repeatInternal(
@NotNull PseudocodeImpl originalPseudocode, originalPseudocode: PseudocodeImpl,
@Nullable Label startLabel, @Nullable Label finishLabel, startLabel: Label?, finishLabel: Label?,
int labelCount) { labelCountArg: Int): Int {
Integer startIndex = startLabel != null ? ((PseudocodeLabel) startLabel).getTargetInstructionIndex() : Integer.valueOf(0); var labelCount = labelCountArg
assert startIndex != null; val startIndex = (if (startLabel != null) (startLabel as PseudocodeLabel).targetInstructionIndex else Integer.valueOf(0))!!
Integer finishIndex = finishLabel != null val finishIndex = (if (finishLabel != null)
? ((PseudocodeLabel) finishLabel).getTargetInstructionIndex() (finishLabel as PseudocodeLabel).targetInstructionIndex
: Integer.valueOf(originalPseudocode.mutableInstructionList.size()); else
assert finishIndex != null; Integer.valueOf(originalPseudocode.mutableInstructionList.size))!!
Map<Label, Label> originalToCopy = Maps.newLinkedHashMap(); val originalToCopy = Maps.newLinkedHashMap<Label, Label>()
Multimap<Instruction, Label> originalLabelsForInstruction = HashMultimap.create(); val originalLabelsForInstruction = HashMultimap.create<Instruction, Label>()
for (PseudocodeLabel label : originalPseudocode.labels) { for (label in originalPseudocode.labels) {
Integer index = label.getTargetInstructionIndex(); val index = label.targetInstructionIndex ?: continue
if (index == null) continue; //label is not bounded yet //label is not bounded yet
if (label == startLabel || label == finishLabel) continue; if (label === startLabel || label === finishLabel) continue
if (startIndex <= index && index <= finishIndex) { if (startIndex <= index && index <= finishIndex) {
originalToCopy.put(label, label.copy(labelCount++)); originalToCopy.put(label, label.copy(labelCount++))
originalLabelsForInstruction.put(getJumpTarget(label), label); originalLabelsForInstruction.put(getJumpTarget(label), label)
} }
} }
for (Label label : originalToCopy.values()) { for (label in originalToCopy.values) {
labels.add((PseudocodeLabel) label); labels.add(label as PseudocodeLabel)
} }
for (int index = startIndex; index < finishIndex; index++) { for (index in startIndex..finishIndex - 1) {
Instruction originalInstruction = originalPseudocode.mutableInstructionList.get(index); val originalInstruction = originalPseudocode.mutableInstructionList[index]
repeatLabelsBindingForInstruction(originalInstruction, originalToCopy, originalLabelsForInstruction); repeatLabelsBindingForInstruction(originalInstruction, originalToCopy, originalLabelsForInstruction)
Instruction copy = copyInstruction(originalInstruction, originalToCopy); val copy = copyInstruction(originalInstruction, originalToCopy)
addInstruction(copy); addInstruction(copy)
if (originalInstruction == originalPseudocode.errorInstruction && copy instanceof SubroutineExitInstruction) { if (originalInstruction === originalPseudocode.internalErrorInstruction && copy is SubroutineExitInstruction) {
errorInstruction = (SubroutineExitInstruction) copy; internalErrorInstruction = copy
} }
if (originalInstruction == originalPseudocode.exitInstruction && copy instanceof SubroutineExitInstruction) { if (originalInstruction === originalPseudocode.internalExitInstruction && copy is SubroutineExitInstruction) {
exitInstruction = (SubroutineExitInstruction) copy; internalExitInstruction = copy
} }
if (originalInstruction == originalPseudocode.sinkInstruction && copy instanceof SubroutineSinkInstruction) { if (originalInstruction === originalPseudocode.internalSinkInstruction && copy is SubroutineSinkInstruction) {
sinkInstruction = (SubroutineSinkInstruction) copy; internalSinkInstruction = copy
} }
} }
if (finishIndex < mutableInstructionList.size()) { if (finishIndex < mutableInstructionList.size) {
repeatLabelsBindingForInstruction(originalPseudocode.mutableInstructionList.get(finishIndex), repeatLabelsBindingForInstruction(originalPseudocode.mutableInstructionList[finishIndex],
originalToCopy, originalToCopy,
originalLabelsForInstruction); originalLabelsForInstruction)
} }
return labelCount; return labelCount
} }
private void repeatLabelsBindingForInstruction( private fun repeatLabelsBindingForInstruction(
@NotNull Instruction originalInstruction, originalInstruction: Instruction,
@NotNull Map<Label, Label> originalToCopy, originalToCopy: Map<Label, Label>,
@NotNull Multimap<Instruction, Label> originalLabelsForInstruction originalLabelsForInstruction: Multimap<Instruction, Label>) {
) { for (originalLabel in originalLabelsForInstruction.get(originalInstruction)) {
for (Label originalLabel : originalLabelsForInstruction.get(originalInstruction)) { bindLabel(originalToCopy[originalLabel]!!)
bindLabel(originalToCopy.get(originalLabel));
} }
} }
private static Instruction copyInstruction(@NotNull Instruction instruction, @NotNull Map<Label, Label> originalToCopy) { private fun copyInstruction(instruction: Instruction, originalToCopy: Map<Label, Label>): Instruction {
if (instruction instanceof AbstractJumpInstruction) { if (instruction is AbstractJumpInstruction) {
Label originalTarget = ((AbstractJumpInstruction) instruction).getTargetLabel(); val originalTarget = instruction.targetLabel
if (originalToCopy.containsKey(originalTarget)) { if (originalToCopy.containsKey(originalTarget)) {
return ((AbstractJumpInstruction)instruction).copy(originalToCopy.get(originalTarget)); return instruction.copy(originalToCopy[originalTarget]!!)
} }
} }
if (instruction instanceof NondeterministicJumpInstruction) { if (instruction is NondeterministicJumpInstruction) {
List<Label> originalTargets = ((NondeterministicJumpInstruction) instruction).getTargetLabels(); val originalTargets = instruction.targetLabels
List<Label> copyTargets = copyLabels(originalTargets, originalToCopy); val copyTargets = copyLabels(originalTargets, originalToCopy)
return ((NondeterministicJumpInstruction) instruction).copy(copyTargets); return instruction.copy(copyTargets)
} }
return ((InstructionImpl)instruction).copy(); return (instruction as InstructionImpl).copy()
} }
@NotNull private fun copyLabels(labels: Collection<Label>, originalToCopy: Map<Label, Label>): MutableList<Label> {
private static List<Label> copyLabels(Collection<Label> labels, Map<Label, Label> originalToCopy) { val newLabels = Lists.newArrayList<Label>()
List<Label> newLabels = Lists.newArrayList(); for (label in labels) {
for (Label label : labels) { val newLabel = originalToCopy[label]
Label newLabel = originalToCopy.get(label); newLabels.add(newLabel ?: label)
newLabels.add(newLabel != null ? newLabel : label);
} }
return newLabels; return newLabels
} }
} }