diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index d8906bdf2f7..9c3d1163253 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.kotlin.load.java.JvmAbi; +import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; import org.jetbrains.kotlin.psi.JetElement; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorUtils; @@ -46,6 +47,7 @@ import java.util.Collections; import java.util.List; import static org.jetbrains.kotlin.codegen.AsmUtil.*; +import static org.jetbrains.kotlin.codegen.ExpressionCodegen.generateClassLiteralReference; import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConst; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass; @@ -53,6 +55,7 @@ import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticC import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*; import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.OtherOrigin; +import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; import static org.jetbrains.org.objectweb.asm.Opcodes.*; public class ClosureCodegen extends MemberCodegen { @@ -61,6 +64,7 @@ public class ClosureCodegen extends MemberCodegen { private final SamType samType; private final JetType superClassType; private final List superInterfaceTypes; + private final FunctionDescriptor functionReferenceTarget; private final FunctionGenerationStrategy strategy; private final CalculatedClosure closure; private final Type asmType; @@ -76,6 +80,7 @@ public class ClosureCodegen extends MemberCodegen { @Nullable SamType samType, @NotNull ClosureContext context, @NotNull KotlinSyntheticClass.Kind syntheticClassKind, + @Nullable FunctionDescriptor functionReferenceTarget, @NotNull FunctionGenerationStrategy strategy, @NotNull MemberCodegen parentCodegen, @NotNull ClassBuilder classBuilder @@ -86,6 +91,7 @@ public class ClosureCodegen extends MemberCodegen { this.classDescriptor = context.getContextDescriptor(); this.samType = samType; this.syntheticClassKind = syntheticClassKind; + this.functionReferenceTarget = functionReferenceTarget; this.strategy = strategy; if (samType == null) { @@ -189,7 +195,11 @@ public class ClosureCodegen extends MemberCodegen { functionCodegen.generateBridges(descriptorForBridges); } - this.constructor = generateConstructor(superClassAsmType); + if (functionReferenceTarget != null) { + generateFunctionReferenceMethods(functionReferenceTarget); + } + + this.constructor = generateConstructor(); if (isConst(closure)) { generateConstInstance(); @@ -214,10 +224,7 @@ public class ClosureCodegen extends MemberCodegen { } @NotNull - public StackValue putInstanceOnStack( - @NotNull final ExpressionCodegen codegen, - @Nullable final FunctionDescriptor functionReferenceTarget - ) { + public StackValue putInstanceOnStack(@NotNull final ExpressionCodegen codegen) { return StackValue.operation(asmType, new Function1() { @Override public Unit invoke(InstructionAdapter v) { @@ -267,7 +274,8 @@ public class ClosureCodegen extends MemberCodegen { MethodVisitor mv = v.newMethod(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_SYNTHETIC, "", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY); InstructionAdapter iv = new InstructionAdapter(mv); - v.newField(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), null, null); + v.newField(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), + null, null); if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { mv.visitCode(); @@ -316,8 +324,78 @@ public class ClosureCodegen extends MemberCodegen { FunctionCodegen.endVisit(mv, "bridge", element); } + private void generateFunctionReferenceMethods(@NotNull FunctionDescriptor descriptor) { + int flags = ACC_PUBLIC | ACC_FINAL; + boolean generateBody = state.getClassBuilderMode() == ClassBuilderMode.FULL; + + { + MethodVisitor mv = + v.newMethod(NO_ORIGIN, flags, "getOwner", Type.getMethodDescriptor(K_DECLARATION_CONTAINER_TYPE), null, null); + if (generateBody) { + mv.visitCode(); + InstructionAdapter iv = new InstructionAdapter(mv); + generateFunctionReferenceDeclarationContainer(iv, descriptor, typeMapper); + iv.areturn(K_DECLARATION_CONTAINER_TYPE); + FunctionCodegen.endVisit(iv, "function reference getOwner", element); + } + } + + { + MethodVisitor mv = + v.newMethod(NO_ORIGIN, flags, "getName", Type.getMethodDescriptor(JAVA_STRING_TYPE), null, null); + if (generateBody) { + mv.visitCode(); + InstructionAdapter iv = new InstructionAdapter(mv); + iv.aconst(descriptor.getName().asString()); + iv.areturn(JAVA_STRING_TYPE); + FunctionCodegen.endVisit(iv, "function reference getName", element); + } + } + + { + MethodVisitor mv = v.newMethod(NO_ORIGIN, flags, "getSignature", Type.getMethodDescriptor(JAVA_STRING_TYPE), null, null); + if (generateBody) { + mv.visitCode(); + InstructionAdapter iv = new InstructionAdapter(mv); + Method method = typeMapper.mapSignature(descriptor).getAsmMethod(); + iv.aconst(method.getName() + method.getDescriptor()); + iv.areturn(JAVA_STRING_TYPE); + FunctionCodegen.endVisit(iv, "function reference getSignature", element); + } + } + } + + private static void generateFunctionReferenceDeclarationContainer( + @NotNull InstructionAdapter iv, + @NotNull FunctionDescriptor descriptor, + @NotNull JetTypeMapper typeMapper + ) { + DeclarationDescriptor container = descriptor.getContainingDeclaration(); + if (container instanceof ClassDescriptor) { + // TODO: getDefaultType() here is wrong and won't work for arrays + StackValue value = generateClassLiteralReference(typeMapper, ((ClassDescriptor) container).getDefaultType()); + value.put(K_CLASS_TYPE, iv); + } + else if (container instanceof PackageFragmentDescriptor) { + String packageClassInternalName = PackageClassUtils.getPackageClassInternalName( + ((PackageFragmentDescriptor) container).getFqName() + ); + iv.getstatic(packageClassInternalName, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, K_PACKAGE_TYPE.getDescriptor()); + } + else if (container instanceof ScriptDescriptor) { + // TODO: correct container for scripts (KScript?) + StackValue value = generateClassLiteralReference( + typeMapper, ((ScriptDescriptor) container).getClassDescriptor().getDefaultType() + ); + value.put(K_CLASS_TYPE, iv); + } + else { + iv.aconst(null); + } + } + @NotNull - private Method generateConstructor(@NotNull Type superClassAsmType) { + private Method generateConstructor() { List args = calculateConstructorParameters(typeMapper, closure, asmType); Type[] argTypes = fieldListToTypeArray(args); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 3bff774576d..1c1806566ba 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1429,7 +1429,8 @@ public class ExpressionCodegen extends JetVisitor implem ); ClosureCodegen closureCodegen = new ClosureCodegen( - state, declaration, samType, context.intoClosure(descriptor, this, typeMapper), kind, strategy, parentCodegen, cv + state, declaration, samType, context.intoClosure(descriptor, this, typeMapper), kind, + functionReferenceTarget, strategy, parentCodegen, cv ); closureCodegen.generate(); @@ -1439,7 +1440,7 @@ public class ExpressionCodegen extends JetVisitor implem propagateChildReifiedTypeParametersUsages(closureCodegen.getReifiedTypeParametersUsages()); } - return closureCodegen.putInstanceOnStack(this, functionReferenceTarget); + return closureCodegen.putInstanceOnStack(this); } @Override @@ -2741,7 +2742,7 @@ public class ExpressionCodegen extends JetVisitor implem assert state.getReflectionTypes().getkClass().getTypeConstructor().equals(type.getConstructor()) : "::class expression should be type checked to a KClass: " + type; - return generateClassLiteralReference(KotlinPackage.single(type.getArguments()).getType()); + return generateClassLiteralReference(typeMapper, KotlinPackage.single(type.getArguments()).getType()); } @Override @@ -2834,7 +2835,7 @@ public class ExpressionCodegen extends JetVisitor implem @Override public Unit invoke(InstructionAdapter v) { v.visitLdcInsn(descriptor.getName().asString()); - StackValue receiverClass = generateClassLiteralReference(containingClass.getDefaultType()); + StackValue receiverClass = generateClassLiteralReference(typeMapper, containingClass.getDefaultType()); receiverClass.put(receiverClass.type, v); v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false); @@ -2844,7 +2845,7 @@ public class ExpressionCodegen extends JetVisitor implem } @NotNull - private StackValue generateClassLiteralReference(@NotNull final JetType type) { + public static StackValue generateClassLiteralReference(@NotNull final JetTypeMapper typeMapper, @NotNull final JetType type) { return StackValue.operation(K_CLASS_TYPE, new Function1() { @Override public Unit invoke(InstructionAdapter v) { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java index 45aa7eed070..f174878ca74 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java @@ -40,6 +40,7 @@ public class AsmTypes { public static final Type K_CLASS_TYPE = reflect("KClass"); public static final Type K_CLASS_ARRAY_TYPE = Type.getObjectType("[" + K_CLASS_TYPE.getDescriptor()); public static final Type K_PACKAGE_TYPE = reflect("KPackage"); + public static final Type K_DECLARATION_CONTAINER_TYPE = reflect("KDeclarationContainer"); public static final Type K_FUNCTION = reflect("KFunction"); public static final Type K_TOP_LEVEL_FUNCTION = reflect("KTopLevelFunction"); diff --git a/core/builtins/src/kotlin/reflect/KClass.kt b/core/builtins/src/kotlin/reflect/KClass.kt index 12349130007..a12536a465a 100644 --- a/core/builtins/src/kotlin/reflect/KClass.kt +++ b/core/builtins/src/kotlin/reflect/KClass.kt @@ -24,7 +24,7 @@ package kotlin.reflect * * @param T the type of the class. */ -public interface KClass { +public interface KClass : KDeclarationContainer { /** * The simple name of the class as it was declared in the source code, * or `null` if the class has no name (if, for example, it is an anonymous object literal). diff --git a/core/builtins/src/kotlin/reflect/KDeclarationContainer.kt b/core/builtins/src/kotlin/reflect/KDeclarationContainer.kt new file mode 100644 index 00000000000..89e02989564 --- /dev/null +++ b/core/builtins/src/kotlin/reflect/KDeclarationContainer.kt @@ -0,0 +1,23 @@ +/* + * 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 kotlin.reflect + +/** + * Represents an entity which may contain declarations of any other entities, + * such as a class or a package. + */ +public interface KDeclarationContainer diff --git a/core/builtins/src/kotlin/reflect/KPackage.kt b/core/builtins/src/kotlin/reflect/KPackage.kt index 1f26a51565b..a2788d14ac9 100644 --- a/core/builtins/src/kotlin/reflect/KPackage.kt +++ b/core/builtins/src/kotlin/reflect/KPackage.kt @@ -19,4 +19,4 @@ package kotlin.reflect /** * Represents a package and provides introspection capabilities. */ -public interface KPackage +public interface KPackage : KDeclarationContainer diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt index 3c0ebd4b6e8..b9a91a3f4c7 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt @@ -30,8 +30,9 @@ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.JvmType.PrimitiveType. import java.lang.reflect.Field import java.lang.reflect.Method import kotlin.reflect.KotlinReflectionInternalError +import kotlin.reflect.KDeclarationContainer -abstract class KCallableContainerImpl { +abstract class KCallableContainerImpl : KDeclarationContainer { // 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() diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt index 33ea57638c5..42534413c73 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt @@ -18,7 +18,4 @@ package kotlin.reflect.jvm.internal import kotlin.jvm.internal.FunctionImpl -/** - * @suppress - */ -public abstract class KFunctionImpl : FunctionImpl() +abstract class KFunctionImpl : FunctionImpl() diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java b/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java index 32d6e321a45..2503e3da797 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java @@ -16,9 +16,10 @@ package kotlin.jvm.internal; +import kotlin.jvm.KotlinReflectionNotSupportedError; import kotlin.reflect.*; -public abstract class FunctionReference +public class FunctionReference extends FunctionImpl implements KTopLevelFunction, KMemberFunction, @@ -39,4 +40,30 @@ public abstract class FunctionReference public int getArity() { return arity; } + + // The following methods provide the information identifying this function, which is used by the reflection implementation. + // They are supposed to be overridden in each subclass (each anonymous class generated for a function reference). + + public KDeclarationContainer getOwner() { + throw error(); + } + + // Kotlin name of the function, the one which was declared in the source code (@platformName can't change it) + public String getName() { + throw error(); + } + + // JVM signature of the function, e.g. "println(Ljava/lang/Object;)V" + public String getSignature() { + throw error(); + } + + // The following methods are the stub implementations of reflection functions. + // They are called when you're using reflection on a function reference without the reflection implementation in the classpath. + + // (nothing here yet) + + private static Error error() { + throw new KotlinReflectionNotSupportedError(); + } }