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