Use abstract factory for reflection objects on JVM
Introduce an abstract factory class ReflectionFactory which is responsible for creating reflection objects (KClass, KProperty, ...). The meaningful implementation is located in "reflection.jvm" where KClassImpl/KPropertyImpl/... are accessible and can be instantiated. The default implementation will be used in the lite runtime with no reflection and will return nulls / throw exceptions there. Put all functions, calls to which are generated by JVM back-end, in one place: the class named Reflection which contains only static methods. Previously these functions were scattered across different files in module "reflection.jvm". The code using reflection may now be compiled against either runtime, but reflection features will work if and only if reflection is accessible at runtime
This commit is contained in:
@@ -2640,57 +2640,59 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
final ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
|
||||
final Method factoryMethod;
|
||||
if (receiverParameter != null) {
|
||||
Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_IMPL_TYPE, getType(Class.class)};
|
||||
Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_TYPE, getType(Class.class)};
|
||||
factoryMethod = descriptor.isVar()
|
||||
? method("mutableTopLevelExtensionProperty", K_MUTABLE_TOP_LEVEL_EXTENSION_PROPERTY_IMPL_TYPE, parameterTypes)
|
||||
: method("topLevelExtensionProperty", K_TOP_LEVEL_EXTENSION_PROPERTY_IMPL_TYPE, parameterTypes);
|
||||
? method("mutableTopLevelExtensionProperty", K_MUTABLE_TOP_LEVEL_EXTENSION_PROPERTY_TYPE, parameterTypes)
|
||||
: method("topLevelExtensionProperty", K_TOP_LEVEL_EXTENSION_PROPERTY_TYPE, parameterTypes);
|
||||
}
|
||||
else {
|
||||
Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_IMPL_TYPE};
|
||||
Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_TYPE};
|
||||
factoryMethod = descriptor.isVar()
|
||||
? method("mutableTopLevelVariable", K_MUTABLE_TOP_LEVEL_VARIABLE_IMPL_TYPE, parameterTypes)
|
||||
: method("topLevelVariable", K_TOP_LEVEL_VARIABLE_IMPL_TYPE, parameterTypes);
|
||||
? method("mutableTopLevelVariable", K_MUTABLE_TOP_LEVEL_VARIABLE_TYPE, parameterTypes)
|
||||
: method("topLevelVariable", K_TOP_LEVEL_VARIABLE_TYPE, parameterTypes);
|
||||
}
|
||||
|
||||
return StackValue.operation(factoryMethod.getReturnType(), new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
v.visitLdcInsn(descriptor.getName().asString());
|
||||
v.getstatic(packageClassInternalName, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, K_PACKAGE_IMPL_TYPE.getDescriptor());
|
||||
v.getstatic(packageClassInternalName, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, K_PACKAGE_TYPE.getDescriptor());
|
||||
|
||||
if (receiverParameter != null) {
|
||||
putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter));
|
||||
}
|
||||
|
||||
v.invokestatic(REFLECTION_INTERNAL_PACKAGE, factoryMethod.getName(), factoryMethod.getDescriptor(), false);
|
||||
v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false);
|
||||
return Unit.INSTANCE$;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue generateMemberPropertyReference(@NotNull final VariableDescriptor descriptor, @NotNull final ClassDescriptor containingClass) {
|
||||
final Type classAsmType = typeMapper.mapClass(containingClass);
|
||||
|
||||
private StackValue generateMemberPropertyReference(
|
||||
@NotNull final VariableDescriptor descriptor,
|
||||
@NotNull final ClassDescriptor containingClass
|
||||
) {
|
||||
final Method factoryMethod = descriptor.isVar()
|
||||
? method("mutableMemberProperty", K_MUTABLE_MEMBER_PROPERTY_TYPE, JAVA_STRING_TYPE)
|
||||
: method("memberProperty", K_MEMBER_PROPERTY_TYPE, JAVA_STRING_TYPE);
|
||||
? method("mutableMemberProperty", K_MUTABLE_MEMBER_PROPERTY_TYPE, JAVA_STRING_TYPE, K_CLASS_TYPE)
|
||||
: method("memberProperty", K_MEMBER_PROPERTY_TYPE, JAVA_STRING_TYPE, K_CLASS_TYPE);
|
||||
|
||||
return StackValue.operation(factoryMethod.getReturnType(), new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
v.visitLdcInsn(descriptor.getName().asString());
|
||||
|
||||
Type classAsmType = typeMapper.mapClass(containingClass);
|
||||
|
||||
if (containingClass instanceof JavaClassDescriptor) {
|
||||
v.aconst(classAsmType);
|
||||
v.invokestatic(REFLECTION_INTERNAL_PACKAGE, "foreignKotlinClass",
|
||||
Type.getMethodDescriptor(K_CLASS_IMPL_TYPE, getType(Class.class)), false);
|
||||
v.invokestatic(REFLECTION, "foreignKotlinClass", Type.getMethodDescriptor(K_CLASS_TYPE, getType(Class.class)), false);
|
||||
}
|
||||
else {
|
||||
v.getstatic(classAsmType.getInternalName(), JvmAbi.KOTLIN_CLASS_FIELD_NAME, K_CLASS_IMPL_TYPE.getDescriptor());
|
||||
v.getstatic(classAsmType.getInternalName(), JvmAbi.KOTLIN_CLASS_FIELD_NAME, K_CLASS_TYPE.getDescriptor());
|
||||
}
|
||||
|
||||
|
||||
v.visitLdcInsn(descriptor.getName().asString());
|
||||
v.invokevirtual(K_CLASS_IMPL_TYPE.getInternalName(), factoryMethod.getName(), factoryMethod.getDescriptor(), false);
|
||||
v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false);
|
||||
|
||||
return Unit.INSTANCE$;
|
||||
}
|
||||
|
||||
@@ -405,7 +405,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
return;
|
||||
}
|
||||
|
||||
generateReflectionObjectField(state, classAsmType, v, method("kClassFromKotlin", K_CLASS_IMPL_TYPE, getType(Class.class)),
|
||||
generateReflectionObjectField(state, classAsmType, v, method("createKotlinClass", K_CLASS_TYPE, getType(Class.class)),
|
||||
JvmAbi.KOTLIN_CLASS_FIELD_NAME, createOrGetClInitCodegen().v);
|
||||
}
|
||||
|
||||
|
||||
@@ -447,7 +447,7 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
|
||||
|
||||
v.aconst(thisAsmType);
|
||||
v.invokestatic(REFLECTION_INTERNAL_PACKAGE, factory.getName(), factory.getDescriptor(), false);
|
||||
v.invokestatic(REFLECTION, factory.getName(), factory.getDescriptor(), false);
|
||||
v.putstatic(thisAsmType.getInternalName(), fieldName, type);
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ import java.util.*;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.asmDescByFqNameWithoutInnerClasses;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.method;
|
||||
import static org.jetbrains.kotlin.load.kotlin.PackageClassUtils.getPackageClassFqName;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.K_PACKAGE_IMPL_TYPE;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.K_PACKAGE_TYPE;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.getType;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
||||
@@ -253,7 +253,7 @@ public class PackageCodegen {
|
||||
|
||||
private void generateKotlinPackageReflectionField() {
|
||||
MethodVisitor mv = v.newMethod(NO_ORIGIN, ACC_STATIC, "<clinit>", "()V", null, null);
|
||||
Method method = method("kPackage", K_PACKAGE_IMPL_TYPE, getType(Class.class));
|
||||
Method method = method("createKotlinPackage", K_PACKAGE_TYPE, getType(Class.class));
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
MemberCodegen.generateReflectionObjectField(state, packageClassType, v, method, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, iv);
|
||||
iv.areturn(Type.VOID_TYPE);
|
||||
|
||||
@@ -102,7 +102,7 @@ public class ScriptCodegen extends MemberCodegen<JetScript> {
|
||||
"java/lang/Object",
|
||||
ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
|
||||
generateReflectionObjectField(state, classType, v, method("kClassFromKotlin", K_CLASS_IMPL_TYPE, getType(Class.class)),
|
||||
generateReflectionObjectField(state, classType, v, method("createKotlinClass", K_CLASS_TYPE, getType(Class.class)),
|
||||
JvmAbi.KOTLIN_CLASS_FIELD_NAME, createOrGetClInitCodegen().v);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user