PseudocodeImpl: converted to Kotlin
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user