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.
*/
package org.jetbrains.kotlin.cfg.pseudocode;
package org.jetbrains.kotlin.cfg.pseudocode
import com.google.common.collect.*;
import com.intellij.util.containers.BidirectionalMap;
import kotlin.collections.MapsKt;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.cfg.Label;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.*;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicInstruction;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MergeInstruction;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.AbstractJumpInstruction;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ConditionalJumpInstruction;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.NondeterministicJumpInstruction;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineEnterInstruction;
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 com.google.common.collect.*
import com.intellij.util.containers.BidirectionalMap
import org.jetbrains.kotlin.cfg.Label
import org.jetbrains.kotlin.cfg.pseudocode.instructions.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MergeInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.AbstractJumpInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ConditionalJumpInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.NondeterministicJumpInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineEnterInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineExitInstruction
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.SubroutineSinkInstruction
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.*
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 static org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder.FORWARD;
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder.BACKWARD
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 {
private final String name;
private final String comment;
private Integer targetInstructionIndex;
inner class PseudocodeLabel internal constructor(private val name: String, private val comment: String?) : Label {
var targetInstructionIndex: Int? = null
private set
private PseudocodeLabel(@NotNull String name, @Nullable String comment) {
this.name = name;
this.comment = comment;
override fun getName(): String {
return name
}
@NotNull
@Override
public String getName() {
return name;
override fun toString(): String {
return if (comment == null) name else "$name [$comment]"
}
@Override
public String toString() {
return comment == null ? name : (name + " [" + comment + "]");
fun setTargetInstructionIndex(targetInstructionIndex: Int) {
this.targetInstructionIndex = targetInstructionIndex
}
public Integer getTargetInstructionIndex() {
return targetInstructionIndex;
fun resolveToInstruction(): Instruction {
assert(targetInstructionIndex != null)
return mutableInstructionList[targetInstructionIndex!!]
}
public void setTargetInstructionIndex(int targetInstructionIndex) {
this.targetInstructionIndex = targetInstructionIndex;
fun copy(newLabelIndex: Int): PseudocodeLabel {
return PseudocodeLabel("L" + newLabelIndex, "copy of $name, $comment")
}
@Nullable
private List<Instruction> resolve() {
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;
}
val pseudocode: PseudocodeImpl
get() = this@PseudocodeImpl
}
private final List<Instruction> mutableInstructionList = new ArrayList<Instruction>();
private final List<Instruction> instructions = new ArrayList<Instruction>();
private val mutableInstructionList = 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 final Map<PseudoValue, Set<PseudoValue>> mergedValues = Maps.newHashMap();
private final Set<Instruction> sideEffectFree = Sets.newHashSet();
private val valueUsages = Maps.newHashMap<PseudoValue, MutableList<Instruction>>()
private val mergedValues = Maps.newHashMap<PseudoValue, Set<PseudoValue>>()
private val sideEffectFree = Sets.newHashSet<Instruction>()
private Pseudocode parent = null;
private Set<LocalFunctionDeclarationInstruction> localDeclarations = null;
override var parent: Pseudocode? = null
private set
override val localDeclarations: Set<LocalFunctionDeclarationInstruction> by lazy {
getLocalDeclarations(this)
}
//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 SubroutineExitInstruction exitInstruction;
private SubroutineSinkInstruction sinkInstruction;
private SubroutineExitInstruction errorInstruction;
private boolean postPrecessed = false;
private var internalExitInstruction: SubroutineExitInstruction? = null
public PseudocodeImpl(KtElement correspondingElement) {
this.correspondingElement = correspondingElement;
}
override val exitInstruction: SubroutineExitInstruction
get() = internalExitInstruction ?: throw AssertionError("Exit instruction is read before initialization")
@NotNull
@Override
public KtElement getCorrespondingElement() {
return correspondingElement;
}
private var internalSinkInstruction: SubroutineSinkInstruction? = null
@NotNull
@Override
public Set<LocalFunctionDeclarationInstruction> getLocalDeclarations() {
if (localDeclarations == null) {
localDeclarations = getLocalDeclarations(this);
}
return localDeclarations;
}
override val sinkInstruction: SubroutineSinkInstruction
get() = internalSinkInstruction ?: throw AssertionError("Sink instruction is read before initialization")
@NotNull
private static Set<LocalFunctionDeclarationInstruction> getLocalDeclarations(@NotNull Pseudocode pseudocode) {
Set<LocalFunctionDeclarationInstruction> localDeclarations = Sets.newLinkedHashSet();
for (Instruction instruction : ((PseudocodeImpl)pseudocode).mutableInstructionList) {
if (instruction instanceof LocalFunctionDeclarationInstruction) {
localDeclarations.add((LocalFunctionDeclarationInstruction) instruction);
localDeclarations.addAll(getLocalDeclarations(((LocalFunctionDeclarationInstruction)instruction).getBody()));
private var internalErrorInstruction: SubroutineExitInstruction? = null
private val errorInstruction: SubroutineExitInstruction
get() = internalErrorInstruction ?: throw AssertionError("Error instruction is read before initialization")
private var postPrecessed = false
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
@Nullable
public Pseudocode getParent() {
return 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);
}
val rootPseudocode: Pseudocode
get() {
var parent = parent
while (parent != null) {
if (parent.parent == null) return parent
parent = parent.parent
}
}
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);
return this
}
if (instruction instanceof MergeInstruction) {
addMergedValues((MergeInstruction) instruction);
}
for (PseudoValue inputValue : instruction.getInputValues()) {
addValueUsage(inputValue, instruction);
for (PseudoValue mergedValue : getMergedValues(inputValue)) {
addValueUsage(mergedValue, instruction);
}
}
if (PseudocodeUtilsKt.calcSideEffectFree(instruction)) {
sideEffectFree.add(instruction);
}
fun createLabel(name: String, comment: String?): PseudocodeLabel {
val label = PseudocodeLabel(name, comment)
labels.add(label)
return label
}
@Override
@NotNull
public SubroutineExitInstruction getExitInstruction() {
return exitInstruction;
}
@Override
@NotNull
public SubroutineSinkInstruction getSinkInstruction() {
return sinkInstruction;
}
@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();
override val reversedInstructions: List<Instruction>
get() {
val traversedInstructions = Sets.newLinkedHashSet<Instruction>()
traverseFollowingInstructions(sinkInstruction, traversedInstructions, BACKWARD, null)
if (traversedInstructions.size < instructions.size) {
val simplyReversedInstructions = Lists.newArrayList(instructions)
Collections.reverse(simplyReversedInstructions)
for (instruction in simplyReversedInstructions) {
if (!traversedInstructions.contains(instruction)) {
traverseFollowingInstructions(instruction, traversedInstructions, BACKWARD, null)
}
}
).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() {
if (postPrecessed) return;
postPrecessed = true;
errorInstruction.setSink(getSinkInstruction());
exitInstruction.setSink(getSinkInstruction());
int index = 0;
for (Instruction instruction : mutableInstructionList) {
//recursively invokes 'postProcess' for local declarations
processInstruction(instruction, index);
index++;
fun addExitInstruction(exitInstruction: SubroutineExitInstruction) {
addInstruction(exitInstruction)
assert(internalExitInstruction == null) {
"Repeated initialization of exit instruction: $internalExitInstruction --> $exitInstruction"
}
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
// (including instructions in local declarations) to avoid being in incomplete state.
collectAndCacheReachableInstructions();
for (LocalFunctionDeclarationInstruction localFunctionDeclarationInstruction : getLocalDeclarations()) {
((PseudocodeImpl) localFunctionDeclarationInstruction.getBody()).collectAndCacheReachableInstructions();
collectAndCacheReachableInstructions()
for (localFunctionDeclarationInstruction in localDeclarations) {
(localFunctionDeclarationInstruction.body as PseudocodeImpl).collectAndCacheReachableInstructions()
}
}
private void collectAndCacheReachableInstructions() {
Set<Instruction> reachableInstructions = collectReachableInstructions();
for (Instruction instruction : mutableInstructionList) {
private fun collectAndCacheReachableInstructions() {
val reachableInstructions = collectReachableInstructions()
for (instruction in mutableInstructionList) {
if (reachableInstructions.contains(instruction)) {
instructions.add(instruction);
instructions.add(instruction)
}
}
markDeadInstructions();
markDeadInstructions()
}
private void processInstruction(Instruction instruction, final int currentPosition) {
instruction.accept(new InstructionVisitor() {
@Override
public void visitInstructionWithNext(@NotNull InstructionWithNext instruction) {
instruction.setNext(getNextPosition(currentPosition));
private fun processInstruction(instruction: Instruction, currentPosition: Int) {
instruction.accept(object : InstructionVisitor() {
override fun visitInstructionWithNext(instruction: InstructionWithNext) {
instruction.next = getNextPosition(currentPosition)
}
@Override
public void visitJump(@NotNull AbstractJumpInstruction instruction) {
instruction.setResolvedTarget(getJumpTarget(instruction.getTargetLabel()));
override fun visitJump(instruction: AbstractJumpInstruction) {
instruction.resolvedTarget = getJumpTarget(instruction.targetLabel)
}
@Override
public void visitNondeterministicJump(@NotNull NondeterministicJumpInstruction instruction) {
instruction.setNext(getNextPosition(currentPosition));
List<Label> targetLabels = instruction.getTargetLabels();
for (Label targetLabel : targetLabels) {
instruction.setResolvedTarget(targetLabel, getJumpTarget(targetLabel));
override fun visitNondeterministicJump(instruction: NondeterministicJumpInstruction) {
instruction.next = getNextPosition(currentPosition)
val targetLabels = instruction.targetLabels
for (targetLabel in targetLabels) {
instruction.setResolvedTarget(targetLabel, getJumpTarget(targetLabel))
}
}
@Override
public void visitConditionalJump(@NotNull ConditionalJumpInstruction instruction) {
Instruction nextInstruction = getNextPosition(currentPosition);
Instruction jumpTarget = getJumpTarget(instruction.getTargetLabel());
if (instruction.getOnTrue()) {
instruction.setNextOnFalse(nextInstruction);
instruction.setNextOnTrue(jumpTarget);
override fun visitConditionalJump(instruction: ConditionalJumpInstruction) {
val nextInstruction = getNextPosition(currentPosition)
val jumpTarget = getJumpTarget(instruction.targetLabel)
if (instruction.onTrue) {
instruction.nextOnFalse = nextInstruction
instruction.nextOnTrue = jumpTarget
}
else {
instruction.setNextOnFalse(jumpTarget);
instruction.setNextOnTrue(nextInstruction);
instruction.nextOnFalse = jumpTarget
instruction.nextOnTrue = nextInstruction
}
visitJump(instruction);
visitJump(instruction)
}
@Override
public void visitLocalFunctionDeclarationInstruction(@NotNull LocalFunctionDeclarationInstruction instruction) {
PseudocodeImpl body = (PseudocodeImpl) instruction.getBody();
body.setParent(PseudocodeImpl.this);
body.postProcess();
instruction.setNext(getSinkInstruction());
override fun visitLocalFunctionDeclarationInstruction(instruction: LocalFunctionDeclarationInstruction) {
val body = instruction.body as PseudocodeImpl
body.parent = this@PseudocodeImpl
body.postProcess()
instruction.next = sinkInstruction
}
@Override
public void visitSubroutineExit(@NotNull SubroutineExitInstruction instruction) {
override fun visitSubroutineExit(instruction: SubroutineExitInstruction) {
// Nothing
}
@Override
public void visitSubroutineSink(@NotNull SubroutineSinkInstruction instruction) {
override fun visitSubroutineSink(instruction: SubroutineSinkInstruction) {
// Nothing
}
@Override
public void visitInstruction(@NotNull Instruction instruction) {
throw new UnsupportedOperationException(instruction.toString());
override fun visitInstruction(instruction: Instruction) {
throw UnsupportedOperationException(instruction.toString())
}
});
})
}
private Set<Instruction> collectReachableInstructions() {
Set<Instruction> visited = Sets.newHashSet();
PseudocodeTraverserKt.traverseFollowingInstructions(getEnterInstruction(), visited, FORWARD,
new Function1<Instruction, TraverseInstructionResult>() {
@Override
public TraverseInstructionResult invoke(Instruction instruction) {
if (instruction instanceof MagicInstruction &&
((MagicInstruction) instruction).getKind() == MagicKind.EXHAUSTIVE_WHEN_ELSE) {
return TraverseInstructionResult.SKIP;
}
return TraverseInstructionResult.CONTINUE;
private fun collectReachableInstructions(): Set<Instruction> {
val visited = Sets.newHashSet<Instruction>()
traverseFollowingInstructions(enterInstruction, visited, FORWARD
) { instruction ->
if (instruction is MagicInstruction && instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
return@traverseFollowingInstructions TraverseInstructionResult.SKIP
}
});
if (!visited.contains(getExitInstruction())) {
visited.add(getExitInstruction());
TraverseInstructionResult.CONTINUE
}
if (!visited.contains(exitInstruction)) {
visited.add(exitInstruction)
}
if (!visited.contains(errorInstruction)) {
visited.add(errorInstruction);
visited.add(errorInstruction)
}
if (!visited.contains(getSinkInstruction())) {
visited.add(getSinkInstruction());
if (!visited.contains(sinkInstruction)) {
visited.add(sinkInstruction)
}
return visited;
return visited
}
private void markDeadInstructions() {
Set<Instruction> instructionSet = Sets.newHashSet(instructions);
for (Instruction instruction : mutableInstructionList) {
private fun markDeadInstructions() {
val instructionSet = Sets.newHashSet(instructions)
for (instruction in mutableInstructionList) {
if (!instructionSet.contains(instruction)) {
((InstructionImpl)instruction).setMarkedAsDead(true);
for (Instruction nextInstruction : instruction.getNextInstructions()) {
nextInstruction.getPreviousInstructions().remove(instruction);
(instruction as? InstructionImpl)?.markedAsDead = true
for (nextInstruction in instruction.nextInstructions) {
(nextInstruction as? InstructionImpl)?.previousInstructions?.remove(instruction)
}
}
}
}
@NotNull
private Instruction getJumpTarget(@NotNull Label targetLabel) {
return ((PseudocodeLabel)targetLabel).resolveToInstruction();
private fun getJumpTarget(targetLabel: Label): Instruction {
return (targetLabel as PseudocodeLabel).resolveToInstruction()
}
@NotNull
private Instruction getNextPosition(int currentPosition) {
int targetPosition = currentPosition + 1;
assert targetPosition < mutableInstructionList.size() : currentPosition;
return mutableInstructionList.get(targetPosition);
private fun getNextPosition(currentPosition: Int): Instruction {
val targetPosition = currentPosition + 1
assert(targetPosition < mutableInstructionList.size) { currentPosition }
return mutableInstructionList[targetPosition]
}
@Override
public PseudocodeImpl copy() {
PseudocodeImpl result = new PseudocodeImpl(correspondingElement);
result.repeatWhole(this);
return result;
override fun copy(): PseudocodeImpl {
val result = PseudocodeImpl(correspondingElement)
result.repeatWhole(this)
return result
}
private void repeatWhole(@NotNull PseudocodeImpl originalPseudocode) {
repeatInternal(originalPseudocode, null, null, 0);
parent = originalPseudocode.parent;
private fun repeatWhole(originalPseudocode: PseudocodeImpl) {
repeatInternal(originalPseudocode, null, null, 0)
parent = originalPseudocode.parent
}
public int repeatPart(@NotNull Label startLabel, @NotNull Label finishLabel, int labelCount) {
return repeatInternal(((PseudocodeLabel) startLabel).getPseudocode(), startLabel, finishLabel, labelCount);
fun repeatPart(startLabel: Label, finishLabel: Label, labelCount: Int): Int {
return repeatInternal((startLabel as PseudocodeLabel).pseudocode, startLabel, finishLabel, labelCount)
}
private int repeatInternal(
@NotNull PseudocodeImpl originalPseudocode,
@Nullable Label startLabel, @Nullable Label finishLabel,
int labelCount) {
Integer startIndex = startLabel != null ? ((PseudocodeLabel) startLabel).getTargetInstructionIndex() : Integer.valueOf(0);
assert startIndex != null;
Integer finishIndex = finishLabel != null
? ((PseudocodeLabel) finishLabel).getTargetInstructionIndex()
: Integer.valueOf(originalPseudocode.mutableInstructionList.size());
assert finishIndex != null;
private fun repeatInternal(
originalPseudocode: PseudocodeImpl,
startLabel: Label?, finishLabel: Label?,
labelCountArg: Int): Int {
var labelCount = labelCountArg
val startIndex = (if (startLabel != null) (startLabel as PseudocodeLabel).targetInstructionIndex else Integer.valueOf(0))!!
val finishIndex = (if (finishLabel != null)
(finishLabel as PseudocodeLabel).targetInstructionIndex
else
Integer.valueOf(originalPseudocode.mutableInstructionList.size))!!
Map<Label, Label> originalToCopy = Maps.newLinkedHashMap();
Multimap<Instruction, Label> originalLabelsForInstruction = HashMultimap.create();
for (PseudocodeLabel label : originalPseudocode.labels) {
Integer index = label.getTargetInstructionIndex();
if (index == null) continue; //label is not bounded yet
if (label == startLabel || label == finishLabel) continue;
val originalToCopy = Maps.newLinkedHashMap<Label, Label>()
val originalLabelsForInstruction = HashMultimap.create<Instruction, Label>()
for (label in originalPseudocode.labels) {
val index = label.targetInstructionIndex ?: continue
//label is not bounded yet
if (label === startLabel || label === finishLabel) continue
if (startIndex <= index && index <= finishIndex) {
originalToCopy.put(label, label.copy(labelCount++));
originalLabelsForInstruction.put(getJumpTarget(label), label);
originalToCopy.put(label, label.copy(labelCount++))
originalLabelsForInstruction.put(getJumpTarget(label), label)
}
}
for (Label label : originalToCopy.values()) {
labels.add((PseudocodeLabel) label);
for (label in originalToCopy.values) {
labels.add(label as PseudocodeLabel)
}
for (int index = startIndex; index < finishIndex; index++) {
Instruction originalInstruction = originalPseudocode.mutableInstructionList.get(index);
repeatLabelsBindingForInstruction(originalInstruction, originalToCopy, originalLabelsForInstruction);
Instruction copy = copyInstruction(originalInstruction, originalToCopy);
addInstruction(copy);
if (originalInstruction == originalPseudocode.errorInstruction && copy instanceof SubroutineExitInstruction) {
errorInstruction = (SubroutineExitInstruction) copy;
for (index in startIndex..finishIndex - 1) {
val originalInstruction = originalPseudocode.mutableInstructionList[index]
repeatLabelsBindingForInstruction(originalInstruction, originalToCopy, originalLabelsForInstruction)
val copy = copyInstruction(originalInstruction, originalToCopy)
addInstruction(copy)
if (originalInstruction === originalPseudocode.internalErrorInstruction && copy is SubroutineExitInstruction) {
internalErrorInstruction = copy
}
if (originalInstruction == originalPseudocode.exitInstruction && copy instanceof SubroutineExitInstruction) {
exitInstruction = (SubroutineExitInstruction) copy;
if (originalInstruction === originalPseudocode.internalExitInstruction && copy is SubroutineExitInstruction) {
internalExitInstruction = copy
}
if (originalInstruction == originalPseudocode.sinkInstruction && copy instanceof SubroutineSinkInstruction) {
sinkInstruction = (SubroutineSinkInstruction) copy;
if (originalInstruction === originalPseudocode.internalSinkInstruction && copy is SubroutineSinkInstruction) {
internalSinkInstruction = copy
}
}
if (finishIndex < mutableInstructionList.size()) {
repeatLabelsBindingForInstruction(originalPseudocode.mutableInstructionList.get(finishIndex),
if (finishIndex < mutableInstructionList.size) {
repeatLabelsBindingForInstruction(originalPseudocode.mutableInstructionList[finishIndex],
originalToCopy,
originalLabelsForInstruction);
originalLabelsForInstruction)
}
return labelCount;
return labelCount
}
private void repeatLabelsBindingForInstruction(
@NotNull Instruction originalInstruction,
@NotNull Map<Label, Label> originalToCopy,
@NotNull Multimap<Instruction, Label> originalLabelsForInstruction
) {
for (Label originalLabel : originalLabelsForInstruction.get(originalInstruction)) {
bindLabel(originalToCopy.get(originalLabel));
private fun repeatLabelsBindingForInstruction(
originalInstruction: Instruction,
originalToCopy: Map<Label, Label>,
originalLabelsForInstruction: Multimap<Instruction, Label>) {
for (originalLabel in originalLabelsForInstruction.get(originalInstruction)) {
bindLabel(originalToCopy[originalLabel]!!)
}
}
private static Instruction copyInstruction(@NotNull Instruction instruction, @NotNull Map<Label, Label> originalToCopy) {
if (instruction instanceof AbstractJumpInstruction) {
Label originalTarget = ((AbstractJumpInstruction) instruction).getTargetLabel();
private fun copyInstruction(instruction: Instruction, originalToCopy: Map<Label, Label>): Instruction {
if (instruction is AbstractJumpInstruction) {
val originalTarget = instruction.targetLabel
if (originalToCopy.containsKey(originalTarget)) {
return ((AbstractJumpInstruction)instruction).copy(originalToCopy.get(originalTarget));
return instruction.copy(originalToCopy[originalTarget]!!)
}
}
if (instruction instanceof NondeterministicJumpInstruction) {
List<Label> originalTargets = ((NondeterministicJumpInstruction) instruction).getTargetLabels();
List<Label> copyTargets = copyLabels(originalTargets, originalToCopy);
return ((NondeterministicJumpInstruction) instruction).copy(copyTargets);
if (instruction is NondeterministicJumpInstruction) {
val originalTargets = instruction.targetLabels
val copyTargets = copyLabels(originalTargets, originalToCopy)
return instruction.copy(copyTargets)
}
return ((InstructionImpl)instruction).copy();
return (instruction as InstructionImpl).copy()
}
@NotNull
private static List<Label> copyLabels(Collection<Label> labels, Map<Label, Label> originalToCopy) {
List<Label> newLabels = Lists.newArrayList();
for (Label label : labels) {
Label newLabel = originalToCopy.get(label);
newLabels.add(newLabel != null ? newLabel : label);
private fun copyLabels(labels: Collection<Label>, originalToCopy: Map<Label, Label>): MutableList<Label> {
val newLabels = Lists.newArrayList<Label>()
for (label in labels) {
val newLabel = originalToCopy[label]
newLabels.add(newLabel ?: label)
}
return newLabels;
return newLabels
}
}