diff --git a/usvm-core/src/main/kotlin/org/usvm/Machine.kt b/usvm-core/src/main/kotlin/org/usvm/Machine.kt index c82b679ed..c94db7a7f 100644 --- a/usvm-core/src/main/kotlin/org/usvm/Machine.kt +++ b/usvm-core/src/main/kotlin/org/usvm/Machine.kt @@ -3,7 +3,6 @@ package org.usvm import mu.KLogging import org.usvm.statistics.UMachineObserver import org.usvm.stopstrategies.StopStrategy -import org.usvm.stopstrategies.stopReason import org.usvm.util.bracket import org.usvm.util.debug @@ -67,7 +66,7 @@ abstract class UMachine : AutoCloseable { } if (!pathSelector.isEmpty()) { - logger.debug { stopReason(stopStrategy) } + logger.debug { stopStrategy.stopReason() } } } } diff --git a/usvm-core/src/main/kotlin/org/usvm/ps/ExceptionPropagationPathSelector.kt b/usvm-core/src/main/kotlin/org/usvm/ps/ExceptionPropagationPathSelector.kt index 076d5833f..305d90961 100644 --- a/usvm-core/src/main/kotlin/org/usvm/ps/ExceptionPropagationPathSelector.kt +++ b/usvm-core/src/main/kotlin/org/usvm/ps/ExceptionPropagationPathSelector.kt @@ -2,6 +2,7 @@ package org.usvm.ps import org.usvm.UPathSelector import org.usvm.UState +import java.util.IdentityHashMap /** * A class designed to give the highest priority to the states containing exceptions. @@ -9,18 +10,18 @@ import org.usvm.UState class ExceptionPropagationPathSelector>( private val selector: UPathSelector, ) : UPathSelector { - // An internal queue for states containing exceptions - private val exceptionalStates: MutableList = mutableListOf() - - // A set containing hash codes of the identities of the states - // containing in the `exceptionalStates`. It is required - // to be able to determine whether a particular state is in the queue. - private val exceptionalStatesHashCodes: MutableSet = mutableSetOf() - - // A set of hash codes of the states that were added in the internal selector. + // An internal queue for states containing exceptions. + // Note that we use an identity map here to be able + // to determine whether some state is already in the queue or not + // without extra time consumption. + // We use only keys from this map. + private val exceptionalStates = IdentityHashMap() + + // An identity map of the states that were added in the internal selector. // That means that these states present not only in the internal queue, but in // the queue of the selector, and we have to process them as well. - private val statesInSelectorHashCodes: MutableSet = mutableSetOf() + // We use only keys from this map. + private val statesInSelector = IdentityHashMap() override fun isEmpty(): Boolean = exceptionalStates.isEmpty() && selector.isEmpty() @@ -28,11 +29,10 @@ class ExceptionPropagationPathSelector>( * Returns an exceptional state from the internal queue if it is not empty, or * the result of [peek] method called on the wrapper selector. */ - override fun peek(): State = exceptionalStates.lastOrNull() ?: selector.peek() + override fun peek(): State = exceptionalStates.keys.lastOrNull() ?: selector.peek() override fun update(state: State) { - val stateHashCode = System.identityHashCode(state) - val alreadyInExceptionalStates = stateHashCode in exceptionalStatesHashCodes + val alreadyInExceptionalStates = state in exceptionalStates val isExceptional = state.isExceptional when { @@ -40,8 +40,7 @@ class ExceptionPropagationPathSelector>( // previous step it didn't contain any exceptions. // We add this exceptional state to the internal queue. isExceptional && !alreadyInExceptionalStates -> { - exceptionalStatesHashCodes += stateHashCode - exceptionalStates += state + exceptionalStates += state to null } // A case when the state contained an exception at the previous step, // but it doesn't contain it anymore. There are two possibilities: @@ -51,12 +50,11 @@ class ExceptionPropagationPathSelector>( // exceptional queue, in the second one just removal is enough since // it was added in the selector earlier. !isExceptional && alreadyInExceptionalStates -> { - exceptionalStatesHashCodes -= stateHashCode exceptionalStates -= state - if (stateHashCode !in statesInSelectorHashCodes) { + if (state !in statesInSelector) { selector.add(listOf(state)) - statesInSelectorHashCodes += stateHashCode + statesInSelector += state to null } } @@ -65,7 +63,7 @@ class ExceptionPropagationPathSelector>( } // If the state is contained in the selector, we must call `update` operation for it. - if (stateHashCode in statesInSelectorHashCodes) { + if (state in statesInSelector) { selector.update(state) } } @@ -79,18 +77,15 @@ class ExceptionPropagationPathSelector>( val statesToAdd = mutableListOf() states.forEach { - val identityHashCode = System.identityHashCode(it) - // It if it is an exceptional state, we don't have to worry whether it // is contains in the selector or not. It was either already added in it, // or will be added later if required, when it becomes unexceptional one. if (it.isExceptional) { - exceptionalStates += it - exceptionalStatesHashCodes += identityHashCode + exceptionalStates += it to null } else { // Otherwise, we simply add it to the selector directly. statesToAdd += it - statesInSelectorHashCodes += identityHashCode + statesInSelector += it to null } } @@ -98,16 +93,12 @@ class ExceptionPropagationPathSelector>( } override fun remove(state: State) { - val stateHashCode = System.identityHashCode(state) - - if (stateHashCode in exceptionalStatesHashCodes) { + if (state in exceptionalStates) { exceptionalStates -= state - exceptionalStatesHashCodes -= stateHashCode } - if (stateHashCode in statesInSelectorHashCodes) { + if (state in statesInSelector) { selector.remove(state) - statesInSelectorHashCodes.remove(stateHashCode) } } -} \ No newline at end of file +} diff --git a/usvm-core/src/main/kotlin/org/usvm/statistics/CoverageStatistics.kt b/usvm-core/src/main/kotlin/org/usvm/statistics/CoverageStatistics.kt index 2d4d0c448..402b1afd0 100644 --- a/usvm-core/src/main/kotlin/org/usvm/statistics/CoverageStatistics.kt +++ b/usvm-core/src/main/kotlin/org/usvm/statistics/CoverageStatistics.kt @@ -39,7 +39,7 @@ class CoverageStatistics Int)?, + private val collectedStateCount: () -> Int, ) : StopStrategy { - private val collectedStateCount: () -> Int - - init { - collectedStateCount = requireNotNull(getCollectedStatesCount) { - "You must specify a provider of the number of collected states to be able to use this stop strategy" - } - } - private var counter = 0UL private var lastStatesCounter = collectedStateCount() diff --git a/usvm-core/src/main/kotlin/org/usvm/stopstrategies/StopStrategy.kt b/usvm-core/src/main/kotlin/org/usvm/stopstrategies/StopStrategy.kt index 23b78a026..43626088f 100644 --- a/usvm-core/src/main/kotlin/org/usvm/stopstrategies/StopStrategy.kt +++ b/usvm-core/src/main/kotlin/org/usvm/stopstrategies/StopStrategy.kt @@ -9,6 +9,8 @@ fun interface StopStrategy { * If true, symbolic execution process is terminated. */ fun shouldStop(): Boolean + + fun stopReason(): String = "Stop reason: ${this::class.simpleName ?: this}" } class GroupedStopStrategy( @@ -18,14 +20,7 @@ class GroupedStopStrategy( override fun shouldStop() = strategies.any { it.shouldStop() } - fun stopReason(): String = strategies + override fun stopReason(): String = strategies .filter { it.shouldStop() } .joinToString(prefix = "Stop reasons: ", separator = ", ") { "${it::class.simpleName ?: it}" } } - -fun stopReason(stopStrategy: StopStrategy): String = - if (stopStrategy is GroupedStopStrategy) { - stopStrategy.stopReason() - } else { - "Stop reason: ${stopStrategy::class.simpleName ?: stopStrategy}" - } diff --git a/usvm-core/src/main/kotlin/org/usvm/stopstrategies/StopStrategyFactory.kt b/usvm-core/src/main/kotlin/org/usvm/stopstrategies/StopStrategyFactory.kt index 8e5c7166f..f1e78d344 100644 --- a/usvm-core/src/main/kotlin/org/usvm/stopstrategies/StopStrategyFactory.kt +++ b/usvm-core/src/main/kotlin/org/usvm/stopstrategies/StopStrategyFactory.kt @@ -35,7 +35,7 @@ fun createStopStrategy( } val stepsFromLastCovered = options.stepsFromLastCovered - if (stepsFromLastCovered != null) { + if (stepsFromLastCovered != null && getCollectedStatesCount != null) { val stepsFromLastCoveredStopStrategy = StepsFromLastCoveredStopStrategy( stepsFromLastCovered.toULong(), getCollectedStatesCount