From 1ddaf465cdd6b8b87f914ed4da178d109b5815ac Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 26 Jan 2016 13:00:17 +0300 Subject: [PATCH] PseudocodeImpl: converted to Kotlin --- .../kotlin/cfg/pseudocode/PseudocodeImpl.kt | 760 ++++++++---------- 1 file changed, 327 insertions(+), 433 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeImpl.kt index ade52174200..1c3cc009daa 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeImpl.kt @@ -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 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 mutableInstructionList = new ArrayList(); - private final List instructions = new ArrayList(); + private val mutableInstructionList = ArrayList() + override val instructions = ArrayList() - private final BidirectionalMap elementsToValues = new BidirectionalMap(); + private val elementsToValues = BidirectionalMap() - private final Map> valueUsages = Maps.newHashMap(); - private final Map> mergedValues = Maps.newHashMap(); - private final Set sideEffectFree = Sets.newHashSet(); + private val valueUsages = Maps.newHashMap>() + private val mergedValues = Maps.newHashMap>() + private val sideEffectFree = Sets.newHashSet() - private Pseudocode parent = null; - private Set localDeclarations = null; + override var parent: Pseudocode? = null + private set + + override val localDeclarations: Set by lazy { + getLocalDeclarations(this) + } //todo getters - private final Map representativeInstructions = new HashMap(); + private val representativeInstructions = HashMap() - private final List labels = new ArrayList(); + private val labels = ArrayList() - 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 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 getLocalDeclarations(@NotNull Pseudocode pseudocode) { - Set 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 { + val localDeclarations = Sets.newLinkedHashSet() + 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 getInstructions() { - return instructions; - } - - @NotNull - @Override - public List getReversedInstructions() { - LinkedHashSet traversedInstructions = Sets.newLinkedHashSet(); - PseudocodeTraverserKt.traverseFollowingInstructions(sinkInstruction, traversedInstructions, BACKWARD, null); - if (traversedInstructions.size() < instructions.size()) { - List 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 getInstructionsIncludingDeadCode() { - return mutableInstructionList; - } - - //for tests only - @NotNull - public List 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 getValueElements(@Nullable PseudoValue value) { - List result = elementsToValues.getKeysByValue(value); - return result != null ? result : Collections.emptyList(); - } - - @NotNull - @Override - public List getUsages(@Nullable PseudoValue value) { - List result = valueUsages.get(value); - return result != null ? result : Collections.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 getMergedValues(@NotNull PseudoValue value) { - Set result = mergedValues.get(value); - return result != null ? result : Collections.emptySet(); - } - - private void addMergedValues(@NotNull MergeInstruction instruction) { - Set result = new LinkedHashSet(); - 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>() { - @Override - public List invoke() { - return Lists.newArrayList(); + override val reversedInstructions: List + get() { + val traversedInstructions = Sets.newLinkedHashSet() + 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 + get() = mutableInstructionList + + //for tests only + fun getLabels(): List { + 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() + 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() }.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 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