Move some codegen utilities to callableReferenceUtil.kt

Some of them were declared in ClosureCodegen near generation of function
references, and some in PropertyReferenceCodegen, which was confusing.
This commit is contained in:
Alexander Udalov
2020-04-29 21:27:01 +02:00
parent 4fe8754ba1
commit 82603f3853
6 changed files with 126 additions and 134 deletions
@@ -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<KtElement> {
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<FieldInfo> args = calculateConstructorParameters(typeMapper, state.getLanguageVersionSettings(), closure, asmType);
@@ -511,8 +453,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
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<KtElement> {
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<KtElement> {
((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<FieldInfo> calculateConstructorParameters(
@NotNull KotlinTypeMapper typeMapper,
@@ -663,21 +663,21 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
List<Type> 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);
}
@@ -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 "<v#$index>"
}
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) {
@@ -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 "<v#$index>"
}
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
}
@@ -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())
@@ -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)