Simplify and fix classloaders handling on script evaluation

#KT-37558 fixed
This commit is contained in:
Ilya Chernikov
2020-04-02 18:58:40 +02:00
parent 138efda19f
commit f84fd810f0
5 changed files with 135 additions and 78 deletions
@@ -8,7 +8,6 @@ package kotlin.script.experimental.jvm
import java.lang.reflect.InvocationTargetException
import kotlin.reflect.KClass
import kotlin.script.experimental.api.*
import kotlin.script.experimental.jvm.impl.getConfigurationWithClassloader
open class BasicJvmScriptEvaluator : ScriptEvaluator {
@@ -16,26 +15,28 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator {
compiledScript: CompiledScript,
scriptEvaluationConfiguration: ScriptEvaluationConfiguration
): ResultWithDiagnostics<EvaluationResult> = try {
val configuration = getConfigurationWithClassloader(compiledScript, scriptEvaluationConfiguration)
compiledScript.getClass(scriptEvaluationConfiguration).onSuccess { scriptClass ->
compiledScript.getClass(configuration).onSuccess { scriptClass ->
// in the future, when (if) we'll stop to compile everything into constructor
// run as SAM
// return res
// configuration shared between all module scripts
val sharedConfiguration = scriptEvaluationConfiguration.getOrPrepareShared(scriptClass.java.classLoader)
val sharedScripts = configuration[ScriptEvaluationConfiguration.jvm.scriptsInstancesSharingMap]
val sharedScripts = sharedConfiguration[ScriptEvaluationConfiguration.jvm.scriptsInstancesSharingMap]
sharedScripts?.get(scriptClass)?.asSuccess()
?: compiledScript.otherScripts.mapSuccess {
invoke(it, configuration)
invoke(it, sharedConfiguration)
}.onSuccess { importedScriptsEvalResults ->
val refinedEvalConfiguration =
configuration.refineBeforeEvaluation(compiledScript).valueOr {
sharedConfiguration.refineBeforeEvaluation(compiledScript).valueOr {
return@invoke ResultWithDiagnostics.Failure(it.reports)
}
val resultValue = try {
// in the future, when (if) we'll stop to compile everything into constructor
// run as SAM
// return res
val instance =
scriptClass.evalWithConfigAndOtherScriptsResults(refinedEvalConfiguration, importedScriptsEvalResults)
@@ -99,3 +100,13 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator {
}
}
private fun ScriptEvaluationConfiguration.getOrPrepareShared(classLoader: ClassLoader): ScriptEvaluationConfiguration =
if (this[ScriptEvaluationConfiguration.jvm.actualClassLoader] != null)
this
else
with {
ScriptEvaluationConfiguration.jvm.actualClassLoader(classLoader)
if (this[ScriptEvaluationConfiguration.scriptsInstancesSharing] == true) {
ScriptEvaluationConfiguration.jvm.scriptsInstancesSharingMap(mutableMapOf())
}
}
@@ -11,7 +11,6 @@ import java.net.URLClassLoader
import kotlin.reflect.KClass
import kotlin.script.experimental.api.*
import kotlin.script.experimental.jvm.*
import kotlin.script.experimental.jvm.actualClassLoader
internal class KJvmCompiledScriptData(
var sourceLocationId: String?,
@@ -122,25 +121,6 @@ fun KJvmCompiledScript.getOrCreateActualClassloader(evaluationConfiguration: Scr
return module.createClassLoader(classLoaderWithDeps)
}
fun getConfigurationWithClassloader(
script: CompiledScript, baseConfiguration: ScriptEvaluationConfiguration
): ScriptEvaluationConfiguration =
if (baseConfiguration.containsKey(ScriptEvaluationConfiguration.jvm.actualClassLoader))
baseConfiguration
else {
val jvmScript = (script as? KJvmCompiledScript)
?: throw IllegalArgumentException("Unexpected compiled script type: $script")
val classloader = jvmScript.getOrCreateActualClassloader(baseConfiguration)
ScriptEvaluationConfiguration(baseConfiguration) {
ScriptEvaluationConfiguration.jvm.actualClassLoader(classloader)
if (baseConfiguration[ScriptEvaluationConfiguration.scriptsInstancesSharing] == true) {
ScriptEvaluationConfiguration.jvm.scriptsInstancesSharingMap(mutableMapOf())
}
}
}
private fun CompiledScript.makeClassLoaderFromDependencies(baseClassLoader: ClassLoader?): ClassLoader? {
val processedScripts = mutableSetOf<CompiledScript>()
fun recursiveScriptsSeq(res: Sequence<CompiledScript>, script: CompiledScript): Sequence<CompiledScript> =