diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/ManagedStrategy.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/ManagedStrategy.kt index 24c6af5e5..2937ceb60 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/ManagedStrategy.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/ManagedStrategy.kt @@ -221,7 +221,6 @@ abstract class ManagedStrategy( } override fun restoreStaticMemorySnapshot() { - // TODO: what is the appropriate location to call this function? if (testCfg.restoreStaticMemory) { staticMemorySnapshot.restoreValues() super.restoreStaticMemorySnapshot() @@ -943,8 +942,7 @@ abstract class ManagedStrategy( */ override fun updateSnapshotOnFieldAccess(obj: Any?, className: String, fieldName: String, codeLocation: Int) = runInIgnoredSection { if (testCfg.restoreStaticMemory) { - val location = CodeLocations.stackTrace(codeLocation).toString() - staticMemorySnapshot.trackField(obj, className, fieldName, location) + staticMemorySnapshot.trackField(obj, className, fieldName) } } @@ -953,8 +951,7 @@ abstract class ManagedStrategy( */ override fun updateSnapshotOnArrayElementAccess(array: Any, index: Int, codeLocation: Int) = runInIgnoredSection { if (testCfg.restoreStaticMemory) { - val location = CodeLocations.stackTrace(codeLocation).toString() - staticMemorySnapshot.trackArrayCell(array, index, location) + staticMemorySnapshot.trackArrayCell(array, index) } } diff --git a/src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/SnapshotTracker.kt b/src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/SnapshotTracker.kt index 508bb5813..0e9cfc7ce 100644 --- a/src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/SnapshotTracker.kt +++ b/src/jvm/main/org/jetbrains/kotlinx/lincheck/strategy/managed/SnapshotTracker.kt @@ -54,60 +54,8 @@ class SnapshotTracker { class ArrayCellNode(descriptor: ArrayCellDescriptor, initialValue: Any?) : MemoryNode(descriptor, initialValue) } - fun size(): Int = (trackedObjects.keys.filter { it !is Class<*> } + trackedObjects.values.flatMap { it }.mapNotNull { it.initialValue }).toSet().size - -// fun printRoots() { -// val rootSizes = mutableMapOf() -// val mappedFromRoots = mutableMapOf>() -// trackedObjects.keys.filterIsInstance>().forEach { root -> -// var size = 0 -// val countedObjs = mutableSetOf() -// mappedFromRoots[root] = mutableListOf() -// -// trackedObjects[root]!!.forEach nodesTraverse@{ node -> -// if (node.initialValue == null) return@nodesTraverse -// -// mappedFromRoots[root]!!.add(node.initialValue) -// size++ -// -// traverseObjectGraph( -// node.initialValue, -// onArrayElement = { _, _, value -> -// if (value in trackedObjects && value !in countedObjs) { -// countedObjs.add(value!!) -// mappedFromRoots[root]!!.add(value) -// size++ -// } -// value -// }, -// onField = { _, _, value -> -// if (value in trackedObjects && value !in countedObjs) { -// countedObjs.add(value!!) -// mappedFromRoots[root]!!.add(value) -// size++ -// } -// value -// } -// ) -// } -// -// rootSizes[root] = size -// } -// -// val sizesSorted = rootSizes.entries -// .sortedBy { -it.value } // Sort by values -// .associate { it.key to it.value } // Convert back to a map -// mappedFromRoots.entries -// .sortedBy { -it.value.size } -// .toList() -// -//// println("Snapshot roots (${sizesSorted.size}): $sizesSorted") -// } - @OptIn(ExperimentalStdlibApi::class) - fun trackField(obj: Any?, className: String, fieldName: String, @Suppress("UNUSED_PARAMETER") location: String = "") { - //println("Consider ($location): obj=${obj?.javaClass?.simpleName}${if (obj != null) "@" + System.identityHashCode(obj).toHexString() else ""}, className=$className, fieldName=$fieldName") - + fun trackField(obj: Any?, className: String, fieldName: String) { if (obj != null && obj !in trackedObjects) return val clazz: Class<*> = Class.forName(className).let { @@ -119,8 +67,6 @@ class SnapshotTracker { if (readResult.isSuccess) { val fieldValue = readResult.getOrNull() - //println("Consider: value=${fieldValue}") - trackSingleField(obj, clazz, field, fieldValue) { if (shouldTrackEnergetically(fieldValue)) { trackHierarchy(fieldValue!!) @@ -130,16 +76,13 @@ class SnapshotTracker { } @OptIn(ExperimentalStdlibApi::class) - fun trackArrayCell(array: Any, index: Int, @Suppress("UNUSED_PARAMETER") location: String) { - //println("Consider ($location): array=${array.javaClass.simpleName}@${System.identityHashCode(array).toHexString()}, index=$index") + fun trackArrayCell(array: Any, index: Int) { if (array !in trackedObjects) return val readResult = runCatching { readArrayElementViaUnsafe(array, index) } if (readResult.isSuccess) { val elementValue = readResult.getOrNull() - //println("Consider: element=${elementValue}") - trackSingleArrayCell(array, index, elementValue) { if (shouldTrackEnergetically(elementValue)) { trackHierarchy(elementValue!!) @@ -206,7 +149,6 @@ class SnapshotTracker { } fun restoreValues() { - //println("====== START RESTORING ======") val visitedObjects = Collections.newSetFromMap(IdentityHashMap()) trackedObjects.keys .filterIsInstance>() @@ -233,7 +175,6 @@ class SnapshotTracker { .any { it.field.name == field.name } // field is already tracked ) return - //println("SNAPSHOT: obj=${if (obj == null) "null" else obj.javaClass.simpleName + "@" + System.identityHashCode(obj).toHexString()}, className=${clazz.name}, fieldName=${field.name}, value=${fieldValue}") val childNode = createMemoryNode( obj, FieldDescriptor(field, getFieldOffset(field)), @@ -256,7 +197,6 @@ class SnapshotTracker { nodesList.any { it is ArrayCellNode && (it.descriptor as ArrayCellDescriptor).index == index } // this array cell is already tracked ) return - //println("SNAPSHOT: array=${array.javaClass.simpleName}@${System.identityHashCode(array).toHexString()}, index=$index, value=${elementValue}") val childNode = createMemoryNode(array, ArrayCellDescriptor(index), elementValue) nodesList.add(childNode) @@ -268,7 +208,6 @@ class SnapshotTracker { @OptIn(ExperimentalStdlibApi::class) private fun trackHierarchy(obj: Any) { - //println("Track hierarchy for object: ${obj.javaClass.simpleName}@${System.identityHashCode(obj).toHexString()}") traverseObjectGraph( obj, onArrayElement = { array, index, elementValue -> @@ -291,6 +230,7 @@ class SnapshotTracker { return ( // TODO: in further development of snapshot restoring feature this check should be removed // (and only check for java atomic classes inserted), see https://github.com/JetBrains/lincheck/pull/418#issue-2595977113 + // right it is need for collections to be restored properly (because of missing support for `System.arrayCopy()` and other similar methods) obj.javaClass.name.startsWith("java.util.") ) } @@ -298,14 +238,12 @@ class SnapshotTracker { @OptIn(ExperimentalStdlibApi::class) private fun restoreValues(obj: Any, visitedObjects: MutableSet) { if (obj in visitedObjects) return - //println("RESTORE: obj=${if (obj is Class<*>) obj.simpleName else obj.javaClass.simpleName}@${System.identityHashCode(obj).toHexString()}:") visitedObjects.add(obj) trackedObjects[obj]!! .forEach { node -> if (node is ArrayCellNode) { val index = (node.descriptor as ArrayCellDescriptor).index - //println("\tRESTORE: arr=${obj.javaClass.simpleName}@${System.identityHashCode(obj).toHexString()}, index=$index, value=${node.initialValue}") when (obj) { // No need to add support for writing to atomicfu array elements, @@ -317,7 +255,6 @@ class SnapshotTracker { } } else if (!Modifier.isFinal((node.descriptor as FieldDescriptor).field.modifiers)) { - //println("\tRESTORE: obj=${if (obj is Class<*>) obj.simpleName else obj.javaClass.simpleName}@${System.identityHashCode(obj).toHexString()}, field=${node.descriptor.field.name}, value=${node.initialValue}") writeField( if (node is StaticFieldNode) null else obj, node.descriptor.field,