IC: call JvmDefault method of inline class using boxed receiver

#KT-43698 Fixed
This commit is contained in:
Ilmir Usmanov
2020-12-07 15:13:54 +01:00
parent d6330337a9
commit 0dc5f3ac00
19 changed files with 227 additions and 78 deletions
@@ -29,7 +29,8 @@ class CallableMethod(
override val generateCalleeType: Type?,
override val returnKotlinType: KotlinType?,
val isInterfaceMethod: Boolean,
private val isDefaultMethodInInterface: Boolean
private val isDefaultMethodInInterface: Boolean,
private val boxInlineClassBeforeInvoke: Boolean
) : Callable {
private val defaultImplMethod: Method by lazy(LazyThreadSafetyMode.PUBLICATION, computeDefaultMethod)
@@ -49,6 +50,9 @@ class CallableMethod(
get() = getAsmMethod().argumentTypes
override fun genInvokeInstruction(v: InstructionAdapter) {
if (boxInlineClassBeforeInvoke) {
StackValue.boxInlineClass(dispatchReceiverKotlinType!!, v)
}
v.visitMethodInsn(
invokeOpcode,
owner.internalName,
@@ -379,7 +379,8 @@ class KotlinTypeMapper @JvmOverloads constructor(
val originalDescriptor = descriptor.original
return CallableMethod(
owner, owner, { mapDefaultMethod(originalDescriptor, OwnerKind.IMPLEMENTATION) }, method, INVOKESPECIAL,
null, null, null, null, null, originalDescriptor.returnType, isInterfaceMethod = false, isDefaultMethodInInterface = false
null, null, null, null, null, originalDescriptor.returnType, isInterfaceMethod = false, isDefaultMethodInInterface = false,
boxInlineClassBeforeInvoke = false
)
}
@@ -402,6 +403,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
val dispatchReceiverKotlinType: KotlinType?
var isInterfaceMember = false
var isDefaultMethodInInterface = false
var boxInlineClassBeforeInvoke = false
if (functionParent is ClassDescriptor) {
val declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor)
@@ -452,11 +454,15 @@ class KotlinTypeMapper @JvmOverloads constructor(
functionDescriptor = descriptor
}
val isStaticInvocation =
isStaticDeclaration(functionDescriptor) && functionDescriptor !is ImportedFromObjectCallableDescriptor<*> ||
isStaticAccessor(functionDescriptor) ||
functionDescriptor.isJvmStaticInObjectOrClassOrInterface() ||
toInlinedErasedClass
val isFakeOverrideOfJvmDefault = toInlinedErasedClass &&
functionDescriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
functionDescriptor.overridesJvmDefault()
val isStaticInvocation = !isFakeOverrideOfJvmDefault &&
(isStaticDeclaration(functionDescriptor) && functionDescriptor !is ImportedFromObjectCallableDescriptor<*> ||
isStaticAccessor(functionDescriptor) ||
functionDescriptor.isJvmStaticInObjectOrClassOrInterface() ||
toInlinedErasedClass)
when {
isStaticInvocation -> {
invokeOpcode = INVOKESTATIC
@@ -466,8 +472,13 @@ class KotlinTypeMapper @JvmOverloads constructor(
invokeOpcode = INVOKEINTERFACE
isInterfaceMember = true
}
isFakeOverrideOfJvmDefault -> {
invokeOpcode = INVOKEVIRTUAL
boxInlineClassBeforeInvoke = true
}
else -> {
val isPrivateFunInvocation = DescriptorVisibilities.isPrivate(functionDescriptor.visibility) && !functionDescriptor.isSuspend
val isPrivateFunInvocation =
DescriptorVisibilities.isPrivate(functionDescriptor.visibility) && !functionDescriptor.isSuspend
invokeOpcode = if (superCall || isPrivateFunInvocation) INVOKESPECIAL else INVOKEVIRTUAL
isInterfaceMember = false
}
@@ -479,7 +490,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
else
functionDescriptor.original
signature = if (toInlinedErasedClass)
signature = if (toInlinedErasedClass && !isFakeOverrideOfJvmDefault)
mapSignatureForInlineErasedClassSkipGeneric(functionToCall)
else
mapSignature(
@@ -547,10 +558,18 @@ class KotlinTypeMapper @JvmOverloads constructor(
signature, invokeOpcode, thisClass, dispatchReceiverKotlinType, receiverParameterType, extensionReceiverKotlinType,
calleeType, returnKotlinType,
if (jvmTarget >= JvmTarget.JVM_1_8) isInterfaceMember else invokeOpcode == INVOKEINTERFACE,
isDefaultMethodInInterface
isDefaultMethodInInterface, boxInlineClassBeforeInvoke
)
}
private fun CallableMemberDescriptor.overridesJvmDefault(): Boolean {
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
return overriddenDescriptors.any { it.overridesJvmDefault() }
}
if (isCompiledToJvmDefault(jvmDefaultMode)) return true
return (containingDeclaration as? JavaClassDescriptor)?.kind == ClassKind.INTERFACE && modality != Modality.ABSTRACT
}
fun mapFunctionName(descriptor: FunctionDescriptor, kind: OwnerKind?): String {
if (descriptor !is JavaCallableMemberDescriptor) {
val platformName = getJvmName(descriptor)