diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index 280d2ba8c08..13bad96edf3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -14,7 +14,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.codegen.binding.CalculatedClosure; -import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.context.ClosureContext; import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor; import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt; @@ -25,7 +24,6 @@ import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.config.LanguageVersionSettings; import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; import org.jetbrains.kotlin.load.java.JvmAbi; @@ -53,6 +51,7 @@ import java.util.Collections; import java.util.List; import static org.jetbrains.kotlin.codegen.AsmUtil.*; +import static org.jetbrains.kotlin.codegen.CallableReferenceUtilKt.*; import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConst; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE; import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.initDefaultSourceMappingIfNeeded; @@ -408,70 +407,13 @@ public class ClosureCodegen extends MemberCodegen { if (generateBody) { mv.visitCode(); InstructionAdapter iv = new InstructionAdapter(mv); - PropertyReferenceCodegen.generateCallableReferenceSignature(iv, descriptor, state); + CallableReferenceUtilKt.generateCallableReferenceSignature(iv, descriptor, state); iv.areturn(JAVA_STRING_TYPE); FunctionCodegen.endVisit(iv, "function reference getSignature", element); } } } - // Returns false if null was generated. - public static boolean generateCallableReferenceDeclarationContainerClass( - @NotNull InstructionAdapter iv, - @NotNull CallableDescriptor descriptor, - @NotNull GenerationState state - ) { - KotlinTypeMapper typeMapper = state.getTypeMapper(); - DeclarationDescriptor container = descriptor.getContainingDeclaration(); - - if (container instanceof ClassDescriptor) { - // TODO: would it work for arrays? - SimpleType containerKotlinType = ((ClassDescriptor) container).getDefaultType(); - Type containerType = typeMapper.mapClass((ClassDescriptor) container); - putJavaLangClassInstance(iv, containerType, containerKotlinType, typeMapper); - } - else if (container instanceof PackageFragmentDescriptor) { - iv.aconst(typeMapper.mapOwner(descriptor)); - } - else if (descriptor instanceof VariableDescriptorWithAccessors) { - iv.aconst(state.getBindingContext().get( - CodegenBinding.DELEGATED_PROPERTY_METADATA_OWNER, ((VariableDescriptorWithAccessors) descriptor) - )); - } - else { - iv.aconst(null); - return false; - } - - return true; - } - - public static void generateCallableReferenceDeclarationContainer( - @NotNull InstructionAdapter iv, - @NotNull CallableDescriptor descriptor, - @NotNull GenerationState state - ) { - if (!generateCallableReferenceDeclarationContainerClass(iv, descriptor, state)) return; - - if (isTopLevelCallableReference(descriptor)) { - // Note that this name is not used in reflection. There should be the name of the referenced declaration's module instead, - // but there's no nice API to obtain that name here yet - // TODO: write the referenced declaration's module name and use it in reflection - iv.aconst(state.getModuleName()); - iv.invokestatic(REFLECTION, "getOrCreateKotlinPackage", - Type.getMethodDescriptor(K_DECLARATION_CONTAINER_TYPE, getType(Class.class), getType(String.class)), false); - } - else { - wrapJavaClassIntoKClass(iv); - } - } - - public static boolean isTopLevelCallableReference(@NotNull CallableDescriptor descriptor) { - return descriptor instanceof LocalVariableDescriptor - ? DescriptorUtils.getParentOfType(descriptor, ClassDescriptor.class) == null - : descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor; - } - @NotNull protected Method generateConstructor() { List args = calculateConstructorParameters(typeMapper, state.getLanguageVersionSettings(), closure, asmType); @@ -511,8 +453,7 @@ public class ClosureCodegen extends MemberCodegen { if (superClassAsmType.equals(LAMBDA) || functionReferenceTarget != null || CoroutineCodegenUtilKt.isCoroutineSuperClass(state.getLanguageVersionSettings(), superClassAsmType.getInternalName()) ) { - int arity = calculateArity(); - iv.iconst(arity); + iv.iconst(CodegenUtilKt.getArity(funDescriptor)); superCtorArgTypes.add(Type.INT_TYPE); if (shouldHaveBoundReferenceReceiver) { CallableReferenceUtilKt.loadBoundReferenceReceiverParameter( @@ -524,9 +465,9 @@ public class ClosureCodegen extends MemberCodegen { assert functionReferenceTarget != null : "No function reference target: " + funDescriptor; generateCallableReferenceDeclarationContainerClass(iv, functionReferenceTarget, state); iv.aconst(functionReferenceTarget.getName().asString()); - PropertyReferenceCodegen.generateCallableReferenceSignature(iv, functionReferenceTarget, state); + CallableReferenceUtilKt.generateCallableReferenceSignature(iv, functionReferenceTarget, state); int flags = - (isTopLevelCallableReference(functionReferenceTarget) ? 1 : 0) + + getCallableReferenceTopLevelFlag(functionReferenceTarget) + (calculateFunctionReferenceFlags(functionReferenceCall, funDescriptor) << 1); iv.aconst(flags); superCtorArgTypes.add(JAVA_CLASS_TYPE); @@ -585,13 +526,6 @@ public class ClosureCodegen extends MemberCodegen { ((hasCoercionToUnit ? 1 : 0) << 2); } - protected int calculateArity() { - int arity = funDescriptor.getValueParameters().size(); - if (funDescriptor.getExtensionReceiverParameter() != null) arity++; - if (funDescriptor.getDispatchReceiverParameter() != null) arity++; - return arity; - } - @NotNull public static List calculateConstructorParameters( @NotNull KotlinTypeMapper typeMapper, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java index 28fbcef80a0..752bc8b408a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java @@ -663,21 +663,21 @@ public abstract class MemberCodegen superCtorArgTypes = new ArrayList<>(); if (generateClassIntCtorCall) { - ClosureCodegen.generateCallableReferenceDeclarationContainerClass(iv, property, state); + CallableReferenceUtilKt.generateCallableReferenceDeclarationContainerClass(iv, property, state); superCtorArgTypes.add(JAVA_CLASS_TYPE); } else { // TODO: generate the container once and save to a local field instead (KT-10495) - ClosureCodegen.generateCallableReferenceDeclarationContainer(iv, property, state); + CallableReferenceUtilKt.generateCallableReferenceDeclarationContainer(iv, property, state); superCtorArgTypes.add(K_DECLARATION_CONTAINER_TYPE); } iv.aconst(property.getName().asString()); - PropertyReferenceCodegen.generateCallableReferenceSignature(iv, property, state); + CallableReferenceUtilKt.generateCallableReferenceSignature(iv, property, state); superCtorArgTypes.add(JAVA_STRING_TYPE); superCtorArgTypes.add(JAVA_STRING_TYPE); if (generateClassIntCtorCall) { - iv.aconst(ClosureCodegen.isTopLevelCallableReference(property) ? 1 : 0); + iv.aconst(CallableReferenceUtilKt.getCallableReferenceTopLevelFlag(property)); superCtorArgTypes.add(Type.INT_TYPE); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt index 25ac04aff65..df5d418a810 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt @@ -23,18 +23,17 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.context.ClassContext import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.resolve.* +import org.jetbrains.kotlin.resolve.PropertyImportedFromObject import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny +import org.jetbrains.kotlin.resolve.isUnderlyingPropertyOfInlineClass import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature -import org.jetbrains.kotlin.resolve.jvm.shouldHideConstructorDueToInlineClassTypeValueParameters import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlin.util.OperatorNameConventions @@ -122,7 +121,7 @@ class PropertyReferenceCodegen( generateCallableReferenceSignature(this, target, state) } generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) { - ClosureCodegen.generateCallableReferenceDeclarationContainer(this, target, state) + generateCallableReferenceDeclarationContainer(this, target, state) } } @@ -147,10 +146,10 @@ class PropertyReferenceCodegen( } if (isOptimizedPropertyReferenceSupertype(superAsmType)) { - ClosureCodegen.generateCallableReferenceDeclarationContainerClass(this, target, state) + generateCallableReferenceDeclarationContainerClass(this, target, state) aconst(target.name.asString()) generateCallableReferenceSignature(this, target, state) - aconst(if (ClosureCodegen.isTopLevelCallableReference(target)) 1 else 0) + aconst(getCallableReferenceTopLevelFlag(target)) superCtorArgTypes.add(JAVA_CLASS_TYPE) superCtorArgTypes.add(JAVA_STRING_TYPE) superCtorArgTypes.add(JAVA_STRING_TYPE) @@ -229,7 +228,6 @@ class PropertyReferenceCodegen( } companion object { - @JvmField val ANY_SUBSTITUTOR = TypeSubstitutor.create(object : TypeSubstitution() { override fun get(key: KotlinType): TypeProjection? { @@ -240,46 +238,6 @@ class PropertyReferenceCodegen( } }) - @JvmStatic - fun generateCallableReferenceSignature(iv: InstructionAdapter, callable: CallableDescriptor, state: GenerationState) { - iv.aconst(getSignatureString(callable, state)) - } - - @JvmStatic - fun getSignatureString(callable: CallableDescriptor, state: GenerationState): String { - if (callable is LocalVariableDescriptor) { - val asmType = state.bindingContext.get(CodegenBinding.DELEGATED_PROPERTY_METADATA_OWNER, callable) - ?: throw AssertionError("No delegated property metadata owner for $callable") - val localDelegatedProperties = CodegenBinding.getLocalDelegatedProperties(state.bindingContext, asmType) - val index = localDelegatedProperties?.indexOf(callable) ?: -1 - if (index < 0) { - throw AssertionError("Local delegated property is not found in $asmType: $callable") - } - return "" - } - - val accessor = when (callable) { - is ClassConstructorDescriptor -> - if (shouldHideConstructorDueToInlineClassTypeValueParameters(callable)) - AccessorForConstructorDescriptor(callable, callable.containingDeclaration, null, AccessorKind.NORMAL) - else - callable - is FunctionDescriptor -> callable - is VariableDescriptorWithAccessors -> - callable.getter ?: DescriptorFactory.createDefaultGetter(callable as PropertyDescriptor, Annotations.EMPTY).apply { - initialize(callable.type) - } - else -> error("Unsupported callable reference: $callable") - } - val declaration = DescriptorUtils.unwrapFakeOverride(accessor).original - val method = - if (callable.containingDeclaration.isInlineClass() && !declaration.isGetterOfUnderlyingPropertyOfInlineClass()) - state.typeMapper.mapSignatureForInlineErasedClassSkipGeneric(declaration).asmMethod - else - state.typeMapper.mapAsmMethod(declaration) - return method.name + method.descriptor - } - @JvmStatic fun getWrapperMethodForPropertyReference(property: VariableDescriptor, receiverCount: Int): Method { return when (receiverCount) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/callableReferenceUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/callableReferenceUtil.kt index 647c6b2c402..34476056507 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/callableReferenceUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/callableReferenceUtil.kt @@ -17,12 +17,18 @@ package org.jetbrains.kotlin.codegen import org.jetbrains.kotlin.codegen.binding.CalculatedClosure -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ConstructorDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.codegen.binding.CodegenBinding +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.psi.KtCallableReferenceExpression +import org.jetbrains.kotlin.resolve.DescriptorFactory import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.isGetterOfUnderlyingPropertyOfInlineClass +import org.jetbrains.kotlin.resolve.isInlineClass import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.resolve.jvm.shouldHideConstructorDueToInlineClassTypeValueParameters import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.builtIns @@ -102,3 +108,100 @@ fun computeExpectedNumberOfReceivers(referencedFunction: FunctionDescriptor, isB return receivers } + +// Returns false if null was generated. +internal fun generateCallableReferenceDeclarationContainerClass( + iv: InstructionAdapter, + descriptor: CallableDescriptor, + state: GenerationState +): Boolean { + val typeMapper = state.typeMapper + val container = descriptor.containingDeclaration + when { + container is ClassDescriptor -> { + // TODO: would it work for arrays? + val containerKotlinType = container.defaultType + val containerType = typeMapper.mapClass(container) + AsmUtil.putJavaLangClassInstance(iv, containerType, containerKotlinType, typeMapper) + } + container is PackageFragmentDescriptor -> { + iv.aconst(typeMapper.mapOwner(descriptor)) + } + descriptor is VariableDescriptorWithAccessors -> { + iv.aconst(state.bindingContext[CodegenBinding.DELEGATED_PROPERTY_METADATA_OWNER, descriptor]) + } + else -> { + iv.aconst(null) + return false + } + } + return true +} + +internal fun generateCallableReferenceDeclarationContainer( + iv: InstructionAdapter, + descriptor: CallableDescriptor, + state: GenerationState +) { + if (!generateCallableReferenceDeclarationContainerClass(iv, descriptor, state)) return + if (isTopLevelCallableReference(descriptor)) { + // Note that this name is not used in reflection. There should be the name of the referenced declaration's module instead, + // but there's no nice API to obtain that name here yet + // TODO: write the referenced declaration's module name and use it in reflection + iv.aconst(state.moduleName) + iv.invokestatic( + AsmTypes.REFLECTION, "getOrCreateKotlinPackage", + Type.getMethodDescriptor( + AsmTypes.K_DECLARATION_CONTAINER_TYPE, AsmTypes.getType(Class::class.java), AsmTypes.getType(String::class.java) + ), false + ) + } else { + AsmUtil.wrapJavaClassIntoKClass(iv) + } +} + +private fun isTopLevelCallableReference(descriptor: CallableDescriptor): Boolean = + if (descriptor is LocalVariableDescriptor) + DescriptorUtils.getParentOfType(descriptor, ClassDescriptor::class.java) == null + else descriptor.containingDeclaration is PackageFragmentDescriptor + +internal fun getCallableReferenceTopLevelFlag(descriptor: CallableDescriptor): Int = + if (isTopLevelCallableReference(descriptor)) 1 else 0 + +internal fun generateCallableReferenceSignature(iv: InstructionAdapter, callable: CallableDescriptor, state: GenerationState) { + iv.aconst(getSignatureString(callable, state)) +} + +private fun getSignatureString(callable: CallableDescriptor, state: GenerationState): String { + if (callable is LocalVariableDescriptor) { + val asmType = state.bindingContext.get(CodegenBinding.DELEGATED_PROPERTY_METADATA_OWNER, callable) + ?: throw AssertionError("No delegated property metadata owner for $callable") + val localDelegatedProperties = CodegenBinding.getLocalDelegatedProperties(state.bindingContext, asmType) + val index = localDelegatedProperties?.indexOf(callable) ?: -1 + if (index < 0) { + throw AssertionError("Local delegated property is not found in $asmType: $callable") + } + return "" + } + + val accessor = when (callable) { + is ClassConstructorDescriptor -> + if (shouldHideConstructorDueToInlineClassTypeValueParameters(callable)) + AccessorForConstructorDescriptor(callable, callable.containingDeclaration, null, AccessorKind.NORMAL) + else + callable + is FunctionDescriptor -> callable + is VariableDescriptorWithAccessors -> + callable.getter ?: DescriptorFactory.createDefaultGetter(callable as PropertyDescriptor, Annotations.EMPTY).apply { + initialize(callable.type) + } + else -> error("Unsupported callable reference: $callable") + } + val declaration = DescriptorUtils.unwrapFakeOverride(accessor).original + val method = + if (callable.containingDeclaration.isInlineClass() && !declaration.isGetterOfUnderlyingPropertyOfInlineClass()) + state.typeMapper.mapSignatureForInlineErasedClassSkipGeneric(declaration).asmMethod + else + state.typeMapper.mapAsmMethod(declaration) + return method.name + method.descriptor +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt index 06356031dd0..f36ffcd7b0d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.codegen import com.intellij.psi.PsiElement -import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.UnsignedTypes import org.jetbrains.kotlin.codegen.binding.CodegenBinding @@ -18,7 +17,6 @@ import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspend import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX import org.jetbrains.kotlin.codegen.inline.ReificationArgument import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics -import org.jetbrains.kotlin.codegen.optimization.common.asSequence import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.config.ApiVersion @@ -62,12 +60,6 @@ import org.jetbrains.org.objectweb.asm.Opcodes.* import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.Method -import org.jetbrains.org.objectweb.asm.tree.MethodNode -import org.jetbrains.org.objectweb.asm.util.Textifier -import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor -import java.io.PrintWriter -import java.io.StringWriter -import java.util.* fun generateIsCheck( v: InstructionAdapter, @@ -320,6 +312,11 @@ fun MemberDescriptor.isToArrayFromCollection(): Boolean { return isGenericToArray() || isNonGenericToArray() } +val CallableDescriptor.arity: Int + get() = valueParameters.size + + (if (extensionReceiverParameter != null) 1 else 0) + + (if (dispatchReceiverParameter != null) 1 else 0) + fun FqName.topLevelClassInternalName() = JvmClassName.byClassId(ClassId(parent(), shortName())).internalName fun FqName.topLevelClassAsmType(): Type = Type.getObjectType(topLevelClassInternalName()) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt index 58e373b5261..2bc8e6f0cd4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -125,7 +125,7 @@ abstract class AbstractCoroutineCodegen( iv.load(0, AsmTypes.OBJECT_TYPE) val hasArityParameter = !languageVersionSettings.isReleaseCoroutines() || passArityToSuperClass if (hasArityParameter) { - iv.iconst(if (passArityToSuperClass) calculateArity() else 0) + iv.iconst(if (passArityToSuperClass) funDescriptor.arity else 0) } iv.load(argTypes.map { it.size }.sum(), AsmTypes.OBJECT_TYPE)