From 9ba6d91e2e0b02ef9503c5aac259962e04aa91d9 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 21 May 2015 05:00:12 +0300 Subject: [PATCH] Prepare JVM runtime for support of reflection on functions Introduce abstract class FunctionReference, which is supposed to be a superclass for all anonymous classes generated for function references. Each anonymous subclass will have statically-generated symbol info, which will be used by reflection to locate the symbol --- .../kotlin/codegen/ClosureCodegen.java | 32 +++++++++- .../kotlin/codegen/ExpressionCodegen.java | 10 +-- .../kotlin/codegen/JvmRuntimeTypes.java | 61 +++---------------- .../kotlin/codegen/state/GenerationState.java | 5 +- .../kotlin/resolve/jvm/AsmTypes.java | 7 +++ .../src/kotlin/reflect/KLocalFunction.kt} | 10 +-- .../jvm/internal/ReflectionFactoryImpl.java | 10 +++ .../jvm/internal/ExtensionFunctionImpl.kt | 23 ------- .../jvm/internal/FunctionReference.java} | 15 ++--- .../kotlin/jvm/internal/MemberFunctionImpl.kt | 23 ------- .../src/kotlin/jvm/internal/Reflection.java | 8 +++ .../jvm/internal/ReflectionFactory.java | 8 +++ 12 files changed, 95 insertions(+), 117 deletions(-) rename core/{reflection.jvm/src/kotlin/reflect/jvm/internal/KExtensionFunctionImpl.kt => builtins/src/kotlin/reflect/KLocalFunction.kt} (76%) delete mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/ExtensionFunctionImpl.kt rename core/{reflection.jvm/src/kotlin/reflect/jvm/internal/KMemberFunctionImpl.kt => runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java} (68%) delete mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/MemberFunctionImpl.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index 22b86bbe97c..c780670753b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -53,6 +53,7 @@ import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass; import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass; 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.org.objectweb.asm.Opcodes.*; @@ -215,7 +216,10 @@ public class ClosureCodegen extends MemberCodegen { } @NotNull - public StackValue putInstanceOnStack(@NotNull final ExpressionCodegen codegen) { + public StackValue putInstanceOnStack( + @NotNull final ExpressionCodegen codegen, + @Nullable final FunctionDescriptor functionReferenceTarget + ) { return StackValue.operation(asmType, new Function1() { @Override public Unit invoke(InstructionAdapter v) { @@ -229,11 +233,37 @@ public class ClosureCodegen extends MemberCodegen { codegen.pushClosureOnStack(classDescriptor, true, codegen.defaultCallGenerator); v.invokespecial(asmType.getInternalName(), "", constructor.getDescriptor(), false); } + + if (functionReferenceTarget != null) { + equipFunctionReferenceWithReflection(v, functionReferenceTarget); + } + return Unit.INSTANCE$; } }); } + private static void equipFunctionReferenceWithReflection(@NotNull InstructionAdapter v, @NotNull FunctionDescriptor target) { + DeclarationDescriptor container = target.getContainingDeclaration(); + + Type type; + if (container instanceof PackageFragmentDescriptor) { + type = target.getExtensionReceiverParameter() != null + ? K_TOP_LEVEL_EXTENSION_FUNCTION + : K_TOP_LEVEL_FUNCTION; + } + else if (container instanceof ClassDescriptor) { + type = K_MEMBER_FUNCTION; + } + else { + type = K_LOCAL_FUNCTION; + } + + Method method = method("function", K_FUNCTION, FUNCTION_REFERENCE); + v.invokestatic(REFLECTION, method.getName(), method.getDescriptor(), false); + StackValue.coerce(K_FUNCTION, type, v); + } + private void generateConstInstance() { MethodVisitor mv = v.newMethod(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_SYNTHETIC, "", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 057e661efd1..de832feb6be 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1396,7 +1396,7 @@ public class ExpressionCodegen extends JetVisitor implem assert descriptor != null : "Function is not resolved to descriptor: " + declaration.getText(); return genClosure( - declaration, descriptor, new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration), samType, kind + declaration, descriptor, new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration), samType, kind, null ); } @@ -1406,7 +1406,8 @@ public class ExpressionCodegen extends JetVisitor implem @NotNull FunctionDescriptor descriptor, @NotNull FunctionGenerationStrategy strategy, @Nullable SamType samType, - @NotNull KotlinSyntheticClass.Kind kind + @NotNull KotlinSyntheticClass.Kind kind, + @Nullable FunctionDescriptor functionReferenceTarget ) { ClassBuilder cv = state.getFactory().newVisitor( OtherOrigin(declaration, descriptor), @@ -1425,7 +1426,7 @@ public class ExpressionCodegen extends JetVisitor implem propagateChildReifiedTypeParametersUsages(closureCodegen.getReifiedTypeParametersUsages()); } - return closureCodegen.putInstanceOnStack(this); + return closureCodegen.putInstanceOnStack(this, functionReferenceTarget); } @Override @@ -2702,7 +2703,8 @@ public class ExpressionCodegen extends JetVisitor implem FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); if (functionDescriptor != null) { FunctionReferenceGenerationStrategy strategy = new FunctionReferenceGenerationStrategy(state, functionDescriptor, resolvedCall); - return genClosure(expression, functionDescriptor, strategy, null, KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER); + return genClosure(expression, functionDescriptor, strategy, null, KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER, + (FunctionDescriptor) resolvedCall.getResultingDescriptor()); } VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java index e021f936e77..5db8904a904 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.codegen; import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.builtins.ReflectionTypes; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl; @@ -28,26 +27,19 @@ import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM; import org.jetbrains.kotlin.storage.LockBasedStorageManager; import org.jetbrains.kotlin.types.JetType; -import org.jetbrains.kotlin.types.JetTypeImpl; -import org.jetbrains.kotlin.types.TypeProjection; -import org.jetbrains.kotlin.types.TypeProjectionImpl; import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns; public class JvmRuntimeTypes { - private final ReflectionTypes reflectionTypes; - private final ClassDescriptor lambda; - private final ClassDescriptor functionImpl; - private final ClassDescriptor memberFunctionImpl; - private final ClassDescriptor extensionFunctionImpl; - - public JvmRuntimeTypes(@NotNull ReflectionTypes reflectionTypes) { - this.reflectionTypes = reflectionTypes; + private final ClassDescriptor functionReference; + public JvmRuntimeTypes() { ModuleDescriptorImpl module = new ModuleDescriptorImpl( Name.special(""), LockBasedStorageManager.NO_LOCKS, @@ -56,9 +48,7 @@ public class JvmRuntimeTypes { PackageFragmentDescriptor kotlinJvmInternal = new MutablePackageFragmentDescriptor(module, new FqName("kotlin.jvm.internal")); this.lambda = createClass(kotlinJvmInternal, "Lambda"); - this.functionImpl = createClass(kotlinJvmInternal, "FunctionImpl"); - this.memberFunctionImpl = createClass(kotlinJvmInternal, "MemberFunctionImpl"); - this.extensionFunctionImpl = createClass(kotlinJvmInternal, "ExtensionFunctionImpl"); + this.functionReference = createClass(kotlinJvmInternal, "FunctionReference"); } @NotNull @@ -95,41 +85,8 @@ public class JvmRuntimeTypes { ReceiverParameterDescriptor extensionReceiver = descriptor.getExtensionReceiverParameter(); ReceiverParameterDescriptor dispatchReceiver = descriptor.getDispatchReceiverParameter(); - List typeArguments = new ArrayList(2); - - ClassDescriptor kFunctionClass; - ClassDescriptor functionImplClass; - JetType receiverType; - if (extensionReceiver != null) { - functionImplClass = extensionFunctionImpl; - receiverType = extensionReceiver.getType(); - kFunctionClass = reflectionTypes.getkExtensionFunction(); - typeArguments.add(new TypeProjectionImpl(receiverType)); - } - else if (dispatchReceiver != null) { - functionImplClass = memberFunctionImpl; - receiverType = dispatchReceiver.getType(); - kFunctionClass = reflectionTypes.getkMemberFunction(); - typeArguments.add(new TypeProjectionImpl(receiverType)); - } - else { - functionImplClass = functionImpl; - receiverType = null; - kFunctionClass = reflectionTypes.getkFunction(); - } - - JetType functionImplType = functionImplClass.getDefaultType(); - - //noinspection ConstantConditions - typeArguments.add(new TypeProjectionImpl(descriptor.getReturnType())); - - JetType kFunctionType = new JetTypeImpl( - kFunctionClass.getDefaultType().getAnnotations(), - kFunctionClass.getTypeConstructor(), - false, - typeArguments, - kFunctionClass.getMemberScope(typeArguments) - ); + JetType receiverType = + extensionReceiver != null ? extensionReceiver.getType() : dispatchReceiver != null ? dispatchReceiver.getType() : null; //noinspection ConstantConditions JetType functionType = getBuiltIns(descriptor).getFunctionType( @@ -139,6 +96,6 @@ public class JvmRuntimeTypes { descriptor.getReturnType() ); - return Arrays.asList(functionImplType, kFunctionType, functionType); + return Arrays.asList(functionReference.getDefaultType(), functionType); } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.java index 75e5594fa32..bd7b4733228 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.java @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.state; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.builtins.ReflectionTypes; import org.jetbrains.kotlin.codegen.*; import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension; @@ -35,7 +36,6 @@ import org.jetbrains.kotlin.psi.JetScript; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.DelegatingBindingTrace; -import org.jetbrains.kotlin.builtins.ReflectionTypes; import java.io.File; import java.util.Collection; @@ -211,7 +211,8 @@ public class GenerationState { this.generateClassFilter = generateClassFilter; this.reflectionTypes = new ReflectionTypes(module); - this.runtimeTypes = new JvmRuntimeTypes(reflectionTypes); + this.runtimeTypes = new JvmRuntimeTypes(); + this.inlineCycleReporter = new InlineCycleReporter(diagnostics); } 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 891973af0c1..03608043f17 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 @@ -35,11 +35,18 @@ public class AsmTypes { public static final Type PROPERTY_METADATA_IMPL_TYPE = Type.getObjectType("kotlin/PropertyMetadataImpl"); public static final Type LAMBDA = Type.getObjectType("kotlin/jvm/internal/Lambda"); + public static final Type FUNCTION_REFERENCE = Type.getObjectType("kotlin/jvm/internal/FunctionReference"); 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_FUNCTION = reflect("KFunction"); + public static final Type K_TOP_LEVEL_FUNCTION = reflect("KTopLevelFunction"); + public static final Type K_MEMBER_FUNCTION = reflect("KMemberFunction"); + public static final Type K_TOP_LEVEL_EXTENSION_FUNCTION = reflect("KTopLevelExtensionFunction"); + public static final Type K_LOCAL_FUNCTION = reflect("KLocalFunction"); + public static final Type K_MEMBER_PROPERTY_TYPE = reflect("KMemberProperty"); public static final Type K_MUTABLE_MEMBER_PROPERTY_TYPE = reflect("KMutableMemberProperty"); public static final Type K_TOP_LEVEL_VARIABLE_TYPE = reflect("KTopLevelVariable"); diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KExtensionFunctionImpl.kt b/core/builtins/src/kotlin/reflect/KLocalFunction.kt similarity index 76% rename from core/reflection.jvm/src/kotlin/reflect/jvm/internal/KExtensionFunctionImpl.kt rename to core/builtins/src/kotlin/reflect/KLocalFunction.kt index a51c3ad6516..31a9aae20ee 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KExtensionFunctionImpl.kt +++ b/core/builtins/src/kotlin/reflect/KLocalFunction.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package kotlin.reflect.jvm.internal - -import kotlin.jvm.internal.ExtensionFunctionImpl +package kotlin.reflect /** - * @suppress + * Represents a local function. + * + * @param R the return type of the function. */ -public abstract class KExtensionFunctionImpl : ExtensionFunctionImpl() +public interface KLocalFunction : KFunction diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java index d811382e65c..59fbdc4b56b 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java @@ -16,6 +16,7 @@ package kotlin.reflect.jvm.internal; +import kotlin.jvm.internal.FunctionReference; import kotlin.jvm.internal.ReflectionFactory; import kotlin.reflect.*; @@ -39,6 +40,15 @@ public class ReflectionFactoryImpl extends ReflectionFactory { return InternalPackage.foreignKotlinClass(javaClass); } + // Functions + + @Override + public KFunction function(FunctionReference f) { + return f; + } + + // Properties + @Override public KMemberProperty memberProperty(String name, KClass owner) { return ((KClassImpl) owner).memberProperty(name); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/ExtensionFunctionImpl.kt b/core/runtime.jvm/src/kotlin/jvm/internal/ExtensionFunctionImpl.kt deleted file mode 100644 index 785369215e5..00000000000 --- a/core/runtime.jvm/src/kotlin/jvm/internal/ExtensionFunctionImpl.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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.jvm.internal - -import java.io.Serializable - -public abstract class ExtensionFunctionImpl : Serializable { - override fun toString() = "${(this as Object).getClass().getGenericInterfaces()[0]}" -} diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KMemberFunctionImpl.kt b/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java similarity index 68% rename from core/reflection.jvm/src/kotlin/reflect/jvm/internal/KMemberFunctionImpl.kt rename to core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java index c205784af91..31ab4de6e60 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KMemberFunctionImpl.kt +++ b/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReference.java @@ -14,13 +14,14 @@ * limitations under the License. */ -package kotlin.reflect.jvm.internal +package kotlin.jvm.internal; -import java.io.Serializable +import kotlin.reflect.*; -/** - * @suppress - */ -public abstract class KMemberFunctionImpl : Serializable { - override fun toString() = "${javaClass.getGenericInterfaces().first()}" +public abstract class FunctionReference + extends FunctionImpl + implements KTopLevelFunction, + KMemberFunction, + KTopLevelExtensionFunction, + KLocalFunction { } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/MemberFunctionImpl.kt b/core/runtime.jvm/src/kotlin/jvm/internal/MemberFunctionImpl.kt deleted file mode 100644 index cecb2b03baf..00000000000 --- a/core/runtime.jvm/src/kotlin/jvm/internal/MemberFunctionImpl.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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.jvm.internal - -import java.io.Serializable - -public abstract class MemberFunctionImpl : Serializable { - override fun toString() = "${(this as Object).getClass().getGenericInterfaces()[0]}" -} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/Reflection.java b/core/runtime.jvm/src/kotlin/jvm/internal/Reflection.java index 2531d5de3f3..6c48b3d55da 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/Reflection.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/Reflection.java @@ -59,6 +59,14 @@ public class Reflection { return factory.foreignKotlinClass(javaClass); } + // Functions + + public static KFunction function(FunctionReference f) { + return factory.function(f); + } + + // Properties + public static KMemberProperty memberProperty(String name, KClass owner) { return factory.memberProperty(name, owner); } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/ReflectionFactory.java b/core/runtime.jvm/src/kotlin/jvm/internal/ReflectionFactory.java index ef58a4f5fa5..431863234fa 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/ReflectionFactory.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/ReflectionFactory.java @@ -32,6 +32,14 @@ public class ReflectionFactory { throw error(); } + // Functions + + public KFunction function(FunctionReference f) { + return f; + } + + // Properties + public KMemberProperty memberProperty(String name, KClass owner) { throw error(); }