JVM IR: implement MethodSignatureMapper.mapToCallableMethod directly
Instead of calling enormously complicated KotlinTypeMapper.mapToCallableMethod, where most of special cases are handled in the IR backend via lowerings.
This commit is contained in:
@@ -1493,29 +1493,19 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
||||
private fun findSuperDeclaration(descriptor: FunctionDescriptor, isSuperCall: Boolean): FunctionDescriptor {
|
||||
var current = descriptor
|
||||
while (current.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||
val overridden = current.overriddenDescriptors
|
||||
if (overridden.isEmpty()) {
|
||||
throw IllegalStateException("Fake override should have at least one overridden descriptor: $current")
|
||||
}
|
||||
|
||||
var classCallable: FunctionDescriptor? = null
|
||||
for (overriddenFunction in overridden) {
|
||||
if (!isInterface(overriddenFunction.containingDeclaration)) {
|
||||
classCallable = overriddenFunction
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
val classCallable = current.overriddenDescriptors.firstOrNull { !isInterface(it.containingDeclaration) }
|
||||
if (classCallable != null) {
|
||||
//prefer class callable cause of else branch
|
||||
current = classCallable
|
||||
continue
|
||||
} else if (isSuperCall && !current.hasJvmDefaultAnnotation() && !isInterface(current.containingDeclaration)) {
|
||||
}
|
||||
if (isSuperCall && !current.hasJvmDefaultAnnotation() && !isInterface(current.containingDeclaration)) {
|
||||
//Don't unwrap fake overrides from class to interface cause substituted override would be implicitly generated
|
||||
return current
|
||||
}
|
||||
|
||||
current = overridden.iterator().next()
|
||||
current = current.overriddenDescriptors.firstOrNull()
|
||||
?: error("Fake override should have at least one overridden descriptor: $current")
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
+7
-17
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.utils.keysToMap
|
||||
@@ -320,8 +321,7 @@ class ExpressionCodegen(
|
||||
classCodegen.context.irIntrinsics.getIntrinsic(expression.symbol)
|
||||
?.invoke(expression, this, data)?.let { return it.coerce(expression.type) }
|
||||
|
||||
val isSuperCall = (expression as? IrCall)?.superQualifier != null
|
||||
val callable = methodSignatureMapper.mapToCallableMethod(expression, isSuperCall)
|
||||
val callable = methodSignatureMapper.mapToCallableMethod(expression)
|
||||
val callee = expression.symbol.owner
|
||||
val callGenerator = getOrCreateCallGenerator(expression, data)
|
||||
val asmType = if (expression is IrConstructorCall) typeMapper.mapTypeAsDeclaration(expression.type) else expression.asmType
|
||||
@@ -357,24 +357,14 @@ class ExpressionCodegen(
|
||||
}
|
||||
|
||||
expression.dispatchReceiver?.let { receiver ->
|
||||
callGenerator.genValueAndPut(
|
||||
callee.dispatchReceiverParameter!!,
|
||||
receiver,
|
||||
if (isSuperCall) receiver.asmType else callable.dispatchReceiverType
|
||||
?: throw AssertionError("No dispatch receiver type: ${expression.render()}"),
|
||||
this,
|
||||
data
|
||||
)
|
||||
val type = if ((expression as? IrCall)?.superQualifier != null) receiver.asmType else callable.owner
|
||||
callGenerator.genValueAndPut(callee.dispatchReceiverParameter!!, receiver, type, this, data)
|
||||
}
|
||||
|
||||
expression.extensionReceiver?.let { receiver ->
|
||||
callGenerator.genValueAndPut(
|
||||
callee.extensionReceiverParameter!!,
|
||||
receiver,
|
||||
callable.extensionReceiverType!!,
|
||||
this,
|
||||
data
|
||||
)
|
||||
val type = callable.signature.valueParameters.singleOrNull { it.kind == JvmMethodParameterKind.RECEIVER }?.asmType
|
||||
?: error("No single extension receiver parameter: ${callable.signature.valueParameters}")
|
||||
callGenerator.genValueAndPut(callee.extensionReceiverParameter!!, receiver, type, this, data)
|
||||
}
|
||||
|
||||
callGenerator.beforeValueParametersStart()
|
||||
|
||||
+8
-4
@@ -5,19 +5,23 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.codegen
|
||||
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import org.jetbrains.org.objectweb.asm.util.Printer
|
||||
|
||||
class IrCallableMethod(
|
||||
val owner: Type,
|
||||
val valueParameterTypes: List<Type>,
|
||||
val invokeOpcode: Int,
|
||||
val asmMethod: Method,
|
||||
val dispatchReceiverType: Type?,
|
||||
val extensionReceiverType: Type?,
|
||||
val signature: JvmMethodSignature,
|
||||
val isInterfaceMethod: Boolean
|
||||
) {
|
||||
val asmMethod: Method = signature.asmMethod
|
||||
|
||||
val valueParameterTypes: List<Type> =
|
||||
signature.valueParameters.filter { it.kind == JvmMethodParameterKind.VALUE }.map { it.asmType }
|
||||
|
||||
override fun toString(): String =
|
||||
"${Printer.OPCODES[invokeOpcode]} $owner.$asmMethod" + (if (isInterfaceMethod) " (itf)" else "")
|
||||
}
|
||||
|
||||
+77
-9
@@ -6,20 +6,28 @@
|
||||
package org.jetbrains.kotlin.backend.jvm.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
||||
import org.jetbrains.kotlin.codegen.OwnerKind
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.isFakeOverride
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.load.java.getOverriddenBuiltinReflectingJvmDescriptor
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
|
||||
class MethodSignatureMapper(context: JvmBackendContext) {
|
||||
private val kotlinTypeMapper: KotlinTypeMapper = context.state.typeMapper
|
||||
private val typeMapper: IrTypeMapper = context.typeMapper
|
||||
private val kotlinTypeMapper: KotlinTypeMapper = typeMapper.kotlinTypeMapper
|
||||
|
||||
fun mapAsmMethod(irFunction: IrFunction): Method =
|
||||
kotlinTypeMapper.mapAsmMethod(irFunction.descriptor)
|
||||
@@ -48,10 +56,70 @@ class MethodSignatureMapper(context: JvmBackendContext) {
|
||||
fun mapSignatureWithGeneric(f: IrFunction, kind: OwnerKind): JvmMethodGenericSignature =
|
||||
kotlinTypeMapper.mapSignatureWithGeneric(f.descriptor, kind)
|
||||
|
||||
fun mapToCallableMethod(expression: IrFunctionAccessExpression, superCall: Boolean): IrCallableMethod =
|
||||
with(kotlinTypeMapper.mapToCallableMethod(expression.descriptor, superCall)) {
|
||||
IrCallableMethod(
|
||||
owner, valueParameterTypes, invokeOpcode, getAsmMethod(), dispatchReceiverType, extensionReceiverType, isInterfaceMethod
|
||||
)
|
||||
fun mapToCallableMethod(expression: IrFunctionAccessExpression): IrCallableMethod {
|
||||
val callee = expression.symbol.owner
|
||||
val calleeParent = callee.parent
|
||||
if (calleeParent !is IrClass) {
|
||||
// Non-class parent is only possible for intrinsics created in IrBuiltIns, such as dataClassArrayMemberHashCode. In that case,
|
||||
// we still need to return some IrCallableMethod with some owner instance, but that owner will be ignored at the call site.
|
||||
// Here we return a fake type, but this needs to be refactored so that we never call mapToCallableMethod on intrinsics.
|
||||
// TODO: get rid of fake owner here
|
||||
val fakeOwner = Type.getObjectType("kotlin/internal/ir/Intrinsic")
|
||||
return IrCallableMethod(fakeOwner, Opcodes.INVOKESTATIC, mapSignatureSkipGeneric(callee), false)
|
||||
}
|
||||
|
||||
val owner = typeMapper.mapClass(calleeParent)
|
||||
|
||||
if (callee !is IrSimpleFunction) {
|
||||
check(callee is IrConstructor) { "Function must be a simple function or a constructor: ${callee.render()}" }
|
||||
return IrCallableMethod(owner, Opcodes.INVOKESPECIAL, mapSignatureSkipGeneric(callee), false)
|
||||
}
|
||||
|
||||
val isInterface = calleeParent.isJvmInterface
|
||||
val isSuperCall = (expression as? IrCall)?.superQualifier != null
|
||||
|
||||
val invokeOpcode = when {
|
||||
callee.dispatchReceiverParameter == null -> Opcodes.INVOKESTATIC
|
||||
isSuperCall -> Opcodes.INVOKESPECIAL
|
||||
isInterface -> Opcodes.INVOKEINTERFACE
|
||||
Visibilities.isPrivate(callee.visibility) && !callee.isSuspend -> Opcodes.INVOKESPECIAL
|
||||
else -> Opcodes.INVOKEVIRTUAL
|
||||
}
|
||||
|
||||
val declaration = findSuperDeclaration(callee, isSuperCall)
|
||||
val signature = mapOverriddenSpecialBuiltinIfNeeded(declaration, isSuperCall)
|
||||
?: mapSignatureSkipGeneric(declaration)
|
||||
|
||||
return IrCallableMethod(owner, invokeOpcode, signature, isInterface)
|
||||
}
|
||||
|
||||
// TODO: get rid of this (probably via some special lowering)
|
||||
private fun mapOverriddenSpecialBuiltinIfNeeded(callee: IrFunction, superCall: Boolean): JvmMethodSignature? {
|
||||
val overriddenSpecialBuiltinFunction = callee.descriptor.original.getOverriddenBuiltinReflectingJvmDescriptor()
|
||||
if (overriddenSpecialBuiltinFunction != null && !superCall) {
|
||||
return kotlinTypeMapper.mapSignatureSkipGeneric(overriddenSpecialBuiltinFunction.original, OwnerKind.IMPLEMENTATION)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
// Copied from KotlinTypeMapper.findSuperDeclaration.
|
||||
private fun findSuperDeclaration(function: IrSimpleFunction, isSuperCall: Boolean): IrSimpleFunction {
|
||||
var current = function
|
||||
while (current.isFakeOverride) {
|
||||
// TODO: probably isJvmInterface instead of isInterface, here and in KotlinTypeMapper
|
||||
val classCallable = current.overriddenSymbols.firstOrNull { !it.owner.parentAsClass.isInterface }?.owner
|
||||
if (classCallable != null) {
|
||||
current = classCallable
|
||||
continue
|
||||
}
|
||||
if (isSuperCall && !current.hasJvmDefault() && !current.parentAsClass.isInterface) {
|
||||
return current
|
||||
}
|
||||
|
||||
current = current.overriddenSymbols.firstOrNull()?.owner
|
||||
?: error("Fake override should have at least one overridden descriptor: ${current.render()}")
|
||||
}
|
||||
return current
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: A.kt
|
||||
|
||||
|
||||
Reference in New Issue
Block a user