JVM: Fix reflection tests for new IC ABI

This commit is contained in:
Dmitry Petrov
2020-05-07 21:30:31 +03:00
parent b5bd3604b1
commit dc9f64fc9d
18 changed files with 214 additions and 47 deletions
@@ -407,7 +407,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
if (generateBody) {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
CallableReferenceUtilKt.generateCallableReferenceSignature(iv, descriptor, state);
CallableReferenceUtilKt.generateFunctionReferenceSignature(iv, descriptor, state);
iv.areturn(JAVA_STRING_TYPE);
FunctionCodegen.endVisit(iv, "function reference getSignature", element);
}
@@ -465,7 +465,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
assert functionReferenceTarget != null : "No function reference target: " + funDescriptor;
generateCallableReferenceDeclarationContainerClass(iv, functionReferenceTarget, state);
iv.aconst(functionReferenceTarget.getName().asString());
CallableReferenceUtilKt.generateCallableReferenceSignature(iv, functionReferenceTarget, state);
CallableReferenceUtilKt.generateFunctionReferenceSignature(iv, functionReferenceTarget, state);
int flags =
getCallableReferenceTopLevelFlag(functionReferenceTarget) +
(calculateFunctionReferenceFlags(functionReferenceCall, funDescriptor) << 1);
@@ -679,7 +679,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
}
iv.aconst(property.getName().asString());
CallableReferenceUtilKt.generateCallableReferenceSignature(iv, property, state);
CallableReferenceUtilKt.generatePropertyReferenceSignature(iv, property, state);
superCtorArgTypes.add(JAVA_STRING_TYPE);
superCtorArgTypes.add(JAVA_STRING_TYPE);
@@ -13,12 +13,13 @@ enum class OwnerKind {
PACKAGE,
IMPLEMENTATION,
DEFAULT_IMPLS,
ERASED_INLINE_CLASS;
ERASED_INLINE_CLASS,
PROPERTY_REFERENCE_SIGNATURE;
companion object {
fun getMemberOwnerKind(descriptor: DeclarationDescriptor): OwnerKind = when (descriptor) {
is PackageFragmentDescriptor -> OwnerKind.PACKAGE
is ClassDescriptor -> OwnerKind.IMPLEMENTATION
is PackageFragmentDescriptor -> PACKAGE
is ClassDescriptor -> IMPLEMENTATION
else -> throw AssertionError("Unexpected declaration container: $this")
}
}
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtilKt;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
@@ -52,6 +51,7 @@ import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.*;
import static org.jetbrains.kotlin.diagnostics.Errors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND;
import static org.jetbrains.kotlin.fileClasses.JvmFileClassUtilKt.isTopLevelInJvmMultifileClass;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface;
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.K_PROPERTY_TYPE;
@@ -135,10 +135,10 @@ public class PropertyCodegen {
boolean isDefaultGetterAndSetter = isDefaultAccessor(getter) && isDefaultAccessor(setter);
if (isAccessorNeeded(declaration, descriptor, getter, isDefaultGetterAndSetter)) {
if (isAccessorNeeded(descriptor, getter, isDefaultGetterAndSetter)) {
generateGetter(descriptor, getter);
}
if (isAccessorNeeded(declaration, descriptor, setter, isDefaultGetterAndSetter)) {
if (isAccessorNeeded(descriptor, setter, isDefaultGetterAndSetter)) {
generateSetter(descriptor, setter);
}
}
@@ -167,17 +167,40 @@ public class PropertyCodegen {
generateSyntheticMethodIfNeeded(descriptor, isBackingFieldOwner);
}
private boolean isAccessorNeeded(
@NotNull PropertyDescriptor descriptor,
@Nullable KtPropertyAccessor accessor,
boolean isDefaultGetterAndSetter
) {
return isAccessorNeeded(descriptor, accessor, isDefaultGetterAndSetter, kind);
}
public static boolean isReferenceablePropertyWithGetter(@NotNull PropertyDescriptor descriptor) {
PsiElement psiElement = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
KtDeclaration ktDeclaration = psiElement instanceof KtDeclaration ? (KtDeclaration) psiElement : null;
if (ktDeclaration instanceof KtProperty) {
KtProperty ktProperty = (KtProperty) ktDeclaration;
boolean isDefaultGetterAndSetter =
isDefaultAccessor(ktProperty.getGetter()) && isDefaultAccessor(ktProperty.getSetter());
return isAccessorNeeded(descriptor, ktProperty.getGetter(), isDefaultGetterAndSetter, OwnerKind.IMPLEMENTATION);
} else if (ktDeclaration instanceof KtParameter) {
return isAccessorNeeded(descriptor, null, true, OwnerKind.IMPLEMENTATION);
} else {
return isAccessorNeeded(descriptor, null, false, OwnerKind.IMPLEMENTATION);
}
}
/**
* Determines if it's necessary to generate an accessor to the property, i.e. if this property can be referenced via getter/setter
* for any reason
*
* @see JvmCodegenUtil#couldUseDirectAccessToProperty
*/
private boolean isAccessorNeeded(
@NotNull KtProperty declaration,
private static boolean isAccessorNeeded(
@NotNull PropertyDescriptor descriptor,
@Nullable KtPropertyAccessor accessor,
boolean isDefaultGetterAndSetter
boolean isDefaultGetterAndSetter,
OwnerKind kind
) {
if (isConstOrHasJvmFieldAnnotation(descriptor)) return false;
@@ -187,7 +210,8 @@ public class PropertyCodegen {
if (kind == OwnerKind.DEFAULT_IMPLS && isDefaultAccessor) return false;
// Delegated or extension properties can only be referenced via accessors
if (declaration.hasDelegate() || declaration.getReceiverTypeReference() != null) return true;
//noinspection deprecation
if (descriptor.isDelegated() || descriptor.getExtensionReceiverParameter() != null) return true;
// Companion object properties should have accessors for non-private properties because these properties can be referenced
// via getter/setter. But these accessors getter/setter are not required for private properties that have a default getter
@@ -201,7 +225,7 @@ public class PropertyCodegen {
}
// Non-const properties from multifile classes have accessors regardless of visibility
if (isTopLevelPropertyInMultifileClass(declaration, descriptor)) return true;
if (isTopLevelInJvmMultifileClass(descriptor)) return true;
// Private class properties have accessors only in cases when those accessors are non-trivial
if (Visibilities.isPrivate(descriptor.getVisibility())) {
@@ -215,15 +239,12 @@ public class PropertyCodegen {
return !isDefaultAccessor;
}
return true;
}
// Non-public API (private and internal) primary vals of inline classes don't have getter
if (InlineClassesUtilsKt.isUnderlyingPropertyOfInlineClass(descriptor) && !descriptor.getVisibility().isPublicAPI()) {
return false;
}
private static boolean isTopLevelPropertyInMultifileClass(
@NotNull KtProperty declaration,
@NotNull PropertyDescriptor descriptor
) {
return descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor &&
JvmFileClassUtilKt.isInsideJvmMultifileClassFile(declaration);
return true;
}
private static boolean areAccessorsNeededForPrimaryConstructorProperty(
@@ -118,7 +118,7 @@ class PropertyReferenceCodegen(
aconst(target.name.asString())
}
generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) {
generateCallableReferenceSignature(this, target, state)
generatePropertyReferenceSignature(this, target, state)
}
generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) {
generateCallableReferenceDeclarationContainer(this, target, state)
@@ -148,7 +148,7 @@ class PropertyReferenceCodegen(
if (isOptimizedPropertyReferenceSupertype(superAsmType)) {
generateCallableReferenceDeclarationContainerClass(this, target, state)
aconst(target.name.asString())
generateCallableReferenceSignature(this, target, state)
generatePropertyReferenceSignature(this, target, state)
aconst(getCallableReferenceTopLevelFlag(target))
superCtorArgTypes.add(JAVA_CLASS_TYPE)
superCtorArgTypes.add(JAVA_STRING_TYPE)
@@ -168,11 +168,15 @@ private fun isTopLevelCallableReference(descriptor: CallableDescriptor): Boolean
internal fun getCallableReferenceTopLevelFlag(descriptor: CallableDescriptor): Int =
if (isTopLevelCallableReference(descriptor)) 1 else 0
internal fun generateCallableReferenceSignature(iv: InstructionAdapter, callable: CallableDescriptor, state: GenerationState) {
internal fun generateFunctionReferenceSignature(iv: InstructionAdapter, callable: CallableDescriptor, state: GenerationState) {
iv.aconst(getSignatureString(callable, state))
}
private fun getSignatureString(callable: CallableDescriptor, state: GenerationState): String {
internal fun generatePropertyReferenceSignature(iv: InstructionAdapter, callable: CallableDescriptor, state: GenerationState) {
iv.aconst(getSignatureString(callable, state, isPropertySignature = true))
}
private fun getSignatureString(callable: CallableDescriptor, state: GenerationState, isPropertySignature: Boolean = false): 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")
@@ -198,10 +202,13 @@ private fun getSignatureString(callable: CallableDescriptor, state: GenerationSt
else -> error("Unsupported callable reference: $callable")
}
val declaration = DescriptorUtils.unwrapFakeOverride(accessor).original
val method =
if (callable.containingDeclaration.isInlineClass() && !declaration.isGetterOfUnderlyingPropertyOfInlineClass())
val method = when {
callable.containingDeclaration.isInlineClass() && !declaration.isGetterOfUnderlyingPropertyOfInlineClass() ->
state.typeMapper.mapSignatureForInlineErasedClassSkipGeneric(declaration).asmMethod
else
isPropertySignature ->
state.typeMapper.mapPropertyReferenceSignature(declaration)
else ->
state.typeMapper.mapAsmMethod(declaration)
}
return method.name + method.descriptor
}
}
@@ -47,7 +47,7 @@ class PsiInlineIntrinsicsSupport(private val state: GenerationState) : ReifiedTy
v.aconst(descriptor.arity)
generateCallableReferenceDeclarationContainerClass(v, descriptor, state)
v.aconst(descriptor.name.asString())
generateCallableReferenceSignature(v, descriptor, state)
generateFunctionReferenceSignature(v, descriptor, state)
v.aconst(getCallableReferenceTopLevelFlag(descriptor))
v.invokespecial(
FUNCTION_REFERENCE_IMPL.internalName, "<init>",
@@ -683,6 +683,15 @@ class KotlinTypeMapper @JvmOverloads constructor(
} else newName
}
private fun CallableMemberDescriptor.isPropertyWithGetterSignaturePresent(): Boolean {
val propertyDescriptor = when (this) {
is PropertyDescriptor -> this
is PropertyAccessorDescriptor -> correspondingProperty
else -> return false
}
return PropertyCodegen.isReferenceablePropertyWithGetter(propertyDescriptor)
}
private fun getModuleName(descriptor: CallableMemberDescriptor): String {
return getJvmModuleNameForDeserializedDescriptor(descriptor) ?: moduleName
}
@@ -691,6 +700,10 @@ class KotlinTypeMapper @JvmOverloads constructor(
return mapSignature(descriptor).asmMethod
}
fun mapPropertyReferenceSignature(descriptor: FunctionDescriptor): Method {
return mapSignature(descriptor, OwnerKind.PROPERTY_REFERENCE_SIGNATURE, true).asmMethod
}
fun mapAsmMethod(descriptor: FunctionDescriptor, kind: OwnerKind): Method {
return mapSignature(descriptor, kind, true).asmMethod
}
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.jvm.*
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameMangling
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
import java.security.MessageDigest