Skip to content

Commit f653554

Browse files
Add ID for serialized objects
1 parent dcc9d91 commit f653554

File tree

3 files changed

+59
-17
lines changed

3 files changed

+59
-17
lines changed

jupyter-lib/shared-compiler/src/main/kotlin/org/jetbrains/kotlinx/jupyter/compiler/util/serializedCompiledScript.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ data class SerializedCompiledScriptsData(
2424
data class SerializedVariablesState(
2525
val type: String = "",
2626
val value: String? = null,
27-
val isContainer: Boolean = false
27+
val isContainer: Boolean = false,
28+
val ID: String = ""
2829
) {
2930
// todo: not null
3031
val fieldDescriptor: MutableMap<String, SerializedVariablesState?> = mutableMapOf()

src/main/kotlin/org/jetbrains/kotlinx/jupyter/serializationUtils.kt

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ data class RuntimeObjectWrapper(
6363
val objectInstance: Any?,
6464
val isRecursive: Boolean = false
6565
) {
66+
val computerID: String = Integer.toHexString(hashCode())
67+
6668
override fun equals(other: Any?): Boolean {
6769
if (other == null) return objectInstance == null
6870
if (objectInstance == null) return false
@@ -71,13 +73,12 @@ data class RuntimeObjectWrapper(
7173
}
7274

7375
override fun hashCode(): Int {
74-
return if (isRecursive) Random.hashCode() else objectInstance?.hashCode() ?: 0
76+
return if (isRecursive) Random.nextInt() else objectInstance?.hashCode() ?: 0
7577
}
7678
}
7779

7880
fun Any?.toObjectWrapper(isRecursive: Boolean = false): RuntimeObjectWrapper = RuntimeObjectWrapper(this, isRecursive)
7981

80-
8182
fun Any?.getToStringValue(isRecursive: Boolean = false): String {
8283
return if (isRecursive) {
8384
"${this!!::class.simpleName}: recursive structure"
@@ -90,6 +91,24 @@ fun Any?.getToStringValue(isRecursive: Boolean = false): String {
9091
}
9192
}
9293

94+
fun Any?.getUniqueID(isRecursive: Boolean = false): String {
95+
return if (this != null) {
96+
val hashCode = if (isRecursive) {
97+
Random.nextLong()
98+
} else {
99+
// ignore standard numerics
100+
if (this !is Number && this::class.simpleName != "int") {
101+
this.hashCode()
102+
} else {
103+
Random.nextLong()
104+
}
105+
}
106+
Integer.toHexString(hashCode.toInt())
107+
} else {
108+
""
109+
}
110+
}
111+
93112
/**
94113
* Provides contract for using threshold-based removal heuristic.
95114
* Every serialization-related info in [T] would be removed once [isShouldRemove] == true.
@@ -162,7 +181,13 @@ class VariablesSerializer(
162181
null
163182
}
164183
} catch (ex: Exception) { null }
165-
val serializedVersion = SerializedVariablesState(simpleTypeName, getProperString(value), true)
184+
val stringedValue = getProperString(value)
185+
val varID = if (value !is String) {
186+
value.getUniqueID(stringedValue.contains(": recursive structure"))
187+
} else {
188+
""
189+
}
190+
val serializedVersion = SerializedVariablesState(simpleTypeName, stringedValue, true, varID)
166191
val descriptors = serializedVersion.fieldDescriptor
167192

168193
// only for set case
@@ -180,6 +205,9 @@ class VariablesSerializer(
180205
if (isDescriptorsNeeded) {
181206
kProperties?.forEach { prop ->
182207
val name = prop.name
208+
if (name == "null") {
209+
return@forEach
210+
}
183211
val propValue = value?.let {
184212
try {
185213
prop as KProperty1<Any, *>
@@ -188,7 +216,13 @@ class VariablesSerializer(
188216
if (prop.name == "size") {
189217
if (isArray(value)) {
190218
value as Array<*>
191-
value.size
219+
// there might be size 10, but only one actual recursive value
220+
val runTimeSize = value.size
221+
if (runTimeSize > 5 && value[0] is List<*> && value[1] == null && value [2] == null) {
222+
1
223+
} else {
224+
runTimeSize
225+
}
192226
} else {
193227
value as Collection<*>
194228
value.size
@@ -405,17 +439,19 @@ class VariablesSerializer(
405439
if (!isSerializationActive || variableState == null || name == null) return SerializedVariablesState()
406440
// force recursive check
407441
variableState.stringValue
408-
return serializeVariableState(cellId, name, variableState.property, variableState.value.getOrNull(), variableState.isRecursive, isOverride)
442+
return serializeVariableState(cellId, name, variableState.property, variableState.value.getOrNull(), variableState.isRecursive, isOverride)
409443
}
410444

411445
private fun serializeVariableState(cellId: Int, name: String, property: Field?, value: Any?, isRecursive: Boolean, isOverride: Boolean = true): SerializedVariablesState {
412-
val processedData = createSerializeVariableState(name, getSimpleTypeNameFrom(property, value), value)
413-
return doActualSerialization(cellId, processedData, value.toObjectWrapper(isRecursive), isRecursive, isOverride)
446+
val wrapper = value.toObjectWrapper(isRecursive)
447+
val processedData = createSerializeVariableState(name, getSimpleTypeNameFrom(property, value), wrapper)
448+
return doActualSerialization(cellId, processedData, wrapper, isRecursive, isOverride)
414449
}
415450

416451
private fun serializeVariableState(cellId: Int, name: String, property: KProperty<*>, value: Any?, isRecursive: Boolean, isOverride: Boolean = true): SerializedVariablesState {
417-
val processedData = createSerializeVariableState(name, getSimpleTypeNameFrom(property, value), value)
418-
return doActualSerialization(cellId, processedData, value.toObjectWrapper(isRecursive), isRecursive, isOverride)
452+
val wrapper = value.toObjectWrapper(isRecursive)
453+
val processedData = createSerializeVariableState(name, getSimpleTypeNameFrom(property, value), wrapper)
454+
return doActualSerialization(cellId, processedData, wrapper, isRecursive, isOverride)
419455
}
420456

421457
private fun doActualSerialization(cellId: Int, processedData: ProcessedSerializedVarsState, value: RuntimeObjectWrapper, isRecursive: Boolean, isOverride: Boolean = true): SerializedVariablesState {
@@ -447,7 +483,7 @@ class VariablesSerializer(
447483
val type = processedData.propertiesType
448484
if (type == PropertiesType.KOTLIN) {
449485
val kProperties = currentCellDescriptors.processedSerializedVarsToKTProperties[serializedVersion]
450-
if (kProperties?.size == 1 && kProperties.first().name == "size" ) {
486+
if (kProperties?.size == 1 && kProperties.first().name == "size") {
451487
serializedVersion.fieldDescriptor.addDescriptor(value.objectInstance, "data")
452488
}
453489
iterateThroughContainerMembers(cellId, value.objectInstance, serializedVersion.fieldDescriptor, isRecursive = isRecursive, kProperties = currentCellDescriptors.processedSerializedVarsToKTProperties[serializedVersion])
@@ -626,7 +662,6 @@ class VariablesSerializer(
626662
// descriptor.putAll(descriptorsState?.fieldDescriptor ?: emptyMap())
627663
// }
628664

629-
630665
if (seenObjectsPerCell?.containsKey(value) == false) {
631666
if (descriptor[name] != null) {
632667
seenObjectsPerCell[value] = descriptor[name]!!
@@ -642,7 +677,7 @@ class VariablesSerializer(
642677
if (value != null) {
643678
value::class.simpleName
644679
} else {
645-
value?.getToStringValue()
680+
value?.getToStringValue()
646681
}
647682
}
648683
}
@@ -666,10 +701,10 @@ class VariablesSerializer(
666701
}
667702

668703
private fun createSerializeVariableState(name: String, simpleTypeName: String?, value: RuntimeObjectWrapper): ProcessedSerializedVarsState {
669-
return doCreateSerializedVarsState(simpleTypeName, value.objectInstance)
704+
return doCreateSerializedVarsState(simpleTypeName, value.objectInstance, value.computerID)
670705
}
671706

672-
private fun doCreateSerializedVarsState(simpleTypeName: String?, value: Any?): ProcessedSerializedVarsState {
707+
private fun doCreateSerializedVarsState(simpleTypeName: String?, value: Any?, uniqueID: String? = null): ProcessedSerializedVarsState {
673708
val javaClass = value?.javaClass
674709
val membersProperties = javaClass?.declaredFields?.filter {
675710
!(it.name.startsWith("script$") || it.name.startsWith("serialVersionUID"))
@@ -687,8 +722,15 @@ class VariablesSerializer(
687722
if (value != null && standardContainersUtilizer.isStandardType(type)) {
688723
return standardContainersUtilizer.serializeContainer(type, value)
689724
}
725+
val stringedValue = getProperString(value)
726+
val finalID = uniqueID
727+
?: if (value !is String) {
728+
value.getUniqueID(stringedValue.contains(": recursive structure"))
729+
} else {
730+
""
731+
}
690732

691-
val serializedVariablesState = SerializedVariablesState(type, getProperString(value), isContainer)
733+
val serializedVariablesState = SerializedVariablesState(type, getProperString(value), isContainer, ID = finalID)
692734

693735
return ProcessedSerializedVarsState(serializedVariablesState, membersProperties?.toTypedArray())
694736
}

src/test/kotlin/org/jetbrains/kotlinx/jupyter/test/repl/ReplTests.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,6 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
11921192
}
11931193
}
11941194

1195-
11961195
@Test
11971196
fun testCyclicSerializationMessage() {
11981197
val res = eval(

0 commit comments

Comments
 (0)