diff --git a/compiler/preloader/src/org/jetbrains/kotlin/preloading/ClassPreloadingUtils.java b/compiler/preloader/src/org/jetbrains/kotlin/preloading/ClassPreloadingUtils.java index b4b866d94da..000ab86eb34 100644 --- a/compiler/preloader/src/org/jetbrains/kotlin/preloading/ClassPreloadingUtils.java +++ b/compiler/preloader/src/org/jetbrains/kotlin/preloading/ClassPreloadingUtils.java @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.preloading; import java.io.*; +import java.net.URL; +import java.net.URLClassLoader; import java.util.*; import java.util.jar.Attributes; import java.util.jar.JarFile; @@ -29,8 +31,6 @@ public class ClassPreloadingUtils { /** * Creates a class loader that loads all classes from {@code jarFiles} into memory to make loading faster (avoid skipping through zip archives). * - * NOTE: if many resources with the same name exist, only the first one will be loaded - * * @param jarFiles jars to load all classes from * @param classCountEstimation an estimated number of classes in a the jars * @param parentClassLoader parent class loader @@ -53,7 +53,15 @@ public class ClassPreloadingUtils { parentClassLoader = preloadClasses(classpath, classCountEstimation, parentClassLoader, null, handler); } - return new MemoryBasedClassLoader(classesToLoadByParent, parentClassLoader, entries, handler); + return new MemoryBasedClassLoader(classesToLoadByParent, createFallbackClassLoader(jarFiles, parentClassLoader), entries, handler); + } + + private static URLClassLoader createFallbackClassLoader(Collection files, ClassLoader parent) throws IOException { + List urls = new ArrayList(files.size()); + for (File file : files) { + urls.add(file.toURI().toURL()); + } + return new URLClassLoader(urls.toArray(new URL[urls.size()]), parent); } public static ClassLoader preloadClasses( diff --git a/compiler/preloader/src/org/jetbrains/kotlin/preloading/MemoryBasedClassLoader.java b/compiler/preloader/src/org/jetbrains/kotlin/preloading/MemoryBasedClassLoader.java index 636d1942917..50dea9d870b 100644 --- a/compiler/preloader/src/org/jetbrains/kotlin/preloading/MemoryBasedClassLoader.java +++ b/compiler/preloader/src/org/jetbrains/kotlin/preloading/MemoryBasedClassLoader.java @@ -21,6 +21,14 @@ import java.net.URL; import java.util.*; @SuppressWarnings("unchecked") +/** + * A class loader which loads classes and resources from the given map. + * + * To save memory, as soon as any class is loaded, its bytecode is removed from the map. + * This means that once any class is loaded, it _cannot be found_ as a resource anymore. + * Therefore if you need to be able to find classes via findResource(), you should pass a parent + * class loader which is able to do that at any point of time. + */ public class MemoryBasedClassLoader extends ClassLoader { private final ClassCondition classesToLoadByParent; private final ClassLoader parent; @@ -77,6 +85,9 @@ public class MemoryBasedClassLoader extends ClassLoader { Object resources = preloadedResources.get(internalName); if (resources == null) return null; + // Clear the resource, we won't need it anymore + preloadedResources.remove(internalName); + ResourceData resourceData = resources instanceof ResourceData ? ((ResourceData) resources) : ((List) resources).get(0); diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.java b/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.java index 2c18b341340..a8af90c9148 100644 --- a/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.java +++ b/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.java @@ -135,7 +135,11 @@ public class PathUtil { @NotNull public static File getResourcePathForClass(@NotNull Class aClass) { - String resourceRoot = PathManager.getResourceRoot(aClass, "/" + aClass.getName().replace('.', '/') + ".class"); + String path = "/" + aClass.getName().replace('.', '/') + ".class"; + String resourceRoot = PathManager.getResourceRoot(aClass, path); + if (resourceRoot == null) { + throw new IllegalStateException("Resource not found: " + path); + } return new File(resourceRoot).getAbsoluteFile(); }