Extract ReadOnly*ControlFlowInfo interfaces from *ControlFlowInfo

It's necessary for further optimizations: not for all cases we actually
need to build a map

The naming is still a subject for discussion
This commit is contained in:
Denis Zharkov
2017-09-20 15:39:49 +03:00
parent 791bfde64b
commit 4b79269cec
4 changed files with 40 additions and 27 deletions
@@ -22,10 +22,10 @@ import org.jetbrains.kotlin.descriptors.VariableDescriptor
typealias ImmutableMap<K, V> = javaslang.collection.Map<K, V> typealias ImmutableMap<K, V> = javaslang.collection.Map<K, V>
typealias ImmutableHashMap<K, V> = javaslang.collection.HashMap<K, V> typealias ImmutableHashMap<K, V> = javaslang.collection.HashMap<K, V>
abstract class ControlFlowInfo<S : ControlFlowInfo<S, D>, D> abstract class ControlFlowInfo<S : ControlFlowInfo<S, D>, D : Any>
internal constructor( internal constructor(
protected val map: ImmutableMap<VariableDescriptor, D> = ImmutableHashMap.empty() protected val map: ImmutableMap<VariableDescriptor, D> = ImmutableHashMap.empty()
) : ImmutableMap<VariableDescriptor, D> by map { ) : ImmutableMap<VariableDescriptor, D> by map, ReadOnlyControlFlowInfo<D> {
abstract protected fun copy(newMap: ImmutableMap<VariableDescriptor, D>): S abstract protected fun copy(newMap: ImmutableMap<VariableDescriptor, D>): S
override fun put(key: VariableDescriptor, value: D): S = put(key, value, this[key].getOrElse(null as D?)) override fun put(key: VariableDescriptor, value: D): S = put(key, value, this[key].getOrElse(null as D?))
@@ -41,6 +41,9 @@ internal constructor(
return copy(map.put(key, value)) return copy(map.put(key, value))
} }
override fun getOrNull(variableDescriptor: VariableDescriptor): D? = this[variableDescriptor].getOrElse(null as D?)
override fun asMap() = this
fun retainAll(predicate: (VariableDescriptor) -> Boolean): S = copy(map.removeAll(map.keySet().filterNot(predicate))) fun retainAll(predicate: (VariableDescriptor) -> Boolean): S = copy(map.removeAll(map.keySet().filterNot(predicate)))
override fun equals(other: Any?) = map == (other as? ControlFlowInfo<*, *>)?.map override fun equals(other: Any?) = map == (other as? ControlFlowInfo<*, *>)?.map
@@ -53,16 +56,26 @@ internal constructor(
operator fun <T> Tuple2<T, *>.component1(): T = _1() operator fun <T> Tuple2<T, *>.component1(): T = _1()
operator fun <T> Tuple2<*, T>.component2(): T = _2() operator fun <T> Tuple2<*, T>.component2(): T = _2()
fun <K, V> ImmutableMap<K, V>.getOrNull(k: K): V? = this[k].getOrElse(null as V?) interface ReadOnlyControlFlowInfo<D : Any> {
fun getOrNull(variableDescriptor: VariableDescriptor): D?
// Only used in tests
fun asMap(): ImmutableMap<VariableDescriptor, D>
}
interface ReadOnlyInitControlFlowInfo : ReadOnlyControlFlowInfo<VariableControlFlowState> {
fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean
}
typealias ReadOnlyUseControlFlowInfo = ReadOnlyControlFlowInfo<VariableUseState>
class InitControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableControlFlowState> = ImmutableHashMap.empty()) : class InitControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableControlFlowState> = ImmutableHashMap.empty()) :
ControlFlowInfo<InitControlFlowInfo, VariableControlFlowState>(map) { ControlFlowInfo<InitControlFlowInfo, VariableControlFlowState>(map), ReadOnlyInitControlFlowInfo {
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableControlFlowState>) = InitControlFlowInfo(newMap) override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableControlFlowState>) = InitControlFlowInfo(newMap)
// this = output of EXHAUSTIVE_WHEN_ELSE instruction // this = output of EXHAUSTIVE_WHEN_ELSE instruction
// merge = input of MergeInstruction // merge = input of MergeInstruction
// returns true if definite initialization in when happens here // returns true if definite initialization in when happens here
fun checkDefiniteInitializationInWhen(merge: InitControlFlowInfo): Boolean { override fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean {
for ((key, value) in iterator()) { for ((key, value) in iterator()) {
if (value.initState == InitState.INITIALIZED_EXHAUSTIVELY && if (value.initState == InitState.INITIALIZED_EXHAUSTIVELY &&
merge.getOrNull(key)?.initState == InitState.INITIALIZED) { merge.getOrNull(key)?.initState == InitState.INITIALIZED) {
@@ -74,7 +87,7 @@ class InitControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableControlF
} }
class UseControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableUseState> = ImmutableHashMap.empty()) : class UseControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableUseState> = ImmutableHashMap.empty()) :
ControlFlowInfo<UseControlFlowInfo, VariableUseState>(map) { ControlFlowInfo<UseControlFlowInfo, VariableUseState>(map), ReadOnlyUseControlFlowInfo {
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableUseState>) = UseControlFlowInfo(newMap) override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableUseState>) = UseControlFlowInfo(newMap)
} }
@@ -274,8 +274,8 @@ class ControlFlowInformationProvider private constructor(
pseudocode.traverse(TraversalOrder.FORWARD, initializers) { pseudocode.traverse(TraversalOrder.FORWARD, initializers) {
instruction: Instruction, instruction: Instruction,
enterData: ImmutableMap<VariableDescriptor, VariableControlFlowState>, enterData: ReadOnlyInitControlFlowInfo,
exitData: ImmutableMap<VariableDescriptor, VariableControlFlowState> -> exitData: ReadOnlyInitControlFlowInfo ->
val ctxt = VariableInitContext(instruction, reportedDiagnosticMap, enterData, exitData, blockScopeVariableInfo) val ctxt = VariableInitContext(instruction, reportedDiagnosticMap, enterData, exitData, blockScopeVariableInfo)
if (ctxt.variableDescriptor == null) return@traverse if (ctxt.variableDescriptor == null) return@traverse
@@ -532,7 +532,7 @@ class ControlFlowInformationProvider private constructor(
private fun recordInitializedVariables( private fun recordInitializedVariables(
pseudocode: Pseudocode, pseudocode: Pseudocode,
initializersMap: Map<Instruction, Edges<InitControlFlowInfo>> initializersMap: Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>>
) { ) {
val initializers = initializersMap[pseudocode.exitInstruction] ?: return val initializers = initializersMap[pseudocode.exitInstruction] ?: return
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false) val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false)
@@ -554,8 +554,8 @@ class ControlFlowInformationProvider private constructor(
val usedValueExpressions = hashSetOf<KtExpression>() val usedValueExpressions = hashSetOf<KtExpression>()
pseudocode.traverse(TraversalOrder.BACKWARD, variableStatusData) { pseudocode.traverse(TraversalOrder.BACKWARD, variableStatusData) {
instruction: Instruction, instruction: Instruction,
enterData: ImmutableMap<VariableDescriptor, VariableUseState>, enterData: ReadOnlyUseControlFlowInfo,
_: ImmutableMap<VariableDescriptor, VariableUseState> -> _: ReadOnlyUseControlFlowInfo ->
val ctxt = VariableUseContext(instruction, reportedDiagnosticMap) val ctxt = VariableUseContext(instruction, reportedDiagnosticMap)
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.owner, false) val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.owner, false)
@@ -1030,8 +1030,8 @@ class ControlFlowInformationProvider private constructor(
private inner class VariableInitContext( private inner class VariableInitContext(
instruction: Instruction, instruction: Instruction,
map: MutableMap<Instruction, DiagnosticFactory<*>>, map: MutableMap<Instruction, DiagnosticFactory<*>>,
`in`: ImmutableMap<VariableDescriptor, VariableControlFlowState>, `in`: ReadOnlyInitControlFlowInfo,
out: ImmutableMap<VariableDescriptor, VariableControlFlowState>, out: ReadOnlyInitControlFlowInfo,
blockScopeVariableInfo: BlockScopeVariableInfo blockScopeVariableInfo: BlockScopeVariableInfo
) : VariableContext(instruction, map) { ) : VariableContext(instruction, map) {
internal val enterInitState = initialize(variableDescriptor, blockScopeVariableInfo, `in`) internal val enterInitState = initialize(variableDescriptor, blockScopeVariableInfo, `in`)
@@ -1040,7 +1040,7 @@ class ControlFlowInformationProvider private constructor(
private fun initialize( private fun initialize(
variableDescriptor: VariableDescriptor?, variableDescriptor: VariableDescriptor?,
blockScopeVariableInfo: BlockScopeVariableInfo, blockScopeVariableInfo: BlockScopeVariableInfo,
map: ImmutableMap<VariableDescriptor, VariableControlFlowState> map: ReadOnlyInitControlFlowInfo
): VariableControlFlowState? { ): VariableControlFlowState? {
val state = map.getOrNull(variableDescriptor ?: return null) val state = map.getOrNull(variableDescriptor ?: return null)
if (state != null) return state if (state != null) return state
@@ -37,7 +37,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
private val declaredVariablesForDeclaration = hashMapOf<Pseudocode, Set<VariableDescriptor>>() private val declaredVariablesForDeclaration = hashMapOf<Pseudocode, Set<VariableDescriptor>>()
val variableInitializers: Map<Instruction, Edges<InitControlFlowInfo>> by lazy { val variableInitializers: Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>> by lazy {
computeVariableInitializers() computeVariableInitializers()
} }
@@ -143,7 +143,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
// variable use // variable use
val variableUseStatusData: Map<Instruction, Edges<UseControlFlowInfo>> val variableUseStatusData: Map<Instruction, Edges<ReadOnlyUseControlFlowInfo>>
get() = pseudocodeVariableDataCollector.collectData(TraversalOrder.BACKWARD, UseControlFlowInfo()) { get() = pseudocodeVariableDataCollector.collectData(TraversalOrder.BACKWARD, UseControlFlowInfo()) {
instruction: Instruction, incomingEdgesData: Collection<UseControlFlowInfo> -> instruction: Instruction, incomingEdgesData: Collection<UseControlFlowInfo> ->
@@ -39,9 +39,9 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
@NotNull BindingContext bindingContext @NotNull BindingContext bindingContext
) { ) {
PseudocodeVariablesData pseudocodeVariablesData = new PseudocodeVariablesData(pseudocode.getRootPseudocode(), bindingContext); PseudocodeVariablesData pseudocodeVariablesData = new PseudocodeVariablesData(pseudocode.getRootPseudocode(), bindingContext);
Map<Instruction, Edges<InitControlFlowInfo>> variableInitializers = Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>> variableInitializers =
pseudocodeVariablesData.getVariableInitializers(); pseudocodeVariablesData.getVariableInitializers();
Map<Instruction, Edges<UseControlFlowInfo>> useStatusData = Map<Instruction, Edges<ReadOnlyControlFlowInfo<VariableUseState>>> useStatusData =
pseudocodeVariablesData.getVariableUseStatusData(); pseudocodeVariablesData.getVariableUseStatusData();
String initPrefix = " INIT:"; String initPrefix = " INIT:";
String usePrefix = " USE:"; String usePrefix = " USE:";
@@ -49,16 +49,16 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
dumpInstructions(pseudocode, out, (instruction, next, prev) -> { dumpInstructions(pseudocode, out, (instruction, next, prev) -> {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
Edges<InitControlFlowInfo> initializersEdges = variableInitializers.get(instruction); Edges<ReadOnlyInitControlFlowInfo> initializersEdges = variableInitializers.get(instruction);
Edges<InitControlFlowInfo> previousInitializersEdges = variableInitializers.get(prev); Edges<ReadOnlyInitControlFlowInfo> previousInitializersEdges = variableInitializers.get(prev);
String initializersData = ""; String initializersData = "";
if (initializersEdges != null && !initializersEdges.equals(previousInitializersEdges)) { if (initializersEdges != null && !initializersEdges.equals(previousInitializersEdges)) {
initializersData = dumpEdgesData(initPrefix, initializersEdges); initializersData = dumpEdgesData(initPrefix, initializersEdges);
} }
result.append(String.format("%1$-" + initializersColumnWidth + "s", initializersData)); result.append(String.format("%1$-" + initializersColumnWidth + "s", initializersData));
Edges<UseControlFlowInfo> useStatusEdges = useStatusData.get(instruction); Edges<ReadOnlyControlFlowInfo<VariableUseState>> useStatusEdges = useStatusData.get(instruction);
Edges<UseControlFlowInfo> nextUseStatusEdges = useStatusData.get(next); Edges<ReadOnlyControlFlowInfo<VariableUseState>> nextUseStatusEdges = useStatusData.get(next);
if (useStatusEdges != null && !useStatusEdges.equals(nextUseStatusEdges)) { if (useStatusEdges != null && !useStatusEdges.equals(nextUseStatusEdges)) {
result.append(dumpEdgesData(usePrefix, useStatusEdges)); result.append(dumpEdgesData(usePrefix, useStatusEdges));
} }
@@ -69,11 +69,11 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
private static int countDataColumnWidth( private static int countDataColumnWidth(
@NotNull String prefix, @NotNull String prefix,
@NotNull List<Instruction> instructions, @NotNull List<Instruction> instructions,
@NotNull Map<Instruction, Edges<InitControlFlowInfo>> data @NotNull Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>> data
) { ) {
int maxWidth = 0; int maxWidth = 0;
for (Instruction instruction : instructions) { for (Instruction instruction : instructions) {
Edges<InitControlFlowInfo> edges = data.get(instruction); Edges<ReadOnlyInitControlFlowInfo> edges = data.get(instruction);
if (edges == null) continue; if (edges == null) continue;
int length = dumpEdgesData(prefix, edges).length(); int length = dumpEdgesData(prefix, edges).length();
if (maxWidth < length) { if (maxWidth < length) {
@@ -85,10 +85,10 @@ public abstract class AbstractDataFlowTest extends AbstractPseudocodeTest {
} }
@NotNull @NotNull
private static <S, I extends ControlFlowInfo<?, S>> String dumpEdgesData(String prefix, @NotNull Edges<I> edges) { private static <S, I extends ReadOnlyControlFlowInfo<S>> String dumpEdgesData(String prefix, @NotNull Edges<I> edges) {
return prefix + return prefix +
" in: " + renderVariableMap(edges.getIncoming()) + " in: " + renderVariableMap(edges.getIncoming().asMap()) +
" out: " + renderVariableMap(edges.getOutgoing()); " out: " + renderVariableMap(edges.getOutgoing().asMap());
} }
private static <S> String renderVariableMap(javaslang.collection.Map<VariableDescriptor, S> map) { private static <S> String renderVariableMap(javaslang.collection.Map<VariableDescriptor, S> map) {