Skip to content

Commit e050cb6

Browse files
Add gradle property jupyter.serialization.enabled;fix recursive structures with jvmFields
1 parent 0981a80 commit e050cb6

File tree

6 files changed

+80
-45
lines changed

6 files changed

+80
-45
lines changed

build.gradle.kts

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ plugins {
1212

1313
val deploy: Configuration by configurations.creating
1414

15+
val serializationFlagProperty = "jupyter.serialization.enabled"
16+
1517
deploy.apply {
1618
exclude("org.jetbrains.kotlinx", "kotlinx-serialization-json-jvm")
1719
exclude("org.jetbrains.kotlinx", "kotlinx-serialization-core-jvm")
@@ -108,7 +110,8 @@ tasks {
108110

109111
"junit.jupiter.execution.parallel.enabled" to doParallelTesting.toString() as Any,
110112
"junit.jupiter.execution.parallel.mode.default" to "concurrent",
111-
"junit.jupiter.execution.parallel.mode.classes.default" to "concurrent"
113+
"junit.jupiter.execution.parallel.mode.classes.default" to "concurrent",
114+
serializationFlagProperty to "true"
112115
)
113116
}
114117

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

-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ data class SerializedCompiledScriptsData(
2222

2323
@Serializable
2424
data class SerializedVariablesState(
25-
val name: String = "",
2625
val type: String = "",
2726
val value: String? = null,
2827
val isContainer: Boolean = false

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

-2
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,6 @@ class ReplForJupyterImpl(
424424
notebook.updateVariablesState(internalEvaluator)
425425
// printVars()
426426
// printUsagesInfo(jupyterId, cellVariables[jupyterId - 1])
427-
val entry = notebook.variablesState.entries.lastOrNull()
428-
val serializedVarsState = variablesSerializer.serializeVariableState(jupyterId - 1, entry?.key, entry?.value)
429427
val serializedData = variablesSerializer.serializeVariables(jupyterId - 1, notebook.variablesState)
430428

431429
EvalResult(rendered, EvaluatedSnippetMetadata(newClasspath, compiledData, newImports, serializedData))

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

+67-38
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,16 @@ typealias FieldDescriptor = Map<String, SerializedVariablesState?>
1515
typealias MutableFieldDescriptor = MutableMap<String, SerializedVariablesState?>
1616
typealias PropertiesData = Collection<KProperty1<out Any, *>>
1717

18-
data class ProcessedSerializedVarsState(
18+
class ProcessedSerializedVarsState(
1919
val serializedVariablesState: SerializedVariablesState,
2020
val propertiesData: PropertiesData?,
2121
val jvmOnlyFields: Array<Field>? = null
22-
) {
23-
// autogenerated
24-
override fun equals(other: Any?): Boolean {
25-
if (this === other) return true
26-
if (javaClass != other?.javaClass) return false
27-
28-
other as ProcessedSerializedVarsState
29-
30-
if (serializedVariablesState != other.serializedVariablesState) return false
31-
if (propertiesData != other.propertiesData) return false
32-
if (jvmOnlyFields != null) {
33-
if (other.jvmOnlyFields == null) return false
34-
if (!jvmOnlyFields.contentEquals(other.jvmOnlyFields)) return false
35-
} else if (other.jvmOnlyFields != null) return false
36-
37-
return true
38-
}
39-
40-
override fun hashCode(): Int {
41-
var result = serializedVariablesState.hashCode()
42-
result = 31 * result + (propertiesData?.hashCode() ?: 0)
43-
result = 31 * result + (jvmOnlyFields?.contentHashCode() ?: 0)
44-
return result
45-
}
46-
}
22+
)
4723

4824
data class ProcessedDescriptorsState(
49-
// perhaps, better tp make SerializedVariablesState -> PropertiesData?
50-
val processedSerializedVarsState: MutableMap<SerializedVariablesState, PropertiesData?> = mutableMapOf(),
25+
val processedSerializedVarsToKProperties: MutableMap<SerializedVariablesState, PropertiesData?> = mutableMapOf(),
26+
// do we need this? Probably, not
27+
// val processedSerializedVarsToJvmFields: MutableMap<SerializedVariablesState, Array<Field>?> = mutableMapOf(),
5128
val instancesPerState: MutableMap<SerializedVariablesState, Any?> = mutableMapOf()
5229
)
5330

@@ -68,7 +45,11 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
6845
*/
6946
private val computedDescriptorsPerCell: MutableMap<Int, ProcessedDescriptorsState> = mutableMapOf()
7047

48+
private val isSerializationActive: Boolean = System.getProperty(serializationEnvProperty)?.toBooleanStrictOrNull() ?: true
49+
7150
fun serializeVariables(cellId: Int, variablesState: Map<String, VariableState>): Map<String, SerializedVariablesState> {
51+
if (!isSerializationActive) return emptyMap()
52+
7253
if (seenObjectsPerCell.containsKey(cellId)) {
7354
seenObjectsPerCell[cellId]!!.clear()
7455
}
@@ -80,6 +61,8 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
8061
}
8162

8263
fun doIncrementalSerialization(cellId: Int, propertyName: String, serializedVariablesState: SerializedVariablesState): SerializedVariablesState {
64+
if (!isSerializationActive) return serializedVariablesState
65+
8366
val cellDescriptors = computedDescriptorsPerCell[cellId] ?: return serializedVariablesState
8467
return updateVariableState(cellId, propertyName, cellDescriptors, serializedVariablesState)
8568
}
@@ -94,9 +77,8 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
9477
evaluatedDescriptorsState: ProcessedDescriptorsState,
9578
serializedVariablesState: SerializedVariablesState
9679
): SerializedVariablesState {
97-
// TODO: consider anonymous class as well and fix bug with state
9880
val value = evaluatedDescriptorsState.instancesPerState[serializedVariablesState]
99-
val propertiesData = evaluatedDescriptorsState.processedSerializedVarsState[serializedVariablesState]
81+
val propertiesData = evaluatedDescriptorsState.processedSerializedVarsToKProperties[serializedVariablesState]
10082
if (propertiesData == null && value != null && (value::class.java.isArray || value::class.java.isMemberClass)) {
10183
return serializeVariableState(cellId, propertyName, propertiesData, value, false)
10284
}
@@ -108,21 +90,25 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
10890
}
10991

11092
fun serializeVariableState(cellId: Int, name: String?, variableState: VariableState?, isOverride: Boolean = true): SerializedVariablesState {
111-
if (variableState == null || name == null) return SerializedVariablesState()
93+
if (!isSerializationActive || variableState == null || name == null) return SerializedVariablesState()
11294
return serializeVariableState(cellId, name, variableState.property, variableState.value, isOverride)
11395
}
11496

115-
fun serializeVariableState(cellId: Int, name: String, property: Field?, value: Any?, isOverride: Boolean = true): SerializedVariablesState {
97+
private fun serializeVariableState(cellId: Int, name: String, property: Field?, value: Any?, isOverride: Boolean = true): SerializedVariablesState {
11698
val processedData = createSerializeVariableState(name, getSimpleTypeNameFrom(property, value), value)
11799
return doActualSerialization(cellId, processedData, value, isOverride)
118100
}
119101

120-
fun serializeVariableState(cellId: Int, name: String, property: KProperty<*>, value: Any?, isOverride: Boolean = true): SerializedVariablesState {
102+
private fun serializeVariableState(cellId: Int, name: String, property: KProperty<*>, value: Any?, isOverride: Boolean = true): SerializedVariablesState {
121103
val processedData = createSerializeVariableState(name, getSimpleTypeNameFrom(property, value), value)
122104
return doActualSerialization(cellId, processedData, value, isOverride)
123105
}
124106

125107
private fun doActualSerialization(cellId: Int, processedData: ProcessedSerializedVarsState, value: Any?, isOverride: Boolean = true): SerializedVariablesState {
108+
fun isCanBeComputed(fieldDescriptors: MutableMap<String, SerializedVariablesState?>): Boolean {
109+
return (fieldDescriptors.isEmpty() || (fieldDescriptors.isNotEmpty() && fieldDescriptors.entries.first().value?.fieldDescriptor!!.isEmpty()))
110+
}
111+
126112
val serializedVersion = processedData.serializedVariablesState
127113

128114
seenObjectsPerCell.putIfAbsent(cellId, mutableMapOf())
@@ -131,13 +117,27 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
131117
computedDescriptorsPerCell[cellId] = ProcessedDescriptorsState()
132118
}
133119
val currentCellDescriptors = computedDescriptorsPerCell[cellId]
134-
currentCellDescriptors!!.processedSerializedVarsState[serializedVersion] = processedData.propertiesData
120+
currentCellDescriptors!!.processedSerializedVarsToKProperties[serializedVersion] = processedData.propertiesData
121+
// currentCellDescriptors.processedSerializedVarsToJvmFields[serializedVersion] = processedData.jvmOnlyFields
135122

136123
if (value != null) {
137-
seenObjectsPerCell[cellId]!![value] = serializedVersion
124+
seenObjectsPerCell[cellId]!!.putIfAbsent(value, serializedVersion)
138125
}
139126
if (serializedVersion.isContainer) {
140-
iterateThroughContainerMembers(cellId, value, serializedVersion.fieldDescriptor, currentCellDescriptors.processedSerializedVarsState[serializedVersion])
127+
// check for seen
128+
if (seenObjectsPerCell[cellId]!!.containsKey(value)) {
129+
val previouslySerializedState = seenObjectsPerCell[cellId]!![value] ?: return processedData.serializedVariablesState
130+
serializedVersion.fieldDescriptor += previouslySerializedState.fieldDescriptor
131+
if (isCanBeComputed(serializedVersion.fieldDescriptor)) {
132+
iterateThroughContainerMembers(cellId, value, serializedVersion.fieldDescriptor, currentCellDescriptors.processedSerializedVarsToKProperties[serializedVersion])
133+
}
134+
} else {
135+
// add jvm descriptors
136+
processedData.jvmOnlyFields?.forEach {
137+
serializedVersion.fieldDescriptor[it.name] = serializeVariableState(cellId, it.name, it, value)
138+
}
139+
iterateThroughContainerMembers(cellId, value, serializedVersion.fieldDescriptor, currentCellDescriptors.processedSerializedVarsToKProperties[serializedVersion])
140+
}
141141
}
142142
return processedData.serializedVariablesState
143143
}
@@ -150,6 +150,7 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
150150
seenObjectsPerCell.putIfAbsent(cellId, mutableMapOf())
151151
val seenObjectsPerCell = seenObjectsPerCell[cellId]
152152
val currentCellDescriptors = computedDescriptorsPerCell[cellId]!!
153+
// ok, it's a copy on the left for some reason
153154
val instancesPerState = currentCellDescriptors.instancesPerState
154155

155156
for (it in properties) {
@@ -181,6 +182,26 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
181182
}
182183

183184
val isArrayType = checkCreateForPossibleArray(callInstance, descriptor, serializedIteration)
185+
computedDescriptorsPerCell[cellId]!!.instancesPerState += instancesPerState
186+
187+
// check for seen
188+
// for now it's O(c*n)
189+
if (serializedIteration.isEmpty()) {
190+
val processedVars = computedDescriptorsPerCell[cellId]!!.processedSerializedVarsToKProperties
191+
descriptor.forEach { (_, state) ->
192+
if (processedVars.containsKey(state)) {
193+
processedVars.entries.firstOrNull {
194+
val itValue = it.key
195+
if (itValue.value == state?.value && itValue.type == state?.value) {
196+
state?.fieldDescriptor?.put(itValue.type, itValue)
197+
true
198+
} else {
199+
false
200+
}
201+
}
202+
}
203+
}
204+
}
184205

185206
serializedIteration.forEach {
186207
val serializedVariablesState = it.value.serializedVariablesState
@@ -227,8 +248,12 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
227248
// update state with JVMFields
228249
it.value.jvmOnlyFields?.forEach { field ->
229250
serializedVariablesState.fieldDescriptor[field.name] = serializeVariableState(cellId, field.name, field, neededCallInstance)
230-
instancesPerState[serializedVariablesState] = neededCallInstance
251+
val properInstance = serializedVariablesState.fieldDescriptor[field.name]
252+
instancesPerState[properInstance!!] = neededCallInstance
253+
seenObjectsPerCell?.set(neededCallInstance!!, serializedVariablesState)
231254
}
255+
computedDescriptorsPerCell[cellId]!!.instancesPerState += instancesPerState
256+
// computedDescriptorsPerCell[cellId]!!.processedSerializedVarsToJvmFields[serializedVariablesState] = it.value.jvmOnlyFields
232257
iterateThroughContainerMembers(
233258
cellId,
234259
neededCallInstance,
@@ -286,7 +311,7 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
286311
simpleTypeName.toString()
287312
}
288313

289-
val serializedVariablesState = SerializedVariablesState(name, type, getProperString(value), isContainer)
314+
val serializedVariablesState = SerializedVariablesState(type, getProperString(value), isContainer)
290315

291316
return ProcessedSerializedVarsState(serializedVariablesState, membersProperties, jvmFields)
292317
}
@@ -324,6 +349,10 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
324349
false
325350
}
326351
}
352+
353+
companion object {
354+
const val serializationEnvProperty = "jupyter.serialization.enabled"
355+
}
327356
}
328357

329358
fun getProperString(value: Any?): String {

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

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.jetbrains.kotlinx.jupyter
22

33
import org.jetbrains.kotlinx.jupyter.api.bufferedImageRenderer
44
import org.jetbrains.kotlinx.jupyter.codegen.ResultsRenderersProcessor
5+
import org.jetbrains.kotlinx.jupyter.compiler.util.SerializedVariablesState
56
import org.jetbrains.kotlinx.jupyter.compiler.util.SourceCodeImpl
67
import kotlin.script.experimental.api.ScriptDiagnostic
78
import kotlin.script.experimental.api.SourceCode
@@ -69,6 +70,10 @@ fun ResultsRenderersProcessor.registerDefaultRenderers() {
6970
register(bufferedImageRenderer)
7071
}
7172

73+
fun Map<String, SerializedVariablesState>.getValuesToString(): Map<String, String?> {
74+
return this.mapValues { it.value.value }
75+
}
76+
7277
/**
7378
* Stores info about where a variable Y was declared and info about what are they at the address X.
7479
* K: key, stands for a way of addressing variables, e.g. address.

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import org.jetbrains.kotlinx.jupyter.api.VariableStateImpl
99
import org.jetbrains.kotlinx.jupyter.exceptions.ReplCompilerException
1010
import org.jetbrains.kotlinx.jupyter.generateDiagnostic
1111
import org.jetbrains.kotlinx.jupyter.generateDiagnosticFromAbsolute
12+
import org.jetbrains.kotlinx.jupyter.getValuesToString
1213
import org.jetbrains.kotlinx.jupyter.repl.CompletionResult
1314
import org.jetbrains.kotlinx.jupyter.repl.ListErrorsResult
1415
import org.jetbrains.kotlinx.jupyter.test.getOrFail
@@ -463,7 +464,7 @@ class ReplVarsTest : AbstractSingleReplTest() {
463464
"y" to "0",
464465
"z" to "47"
465466
)
466-
assertEquals(res.metadata.evaluatedVariablesState.mapValues { it.value.value }, varsUpdate)
467+
assertEquals(res.metadata.evaluatedVariablesState.getValuesToString(), varsUpdate)
467468
assertFalse(repl.notebook.variablesState.isEmpty())
468469
val varsState = repl.notebook.variablesState
469470
assertEquals("1", varsState.getStringValue("x"))
@@ -866,7 +867,7 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
866867

867868
val serializer = repl.variablesSerializer
868869

869-
val newData = serializer.doIncrementalSerialization(0, descriptor["i"]!!.name, descriptor["i"]!!)
870+
val newData = serializer.doIncrementalSerialization(0, "i", descriptor["i"]!!)
870871
val a = 1
871872
}
872873

@@ -887,7 +888,7 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
887888
val actualContainer = listData.fieldDescriptor.entries.first().value!!
888889
val serializer = repl.variablesSerializer
889890

890-
val newData = serializer.doIncrementalSerialization(0, actualContainer.name, actualContainer)
891+
val newData = serializer.doIncrementalSerialization(0, listData.fieldDescriptor.entries.first().key, actualContainer)
891892
var receivedDescriptor = newData.fieldDescriptor
892893
assertEquals(2, receivedDescriptor.size)
893894
assertTrue(receivedDescriptor.containsKey("size"))

0 commit comments

Comments
 (0)