diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt index 2a75f9e6f71..a9222e2283d 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt @@ -130,17 +130,17 @@ val ScriptCompilationConfigurationKeys.compilerOptions by PropertiesCollection.k /** * The callback that will be called on the script compilation before parsing the script */ -val ScriptCompilationConfigurationKeys.refineConfigurationBeforeParsing by PropertiesCollection.key>() +val ScriptCompilationConfigurationKeys.refineConfigurationBeforeParsing by PropertiesCollection.key>(isTransient = true) /** * The callback that will be called on the script compilation after parsing script file annotations */ -val ScriptCompilationConfigurationKeys.refineConfigurationOnAnnotations by PropertiesCollection.key>() +val ScriptCompilationConfigurationKeys.refineConfigurationOnAnnotations by PropertiesCollection.key>(isTransient = true) /** * The callback that will be called on the script compilation immediately before starting the compilation */ -val ScriptCompilationConfigurationKeys.refineConfigurationBeforeCompiling by PropertiesCollection.key>() +val ScriptCompilationConfigurationKeys.refineConfigurationBeforeCompiling by PropertiesCollection.key>(isTransient = true) /** * The list of script fragments that should be compiled intead of the whole text @@ -151,7 +151,7 @@ val ScriptCompilationConfigurationKeys.sourceFragments by PropertiesCollection.k /** * Scripting host configuration */ -val ScriptCompilationConfigurationKeys.hostConfiguration by PropertiesCollection.key() +val ScriptCompilationConfigurationKeys.hostConfiguration by PropertiesCollection.key(isTransient = true) /** * The sub-builder DSL for configuring refinement callbacks diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt index 15bf93c9f0e..893791c80fb 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptEvaluation.kt @@ -68,10 +68,10 @@ val ScriptEvaluationConfigurationKeys.constructorArgs by PropertiesCollection.ke * For the first snippet in a REPL an empty list should be passed explicitly * An array of the previous snippets will be passed to the current snippet constructor */ -val ScriptEvaluationConfigurationKeys.previousSnippets by PropertiesCollection.key>() +val ScriptEvaluationConfigurationKeys.previousSnippets by PropertiesCollection.key>(isTransient = true) @Deprecated("use scriptsInstancesSharing flag instead", level = DeprecationLevel.ERROR) -val ScriptEvaluationConfigurationKeys.scriptsInstancesSharingMap by PropertiesCollection.key, EvaluationResult>>() +val ScriptEvaluationConfigurationKeys.scriptsInstancesSharingMap by PropertiesCollection.key, EvaluationResult>>(isTransient = true) /** * If enabled - the evaluator will try to get imported script from a shared container @@ -83,12 +83,12 @@ val ScriptEvaluationConfigurationKeys.scriptsInstancesSharing by PropertiesColle /** * Scripting host configuration */ -val ScriptEvaluationConfigurationKeys.hostConfiguration by PropertiesCollection.key() +val ScriptEvaluationConfigurationKeys.hostConfiguration by PropertiesCollection.key(isTransient = true) /** * The callback that will be called on the script compilation immediately before starting the compilation */ -val ScriptEvaluationConfigurationKeys.refineConfigurationBeforeEvaluate by PropertiesCollection.key>() +val ScriptEvaluationConfigurationKeys.refineConfigurationBeforeEvaluate by PropertiesCollection.key>(isTransient = true) /** * A helper to enable scriptsInstancesSharingMap with default implementation diff --git a/libraries/scripting/common/src/kotlin/script/experimental/host/hostConfiguration.kt b/libraries/scripting/common/src/kotlin/script/experimental/host/hostConfiguration.kt index c0eb08a3c4d..47d0554efdc 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/host/hostConfiguration.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/host/hostConfiguration.kt @@ -50,7 +50,7 @@ val ScriptingHostConfigurationKeys.configurationDependencies by PropertiesCollec /** * The pointer to the generic "class loader" for the types used in the script configurations */ -val ScriptingHostConfigurationKeys.getScriptingClass by PropertiesCollection.key() +val ScriptingHostConfigurationKeys.getScriptingClass by PropertiesCollection.key(isTransient = true) /** * The interface to the generic "class loader" for the types used in the script configurations diff --git a/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt b/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt index a1e1856751b..076a9c1c9a1 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/util/propertiesCollection.kt @@ -5,15 +5,20 @@ package kotlin.script.experimental.util +import java.io.ObjectInputStream +import java.io.ObjectOutputStream import java.io.Serializable import kotlin.reflect.KClass import kotlin.reflect.KProperty import kotlin.reflect.KType import kotlin.script.experimental.api.KotlinType -open class PropertiesCollection(private val properties: Map, Any?> = emptyMap()) : Serializable { +open class PropertiesCollection(private var properties: Map, Any?> = emptyMap()) : Serializable { - class Key(val name: String, @Transient val getDefaultValue: PropertiesCollection.() -> T?) : Serializable { + open class Key( + val name: String, + @Transient val getDefaultValue: PropertiesCollection.() -> T? + ) : Serializable { constructor(name: String, defaultValue: T? = null) : this(name, { defaultValue }) @@ -27,11 +32,17 @@ open class PropertiesCollection(private val properties: Map, Any?> = empt } } - class PropertyKeyDelegate(private val getDefaultValue: PropertiesCollection.() -> T?) { - constructor(defaultValue: T?) : this({ defaultValue }) + class TransientKey( + name: String, + getDefaultValue: PropertiesCollection.() -> T? + ) : Key(name, getDefaultValue) + + class PropertyKeyDelegate(private val getDefaultValue: PropertiesCollection.() -> T?, val isTransient: Boolean = false) { + constructor(defaultValue: T?, isTransient: Boolean = false) : this({ defaultValue }, isTransient) operator fun getValue(thisRef: Any?, property: KProperty<*>): Key = - Key(property.name, getDefaultValue) + if (isTransient) TransientKey(property.name, getDefaultValue) + else Key(property.name, getDefaultValue) } class PropertyKeyCopyDelegate(val source: Key) { @@ -51,14 +62,29 @@ open class PropertiesCollection(private val properties: Map, Any?> = empt fun entries(): Set, Any?>> = properties.entries + val notTransientData: Map, Any?> get() = properties.filterKeys { it !is TransientKey<*>} + override fun equals(other: Any?): Boolean = (other as? PropertiesCollection)?.let { it.properties == properties } == true override fun hashCode(): Int = properties.hashCode() + private fun writeObject(outputStream: ObjectOutputStream) { + outputStream.writeObject(notTransientData) + } + + private fun readObject(inputStream: ObjectInputStream) { + @Suppress("UNCHECKED_CAST") + properties = inputStream.readObject() as Map, Any?> + } + companion object { - fun key(defaultValue: T? = null): PropertyKeyDelegate = PropertyKeyDelegate(defaultValue) - fun key(getDefaultValue: PropertiesCollection.() -> T?): PropertyKeyDelegate = PropertyKeyDelegate(getDefaultValue) + fun key(defaultValue: T? = null, isTransient: Boolean = false): PropertyKeyDelegate = + PropertyKeyDelegate(defaultValue, isTransient) + + fun key(getDefaultValue: PropertiesCollection.() -> T?, isTransient: Boolean = false): PropertyKeyDelegate = + PropertyKeyDelegate(getDefaultValue, isTransient) + fun keyCopy(source: Key): PropertyKeyCopyDelegate = PropertyKeyCopyDelegate(source) @JvmStatic diff --git a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/CachingTest.kt b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/CachingTest.kt index df24b12bf6d..188fd2c5d93 100644 --- a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/CachingTest.kt +++ b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/CachingTest.kt @@ -128,7 +128,7 @@ class CachingTest : TestCase() { Assert.assertEquals(1, cache.storedScripts) Assert.assertEquals(0, cache.retrievedScripts) - val cachedScript = cache.get(script.toScriptSource(), scriptCompilationConfiguration) + val cachedScript = cache.get(script.toScriptSource(), compiledScript!!.compilationConfiguration) Assert.assertNotNull(cachedScript) Assert.assertEquals(1, cache.retrievedScripts) @@ -164,7 +164,7 @@ private interface ScriptingCacheWithCounters : CompiledJvmScriptsCache { private class SimpleMemoryScriptsCache : ScriptingCacheWithCounters { - internal val data = hashMapOf, CompiledScript<*>>() + internal val data = hashMapOf>, CompiledScript<*>>() private var _storedScripts = 0 private var _retrievedScripts = 0 @@ -176,14 +176,14 @@ private class SimpleMemoryScriptsCache : ScriptingCacheWithCounters { get() = _retrievedScripts override fun get(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration): CompiledScript<*>? = - data[script to scriptCompilationConfiguration]?.also { _retrievedScripts++ } + data[script to scriptCompilationConfiguration.notTransientData]?.also { _retrievedScripts++ } override fun store( compiledScript: CompiledScript<*>, script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration ) { - data[script to scriptCompilationConfiguration] = compiledScript + data[script to scriptCompilationConfiguration.notTransientData] = compiledScript _storedScripts++ } } @@ -242,10 +242,12 @@ class TestCompiledScriptJarsCache(val baseDir: File) : CompiledScriptJarsCache( internal fun uniqueScriptHash(script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration): String { val digestWrapper = MessageDigest.getInstance("MD5") digestWrapper.update(script.text.toByteArray()) - scriptCompilationConfiguration.entries().sortedBy { it.key.name }.forEach { - digestWrapper.update(it.key.name.toByteArray()) - digestWrapper.update(it.value.toString().toByteArray()) - } + scriptCompilationConfiguration.notTransientData.entries + .sortedBy { it.key.name } + .forEach { + digestWrapper.update(it.key.name.toByteArray()) + digestWrapper.update(it.value.toString().toByteArray()) + } return digestWrapper.digest().toHexString() } diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jsr223/KotlinJsr223HostConfiguration.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jsr223/KotlinJsr223HostConfiguration.kt index 730f9dfca13..aff09d15545 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jsr223/KotlinJsr223HostConfiguration.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jsr223/KotlinJsr223HostConfiguration.kt @@ -32,9 +32,12 @@ open class Jsr223CompilationConfigurationBuilder : PropertiesCollection.Builder( val ScriptCompilationConfigurationKeys.jsr223 get() = Jsr223CompilationConfigurationBuilder() -val Jsr223CompilationConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?> { - get(ScriptCompilationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jsr223.getScriptContext) -} +val Jsr223CompilationConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?>( + { + get(ScriptCompilationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jsr223.getScriptContext) + }, + isTransient = true +) val Jsr223CompilationConfigurationKeys.importAllBindings by PropertiesCollection.key(false) @@ -47,8 +50,11 @@ open class Jsr223EvaluationConfigurationBuilder : PropertiesCollection.Builder() val ScriptEvaluationConfigurationKeys.jsr223 get() = Jsr223EvaluationConfigurationBuilder() -val Jsr223EvaluationConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?> { - get(ScriptEvaluationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jsr223.getScriptContext) -} +val Jsr223EvaluationConfigurationKeys.getScriptContext by PropertiesCollection.key<() -> ScriptContext?>( + { + get(ScriptEvaluationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jsr223.getScriptContext) + }, + isTransient = true +) diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt index b69c1153284..7fe61bc3265 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt @@ -8,7 +8,10 @@ package kotlin.script.experimental.jvm import kotlin.reflect.KClass -import kotlin.script.experimental.api.* +import kotlin.script.experimental.api.EvaluationResult +import kotlin.script.experimental.api.ScriptEvaluationConfiguration +import kotlin.script.experimental.api.ScriptEvaluationConfigurationKeys +import kotlin.script.experimental.api.hostConfiguration import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.util.PropertiesCollection @@ -22,10 +25,13 @@ open class JvmScriptEvaluationConfigurationBuilder : PropertiesCollection.Builde /** * The base classloader to use for script classes loading */ -val JvmScriptEvaluationConfigurationKeys.baseClassLoader by PropertiesCollection.key { - get(ScriptEvaluationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jvm.baseClassLoader) - ?: Thread.currentThread().contextClassLoader -} +val JvmScriptEvaluationConfigurationKeys.baseClassLoader by PropertiesCollection.key( + { + get(ScriptEvaluationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jvm.baseClassLoader) + ?: Thread.currentThread().contextClassLoader + }, + isTransient = true +) /** * Load script dependencies before evaluation, true by default @@ -38,8 +44,10 @@ val JvmScriptEvaluationConfigurationKeys.loadDependencies by PropertiesCollectio */ val JvmScriptEvaluationConfigurationKeys.mainArguments by PropertiesCollection.key>() -internal val JvmScriptEvaluationConfigurationKeys.actualClassLoader by PropertiesCollection.key() +internal val JvmScriptEvaluationConfigurationKeys.actualClassLoader by PropertiesCollection.key(isTransient = true) -internal val JvmScriptEvaluationConfigurationKeys.scriptsInstancesSharingMap by PropertiesCollection.key, EvaluationResult>>() +internal val JvmScriptEvaluationConfigurationKeys.scriptsInstancesSharingMap by PropertiesCollection.key, EvaluationResult>>( + isTransient = true +) val ScriptEvaluationConfigurationKeys.jvm get() = JvmScriptEvaluationConfigurationBuilder() diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptingHostConfiguration.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptingHostConfiguration.kt index 42540d9be7b..727f3b15c65 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptingHostConfiguration.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptingHostConfiguration.kt @@ -9,7 +9,8 @@ import java.io.File import java.io.Serializable import java.net.URLClassLoader import kotlin.reflect.KClass -import kotlin.script.experimental.api.* +import kotlin.script.experimental.api.KotlinType +import kotlin.script.experimental.api.ScriptDependency import kotlin.script.experimental.host.* import kotlin.script.experimental.jvm.impl.toClassPathOrEmpty import kotlin.script.experimental.util.PropertiesCollection @@ -26,11 +27,14 @@ val JvmScriptingHostConfigurationKeys.javaHome by PropertiesCollection.key val JvmScriptingHostConfigurationKeys.jdkHome by PropertiesCollection.key() -val JvmScriptingHostConfigurationKeys.baseClassLoader by PropertiesCollection.key { - get(ScriptingHostConfiguration.configurationDependencies)?.let { - URLClassLoader(it.toClassPathOrEmpty().map { f -> f.toURI().toURL() }.toTypedArray()) - } -} +val JvmScriptingHostConfigurationKeys.baseClassLoader by PropertiesCollection.key( + { + get(ScriptingHostConfiguration.configurationDependencies)?.let { + URLClassLoader(it.toClassPathOrEmpty().map { f -> f.toURI().toURL() }.toTypedArray()) + } + }, + isTransient = true +) @Suppress("unused") val ScriptingHostConfigurationKeys.jvm