From dd953e0f6671981d2dd94cab5ed535c512948fd1 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Thu, 12 Sep 2019 15:10:21 +0200 Subject: [PATCH] Deduplicating classloaders and classpath entries on constructing script classloader --- .../jvm/impl/KJvmCompiledModule.kt | 4 +-- .../jvm/impl/KJvmCompiledScript.kt | 32 ++++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/KJvmCompiledModule.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/KJvmCompiledModule.kt index cf5ee8bfb96..19e779eb647 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/KJvmCompiledModule.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/KJvmCompiledModule.kt @@ -31,7 +31,7 @@ class KJvmCompiledModuleFromClassLoader(val moduleClassLoader: ClassLoader) : KJ internal class DualClassLoader(fallbackLoader: ClassLoader, parentLoader: ClassLoader?) : ClassLoader(singleClassLoader(fallbackLoader, parentLoader) ?: parentLoader) { - private class Wrapper(parent: ClassLoader) : ClassLoader(parent) { + internal class Wrapper(parent: ClassLoader) : ClassLoader(parent) { fun openFindResources(name: String): Enumeration = super.findResources(name) fun openFindResource(name: String): URL? = super.findResource(name) } @@ -53,7 +53,7 @@ internal class DualClassLoader(fallbackLoader: ClassLoader, parentLoader: ClassL } } - private val fallbackClassLoader: Wrapper? = + internal val fallbackClassLoader: Wrapper? = if (/* optimization */ parentLoader == null || singleClassLoader(fallbackLoader, parentLoader) != null) null else Wrapper(fallbackLoader) diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/KJvmCompiledScript.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/KJvmCompiledScript.kt index 92f0e7bb088..321bbb218b8 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/KJvmCompiledScript.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/KJvmCompiledScript.kt @@ -6,6 +6,7 @@ package kotlin.script.experimental.jvm.impl import java.io.* +import java.net.URL import java.net.URLClassLoader import kotlin.reflect.KClass import kotlin.script.experimental.api.* @@ -149,12 +150,35 @@ private fun CompiledScript<*>.makeClassLoaderFromDependencies(baseClassLoader: C script.compilationConfiguration[ScriptCompilationConfiguration.dependencies] ?.asSequence()?.map { script.compilationConfiguration to it } ?: emptySequence() } + + val processedClasspathElements = mutableSetOf() + fun recursiveClassPath(res: Sequence, classLoader: ClassLoader?): Sequence = + when (classLoader) { + null -> res + is DualClassLoader -> recursiveClassPath(res, classLoader.parent) + + recursiveClassPath(emptySequence(), classLoader.fallbackClassLoader) + is URLClassLoader -> recursiveClassPath(res + classLoader.urLs, classLoader.parent) + else -> recursiveClassPath(res, classLoader.parent) + } + recursiveClassPath(emptySequence(), baseClassLoader).forEach { processedClasspathElements.add(it) } + + val processedClassloaders = mutableSetOf() + return dependenciesWithConfigurations.fold(baseClassLoader) { parentClassLoader, (compilationConfiguration, scriptDependency) -> when (scriptDependency) { - is JvmDependency -> URLClassLoader(scriptDependency.classpath.map { it.toURI().toURL() }.toTypedArray(), parentClassLoader) - is JvmDependencyFromClassLoader -> DualClassLoader(scriptDependency.getClassLoader(compilationConfiguration), baseClassLoader) - else -> baseClassLoader - } + is JvmDependency -> { + scriptDependency.classpath.mapNotNull { + val url = it.toURI().toURL() + if (processedClasspathElements.add(url)) url else null + }.takeUnless { it.isEmpty() }?.let { URLClassLoader(it.toTypedArray(), parentClassLoader) } + } + is JvmDependencyFromClassLoader -> { + val dependenciesClassLoader = scriptDependency.getClassLoader(compilationConfiguration) + if (processedClassloaders.add(dependenciesClassLoader)) DualClassLoader(dependenciesClassLoader, parentClassLoader) + else null + } + else -> null + } ?: parentClassLoader } }