Reflection support
This commit is contained in:
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.backend.common;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import kotlin.KotlinPackage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.bridges.BridgesPackage;
|
||||
|
||||
@@ -38,6 +38,8 @@ import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.getMappingFileName;
|
||||
|
||||
public class ClassFileFactory implements OutputFileCollection {
|
||||
private final GenerationState state;
|
||||
private final ClassBuilderFactory builderFactory;
|
||||
@@ -86,7 +88,7 @@ public class ClassFileFactory implements OutputFileCollection {
|
||||
|
||||
private void writeModuleMappings(Collection<PackageCodegen> values) {
|
||||
String moduleName = KotlinPackage.removeSurrounding(state.getModule().getName().asString(), "<", ">");
|
||||
String outputFilePath = "META-INF/" + moduleName + ".kotlin_module";
|
||||
String outputFilePath = getMappingFileName(moduleName);
|
||||
final StringWriter moduleMapping = new StringWriter(1024);
|
||||
for (PackageCodegen codegen : values) {
|
||||
codegen.getFacades().serialize(moduleMapping);
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.codegen;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFile;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.List;
|
||||
@@ -32,6 +34,15 @@ public class GeneratedClassLoader extends URLClassLoader {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceAsStream(String name) {
|
||||
OutputFile outputFile = factory.get(name);
|
||||
if (outputFile != null) {
|
||||
return new ByteArrayInputStream(outputFile.asByteArray());
|
||||
}
|
||||
return super.getResourceAsStream(name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<?> findClass(@NotNull String name) throws ClassNotFoundException {
|
||||
|
||||
@@ -245,4 +245,13 @@ public class JvmCodegenUtil {
|
||||
module == module.getBuiltIns().getBuiltInsModule() ||
|
||||
DescriptorUtils.isAnnotationClass(descriptor);
|
||||
}
|
||||
|
||||
public static String getModuleName(ModuleDescriptor module) {
|
||||
return KotlinPackage.removeSurrounding(module.getName().asString(), "<", ">");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getMappingFileName(@NotNull String moduleName) {
|
||||
return "META-INF/" + moduleName + ".kotlin_module";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,6 +467,9 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
|
||||
|
||||
v.aconst(thisAsmType);
|
||||
if (factory.getArgumentTypes().length == 2) {
|
||||
v.aconst(JvmCodegenUtil.getModuleName(state.getModule()));
|
||||
}
|
||||
v.invokestatic(REFLECTION, factory.getName(), factory.getDescriptor(), false);
|
||||
v.putstatic(thisAsmType.getInternalName(), fieldName, type);
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ public class PackageCodegen {
|
||||
|
||||
private void generateKotlinPackageReflectionField() {
|
||||
MethodVisitor mv = v.newMethod(NO_ORIGIN, ACC_STATIC, "<clinit>", "()V", null, null);
|
||||
Method method = method("createKotlinPackage", K_PACKAGE_TYPE, getType(Class.class));
|
||||
Method method = method("createKotlinPackage", K_PACKAGE_TYPE, getType(Class.class), getType(String.class));
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
MemberCodegen.generateReflectionObjectField(state, packageClassType, v, method, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, iv);
|
||||
iv.areturn(Type.VOID_TYPE);
|
||||
|
||||
+3
-3
@@ -82,7 +82,7 @@ public abstract class AbstractJvmRuntimeDescriptorLoaderTest : TestCaseWithTmpdi
|
||||
|
||||
val classLoader = URLClassLoader(arrayOf(tmpdir.toURI().toURL()), ForTestCompileRuntime.runtimeAndReflectJarClassLoader())
|
||||
|
||||
val actual = createReflectedPackageView(classLoader)
|
||||
val actual = createReflectedPackageView(classLoader, "")
|
||||
|
||||
val expected = LoadDescriptorUtil.loadTestPackageAndBindingContextFromJavaRoot(
|
||||
tmpdir, getTestRootDisposable(), jdkKind, ConfigurationKind.ALL, true
|
||||
@@ -129,8 +129,8 @@ public abstract class AbstractJvmRuntimeDescriptorLoaderTest : TestCaseWithTmpdi
|
||||
}
|
||||
}
|
||||
|
||||
private fun createReflectedPackageView(classLoader: URLClassLoader): SyntheticPackageViewForTest {
|
||||
val module = RuntimeModuleData.create(classLoader).module
|
||||
private fun createReflectedPackageView(classLoader: URLClassLoader, moduleName: String): SyntheticPackageViewForTest {
|
||||
val module = RuntimeModuleData.create(classLoader, moduleName).module
|
||||
|
||||
|
||||
val generatedPackageDir = File(tmpdir, LoadDescriptorUtil.TEST_PACKAGE_FQNAME.pathSegments().single().asString())
|
||||
|
||||
+4
-2
@@ -44,7 +44,7 @@ public class RuntimeModuleData private constructor(public val deserialization: D
|
||||
public val localClassResolver: LocalClassResolver get() = deserialization.localClassResolver
|
||||
|
||||
companion object {
|
||||
public fun create(classLoader: ClassLoader): RuntimeModuleData {
|
||||
public fun create(classLoader: ClassLoader, moduleName: String?): RuntimeModuleData {
|
||||
val storageManager = LockBasedStorageManager()
|
||||
val module = ModuleDescriptorImpl(Name.special("<runtime module for $classLoader>"), storageManager,
|
||||
ModuleParameters(listOf(), JavaToKotlinClassMap.INSTANCE))
|
||||
@@ -57,8 +57,10 @@ public class RuntimeModuleData private constructor(public val deserialization: D
|
||||
ExternalAnnotationResolver.EMPTY, ExternalSignatureResolver.DO_NOTHING, RuntimeErrorReporter, JavaResolverCache.EMPTY,
|
||||
JavaPropertyInitializerEvaluator.DoNothing, SamConversionResolver, RuntimeSourceElementFactory, singleModuleClassResolver
|
||||
)
|
||||
println("moduleName $moduleName")
|
||||
val lazyJavaPackageFragmentProvider =
|
||||
LazyJavaPackageFragmentProvider(globalJavaResolverContext, module, ReflectionTypes(module), PackageMappingProvider.EMPTY)
|
||||
LazyJavaPackageFragmentProvider(globalJavaResolverContext, module, ReflectionTypes(module),
|
||||
if (moduleName == null) PackageMappingProvider.EMPTY else RuntimePackageMappingProvider(moduleName, classLoader))
|
||||
val javaDescriptorResolver = JavaDescriptorResolver(lazyJavaPackageFragmentProvider, module)
|
||||
val javaClassDataFinder = JavaClassDataFinder(reflectKotlinClassFinder, deserializedDescriptorResolver)
|
||||
val binaryClassAnnotationAndConstantLoader = BinaryClassAnnotationAndConstantLoaderImpl(module, storageManager, reflectKotlinClassFinder, RuntimeErrorReporter)
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.load.kotlin.reflect
|
||||
|
||||
import org.jetbrains.kotlin.load.java.lazy.PackageMappingProvider
|
||||
import org.jetbrains.kotlin.load.kotlin.ModuleMapping
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageFacades
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
class RuntimePackageMappingProvider(val moduleName: String, val classLoader : ClassLoader) : PackageMappingProvider {
|
||||
|
||||
val mapping: ModuleMapping by lazy {
|
||||
print("finding metainf for $moduleName")
|
||||
val resourceAsStream = classLoader.getResourceAsStream("META-INF/$moduleName.kotlin_module") ?: return@lazy ModuleMapping("")
|
||||
|
||||
print("OK")
|
||||
|
||||
try {
|
||||
val out = ByteArrayOutputStream(4096);
|
||||
val buffer = ByteArray(4096);
|
||||
while (true) {
|
||||
val r = resourceAsStream.read(buffer);
|
||||
if (r == -1) break;
|
||||
out.write(buffer, 0, r);
|
||||
}
|
||||
|
||||
val ret = out.toByteArray();
|
||||
return@lazy ModuleMapping(String(ret, "UTF-8"))
|
||||
} finally {
|
||||
resourceAsStream.close()
|
||||
}
|
||||
}
|
||||
|
||||
override fun findPackageMembers(packageName: String): List<String> {
|
||||
print("finding $packageName")
|
||||
return mapping.package2MiniFacades.getOrElse (packageName, { PackageFacades("default") }).parts.toList()
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ import kotlin.reflect.KotlinReflectionInternalError
|
||||
abstract class KDeclarationContainerImpl : ClassBasedDeclarationContainer {
|
||||
// Note: this is stored here on a soft reference to prevent GC from destroying the weak reference to it in the moduleByClassLoader cache
|
||||
val moduleData by ReflectProperties.lazySoft {
|
||||
jClass.getOrCreateModule()
|
||||
jClass.getOrCreateModule(null)
|
||||
}
|
||||
|
||||
abstract val constructorDescriptors: Collection<ConstructorDescriptor>
|
||||
|
||||
@@ -27,9 +27,9 @@ import kotlin.jvm.internal.KotlinPackage
|
||||
import kotlin.reflect.KCallable
|
||||
import kotlin.reflect.KPackage
|
||||
|
||||
class KPackageImpl(override val jClass: Class<*>) : KDeclarationContainerImpl(), KPackage {
|
||||
class KPackageImpl(override val jClass: Class<*>, val moduleName: String) : KDeclarationContainerImpl(), KPackage {
|
||||
val descriptor by ReflectProperties.lazySoft {
|
||||
val moduleData = jClass.getOrCreateModule()
|
||||
val moduleData = jClass.getOrCreateModule(moduleName)
|
||||
val fqName = jClass.classId.getPackageFqName()
|
||||
|
||||
moduleData.module.getPackage(fqName)
|
||||
|
||||
@@ -32,7 +32,12 @@ public class ReflectionFactoryImpl extends ReflectionFactory {
|
||||
|
||||
@Override
|
||||
public KPackage createKotlinPackage(Class javaClass) {
|
||||
return new KPackageImpl(javaClass);
|
||||
return createKotlinPackage(javaClass, "undefined");
|
||||
}
|
||||
|
||||
@Override
|
||||
public KPackage createKotlinPackage(Class javaClass, String moduleName) {
|
||||
return new KPackageImpl(javaClass, moduleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -44,7 +44,7 @@ private class WeakClassLoaderBox(classLoader: ClassLoader) {
|
||||
ref.get()?.let { it.toString() } ?: "<null>"
|
||||
}
|
||||
|
||||
internal fun Class<*>.getOrCreateModule(): RuntimeModuleData {
|
||||
internal fun Class<*>.getOrCreateModule(moduleName: String?): RuntimeModuleData {
|
||||
val classLoader = this.safeClassLoader
|
||||
val key = WeakClassLoaderBox(classLoader)
|
||||
|
||||
@@ -54,7 +54,7 @@ internal fun Class<*>.getOrCreateModule(): RuntimeModuleData {
|
||||
moduleByClassLoader.remove(key, cached)
|
||||
}
|
||||
|
||||
val module = RuntimeModuleData.create(classLoader)
|
||||
val module = RuntimeModuleData.create(classLoader, moduleName)
|
||||
try {
|
||||
while (true) {
|
||||
val ref = moduleByClassLoader.putIfAbsent(key, WeakReference(module))
|
||||
|
||||
@@ -94,7 +94,7 @@ public val KType.javaType: Type
|
||||
*/
|
||||
public val Class<*>.kotlinPackage: KPackage?
|
||||
get() = if (getSimpleName().endsWith("Package") &&
|
||||
getAnnotation(javaClass<kotlin.jvm.internal.KotlinPackage>()) != null) KPackageImpl(this) else null
|
||||
getAnnotation(javaClass<kotlin.jvm.internal.KotlinPackage>()) != null) KPackageImpl(this, "undefined") else null
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,6 +55,10 @@ public class Reflection {
|
||||
return factory.createKotlinPackage(javaClass);
|
||||
}
|
||||
|
||||
public static KPackage createKotlinPackage(Class javaClass, String moduleName) {
|
||||
return factory.createKotlinPackage(javaClass, moduleName);
|
||||
}
|
||||
|
||||
public static KClass foreignKotlinClass(Class javaClass) {
|
||||
return factory.foreignKotlinClass(javaClass);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ public class ReflectionFactory {
|
||||
return null;
|
||||
}
|
||||
|
||||
public KPackage createKotlinPackage(Class javaClass, String moduleName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public KClass foreignKotlinClass(Class javaClass) {
|
||||
return new ClassReference(javaClass);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user