diff --git a/compiler/testData/reflection/classLoaderForBuiltIns/Main.java b/compiler/testData/reflection/classLoaderForBuiltIns/Main.java new file mode 100644 index 00000000000..b57327385f0 --- /dev/null +++ b/compiler/testData/reflection/classLoaderForBuiltIns/Main.java @@ -0,0 +1,15 @@ +import java.io.*; +import java.net.*; + +public class Main { + public static void main(String[] args) throws Exception { + URL[] urls = new URL[args.length]; + for (int i = 0; i < args.length; i++) { + urls[i] = new File(args[i]).toURI().toURL(); + } + + ClassLoader cl = new URLClassLoader(urls); + Class c = cl.loadClass("TestKt"); + c.getDeclaredMethods()[0].invoke(null); + } +} diff --git a/compiler/testData/reflection/classLoaderForBuiltIns/test.kt b/compiler/testData/reflection/classLoaderForBuiltIns/test.kt new file mode 100644 index 00000000000..fa36bdb9893 --- /dev/null +++ b/compiler/testData/reflection/classLoaderForBuiltIns/test.kt @@ -0,0 +1,3 @@ +fun test() { + println(String::class.supertypes) +} diff --git a/compiler/tests/org/jetbrains/kotlin/reflection/ReflectionIntegrationTest.kt b/compiler/tests/org/jetbrains/kotlin/reflection/ReflectionIntegrationTest.kt new file mode 100644 index 00000000000..cc74f6a3e89 --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/reflection/ReflectionIntegrationTest.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.reflection + +import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime +import org.jetbrains.kotlin.test.CompilerTestUtil +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase +import java.io.File +import java.util.concurrent.TimeUnit + +class ReflectionIntegrationTest : KtUsefulTestCase() { + // This test checks that we use the correct class loader to load .kotlin_builtins resource files. + // On Android, the class loader used to load the application classes differs from the boot class loader (which loads core JDK classes), + // so attempting to find kotlin/kotlin.kotlin_builtins in the same class loader that found java.lang.Object can fail. + // We should always use the class loader that loads stdlib class files to locate .kotlin_builtins resource files + fun testClassLoaderForBuiltIns() { + val tmpdir = KotlinTestUtils.tmpDirForTest(this) + + val root = KotlinTestUtils.getTestDataPathBase() + "/reflection/classLoaderForBuiltIns" + KotlinTestUtils.compileJavaFiles( + listOf(File("$root/Main.java")), + listOf("-d", tmpdir.absolutePath) + ) + + val lib = CompilerTestUtil.compileJvmLibrary(File("$root/test.kt")) + + val javaHome = System.getProperty("java.home") + val javaExe = File(javaHome, "bin/java.exe").takeIf(File::exists) + ?: File(javaHome, "bin/java").takeIf(File::exists) + ?: error("Can't find 'java' executable in $javaHome") + + val command = arrayOf( + javaExe.absolutePath, + "-ea", + "-classpath", + tmpdir.absolutePath, + "Main", + lib.absolutePath, + ForTestCompileRuntime.runtimeJarForTests().absolutePath, + ForTestCompileRuntime.reflectJarForTests().absolutePath + ) + + val process = ProcessBuilder(*command).inheritIO().start() + process.waitFor(1, TimeUnit.MINUTES) + assertEquals(0, process.exitValue()) + } +} diff --git a/core/descriptors.runtime/src/kotlin/reflect/jvm/internal/components/RuntimeModuleData.kt b/core/descriptors.runtime/src/kotlin/reflect/jvm/internal/components/RuntimeModuleData.kt index 98cfc58f3fc..45bcf3391f5 100644 --- a/core/descriptors.runtime/src/kotlin/reflect/jvm/internal/components/RuntimeModuleData.kt +++ b/core/descriptors.runtime/src/kotlin/reflect/jvm/internal/components/RuntimeModuleData.kt @@ -87,8 +87,11 @@ class RuntimeModuleData private constructor( binaryClassAnnotationAndConstantLoader, lazyJavaPackageFragmentProvider, notFoundClasses, RuntimeErrorReporter, LookupTracker.DO_NOTHING, ContractDeserializer.DEFAULT ) + + // .kotlin_builtins files should be found by the same class loader that loaded stdlib classes + val stdlibClassLoader = Unit::class.java.classLoader val builtinsProvider = JvmBuiltInsPackageFragmentProvider( - storageManager, reflectKotlinClassFinder, module, notFoundClasses, builtIns.settings, builtIns.settings, + storageManager, ReflectKotlinClassFinder(stdlibClassLoader), module, notFoundClasses, builtIns.settings, builtIns.settings, DeserializationConfiguration.Default )