JVM IR: specialize ExpressionCodegen.visitFunctionAccess for constructors
This makes the code a bit clearer, and gets rid of some extra type mapper invocations when generating constructor calls.
This commit is contained in:
+68
-44
@@ -52,6 +52,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
import org.jetbrains.kotlin.utils.keysToMap
|
import org.jetbrains.kotlin.utils.keysToMap
|
||||||
import org.jetbrains.org.objectweb.asm.Label
|
import org.jetbrains.org.objectweb.asm.Label
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -386,7 +387,7 @@ class ExpressionCodegen(
|
|||||||
override fun visitContainerExpression(expression: IrContainerExpression, data: BlockInfo) =
|
override fun visitContainerExpression(expression: IrContainerExpression, data: BlockInfo) =
|
||||||
visitStatementContainer(expression, data)
|
visitStatementContainer(expression, data)
|
||||||
|
|
||||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: BlockInfo): PromisedValue {
|
override fun visitCall(expression: IrCall, data: BlockInfo): PromisedValue {
|
||||||
classCodegen.context.irIntrinsics.getIntrinsic(expression.symbol)
|
classCodegen.context.irIntrinsics.getIntrinsic(expression.symbol)
|
||||||
?.invoke(expression, this, data)?.let { return it }
|
?.invoke(expression, this, data)?.let { return it }
|
||||||
|
|
||||||
@@ -394,47 +395,14 @@ class ExpressionCodegen(
|
|||||||
require(callee.parent is IrClass) { "Unhandled intrinsic in ExpressionCodegen: ${callee.render()}" }
|
require(callee.parent is IrClass) { "Unhandled intrinsic in ExpressionCodegen: ${callee.render()}" }
|
||||||
val callable = methodSignatureMapper.mapToCallableMethod(irFunction, expression)
|
val callable = methodSignatureMapper.mapToCallableMethod(irFunction, expression)
|
||||||
val callGenerator = getOrCreateCallGenerator(expression, data, callable.signature)
|
val callGenerator = getOrCreateCallGenerator(expression, data, callable.signature)
|
||||||
val asmType = if (expression is IrConstructorCall) typeMapper.mapTypeAsDeclaration(expression.type) else expression.asmType
|
|
||||||
val isSuspensionPoint = expression.isSuspensionPoint()
|
val isSuspensionPoint = expression.isSuspensionPoint()
|
||||||
|
|
||||||
if (isSuspensionPoint != SuspensionPointKind.NEVER) {
|
if (isSuspensionPoint != SuspensionPointKind.NEVER) {
|
||||||
addInlineMarker(mv, isStartNotEnd = true)
|
addInlineMarker(mv, isStartNotEnd = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
when {
|
|
||||||
expression is IrConstructorCall -> {
|
|
||||||
closureReifiedMarkers[expression.symbol.owner.parentAsClass]?.let {
|
|
||||||
if (it.wereUsedReifiedParameters()) {
|
|
||||||
putNeedClassReificationMarker(v)
|
|
||||||
propagateChildReifiedTypeParametersUsages(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IR constructors have no receiver and return the new instance, but on JVM they are void-returning
|
|
||||||
// instance methods named <init>.
|
|
||||||
markLineNumber(expression)
|
|
||||||
mv.anew(asmType)
|
|
||||||
mv.dup()
|
|
||||||
}
|
|
||||||
expression is IrDelegatingConstructorCall -> {
|
|
||||||
expression.markLineNumber(startOffset = true)
|
|
||||||
|
|
||||||
// In this case the receiver is `this` (not specified in IR) and the return value is discarded anyway.
|
|
||||||
mv.load(0, OBJECT_TYPE)
|
|
||||||
|
|
||||||
for (argumentIndex in 0 until expression.typeArgumentsCount) {
|
|
||||||
val classifier = expression.getTypeArgument(argumentIndex)?.classifierOrNull
|
|
||||||
if (classifier is IrTypeParameterSymbol && classifier.owner.isReified) {
|
|
||||||
consumeReifiedOperationMarker(classifier)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expression.symbol.owner is IrConstructor ->
|
|
||||||
throw AssertionError("IrCall to IrConstructor: ${expression.javaClass.simpleName}")
|
|
||||||
}
|
|
||||||
|
|
||||||
expression.dispatchReceiver?.let { receiver ->
|
expression.dispatchReceiver?.let { receiver ->
|
||||||
val type = if ((expression as? IrCall)?.superQualifierSymbol != null) receiver.asmType else callable.owner
|
val type = if (expression.superQualifierSymbol != null) receiver.asmType else callable.owner
|
||||||
callGenerator.genValueAndPut(callee.dispatchReceiverParameter!!, receiver, type, this, data)
|
callGenerator.genValueAndPut(callee.dispatchReceiverParameter!!, receiver, type, this, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,14 +426,10 @@ class ExpressionCodegen(
|
|||||||
addSuspendMarker(mv, isStartNotEnd = true, isSuspensionPoint == SuspensionPointKind.NOT_INLINE)
|
addSuspendMarker(mv, isStartNotEnd = true, isSuspensionPoint == SuspensionPointKind.NOT_INLINE)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (irFunction.isInvokeSuspendOfContinuation()) {
|
val generatorForActualCall =
|
||||||
// Do not inline callee to continuation, instead, call it
|
// Do not inline callee to continuation, instead, call it
|
||||||
with(callable) {
|
if (irFunction.isInvokeSuspendOfContinuation()) IrCallGenerator.DefaultCallGenerator else callGenerator
|
||||||
mv.visitMethodInsn(invokeOpcode, owner.internalName, asmMethod.name, asmMethod.descriptor, isInterfaceMethod)
|
generatorForActualCall.genCall(callable, this, expression)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
callGenerator.genCall(callable, this, expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSuspensionPoint != SuspensionPointKind.NEVER) {
|
if (isSuspensionPoint != SuspensionPointKind.NEVER) {
|
||||||
addSuspendMarker(mv, isStartNotEnd = false, isSuspensionPoint == SuspensionPointKind.NOT_INLINE)
|
addSuspendMarker(mv, isStartNotEnd = false, isSuspensionPoint == SuspensionPointKind.NOT_INLINE)
|
||||||
@@ -473,8 +437,6 @@ class ExpressionCodegen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
expression is IrConstructorCall ->
|
|
||||||
MaterialValue(this, asmType, expression.type)
|
|
||||||
(expression.type.isNothing() || expression.type.isUnit()) && irFunction.shouldContainSuspendMarkers() -> {
|
(expression.type.isNothing() || expression.type.isUnit()) && irFunction.shouldContainSuspendMarkers() -> {
|
||||||
// NewInference allows casting `() -> T` to `() -> Unit`. A CHECKCAST here will fail.
|
// NewInference allows casting `() -> T` to `() -> Unit`. A CHECKCAST here will fail.
|
||||||
// Also, if the callee is a suspend function with a suspending tail call, the next `resumeWith`
|
// Also, if the callee is a suspend function with a suspending tail call, the next `resumeWith`
|
||||||
@@ -511,6 +473,68 @@ class ExpressionCodegen(
|
|||||||
else -> SuspensionPointKind.ALWAYS
|
else -> SuspensionPointKind.ALWAYS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: BlockInfo): PromisedValue {
|
||||||
|
val callee = expression.symbol.owner
|
||||||
|
val owner = typeMapper.mapClass(callee.constructedClass)
|
||||||
|
val signature = methodSignatureMapper.mapSignatureSkipGeneric(callee)
|
||||||
|
|
||||||
|
markLineNumber(expression)
|
||||||
|
|
||||||
|
// In this case the receiver is `this` (not specified in IR) and the return value is discarded anyway.
|
||||||
|
mv.load(0, OBJECT_TYPE)
|
||||||
|
|
||||||
|
for (argumentIndex in 0 until expression.typeArgumentsCount) {
|
||||||
|
val classifier = expression.getTypeArgument(argumentIndex)?.classifierOrNull
|
||||||
|
if (classifier is IrTypeParameterSymbol && classifier.owner.isReified) {
|
||||||
|
consumeReifiedOperationMarker(classifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generateConstructorArguments(expression, signature, data)
|
||||||
|
markLineNumber(expression)
|
||||||
|
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner.internalName, signature.asmMethod.name, signature.asmMethod.descriptor, false)
|
||||||
|
|
||||||
|
return unitValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConstructorCall(expression: IrConstructorCall, data: BlockInfo): PromisedValue {
|
||||||
|
classCodegen.context.irIntrinsics.getIntrinsic(expression.symbol)
|
||||||
|
?.invoke(expression, this, data)?.let { return it }
|
||||||
|
|
||||||
|
val callee = expression.symbol.owner
|
||||||
|
val owner = typeMapper.mapClass(callee.constructedClass)
|
||||||
|
val signature = methodSignatureMapper.mapSignatureSkipGeneric(callee)
|
||||||
|
|
||||||
|
closureReifiedMarkers[expression.symbol.owner.parentAsClass]?.let {
|
||||||
|
if (it.wereUsedReifiedParameters()) {
|
||||||
|
putNeedClassReificationMarker(v)
|
||||||
|
propagateChildReifiedTypeParametersUsages(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IR constructors have no receiver and return the new instance, but on JVM they are void-returning
|
||||||
|
// instance methods named <init>.
|
||||||
|
markLineNumber(expression)
|
||||||
|
mv.anew(owner)
|
||||||
|
mv.dup()
|
||||||
|
|
||||||
|
generateConstructorArguments(expression, signature, data)
|
||||||
|
markLineNumber(expression)
|
||||||
|
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner.internalName, signature.asmMethod.name, signature.asmMethod.descriptor, false)
|
||||||
|
|
||||||
|
return MaterialValue(this, owner, expression.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateConstructorArguments(expression: IrFunctionAccessExpression, signature: JvmMethodSignature, data: BlockInfo) {
|
||||||
|
expression.symbol.owner.valueParameters.forEachIndexed { i, irParameter ->
|
||||||
|
val arg = expression.getValueArgument(i)
|
||||||
|
?: error("Null argument in ExpressionCodegen for parameter ${irParameter.render()}")
|
||||||
|
gen(arg, signature.valueParameters[i].asmType, irParameter.type, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitVariable(declaration: IrVariable, data: BlockInfo): PromisedValue {
|
override fun visitVariable(declaration: IrVariable, data: BlockInfo): PromisedValue {
|
||||||
val varType = typeMapper.mapType(declaration)
|
val varType = typeMapper.mapType(declaration)
|
||||||
val index = frameMap.enter(declaration.symbol, varType)
|
val index = frameMap.enter(declaration.symbol, varType)
|
||||||
|
|||||||
+6
-19
@@ -33,9 +33,7 @@ import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunctionBase
|
|||||||
import org.jetbrains.kotlin.ir.descriptors.IrBasedSimpleFunctionDescriptor
|
import org.jetbrains.kotlin.ir.descriptors.IrBasedSimpleFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor
|
import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor
|
||||||
import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType
|
import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.load.java.*
|
import org.jetbrains.kotlin.load.java.*
|
||||||
@@ -300,26 +298,15 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
|||||||
if (valueArgumentsCount > 0) (getValueArgument(0) as? IrConst<*>)?.value as? Boolean ?: true else null
|
if (valueArgumentsCount > 0) (getValueArgument(0) as? IrConst<*>)?.value as? Boolean ?: true else null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrFunctionAccessExpression.computeCalleeParent(): IrClass {
|
fun mapToCallableMethod(caller: IrFunction, expression: IrCall): IrCallableMethod {
|
||||||
if (this is IrCall) {
|
|
||||||
superQualifierSymbol?.let { return it.owner }
|
|
||||||
}
|
|
||||||
return dispatchReceiver?.type?.classOrNull?.owner
|
|
||||||
?: symbol.owner.parentAsClass // Static call or type parameter
|
|
||||||
}
|
|
||||||
|
|
||||||
fun mapToCallableMethod(caller: IrFunction, expression: IrFunctionAccessExpression): IrCallableMethod {
|
|
||||||
val callee = expression.symbol.owner
|
val callee = expression.symbol.owner
|
||||||
val calleeParent = expression.computeCalleeParent()
|
val calleeParent = expression.superQualifierSymbol?.owner
|
||||||
|
?: expression.dispatchReceiver?.type?.classOrNull?.owner
|
||||||
|
?: callee.parentAsClass // Static call or type parameter
|
||||||
val owner = typeMapper.mapOwner(calleeParent)
|
val owner = typeMapper.mapOwner(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 isInterface = calleeParent.isJvmInterface
|
||||||
val isSuperCall = (expression as? IrCall)?.superQualifierSymbol != null
|
val isSuperCall = expression.superQualifierSymbol != null
|
||||||
|
|
||||||
val invokeOpcode = when {
|
val invokeOpcode = when {
|
||||||
callee.dispatchReceiverParameter == null -> Opcodes.INVOKESTATIC
|
callee.dispatchReceiverParameter == null -> Opcodes.INVOKESTATIC
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.codegen.StackValue
|
|||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.org.objectweb.asm.Label
|
import org.jetbrains.org.objectweb.asm.Label
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
@@ -66,9 +65,6 @@ abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type, val
|
|||||||
|
|
||||||
val typeMapper: IrTypeMapper
|
val typeMapper: IrTypeMapper
|
||||||
get() = codegen.typeMapper
|
get() = codegen.typeMapper
|
||||||
|
|
||||||
val kotlinType: KotlinType
|
|
||||||
get() = irType.toKotlinType()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A value that *has* been fully constructed.
|
// A value that *has* been fully constructed.
|
||||||
|
|||||||
Reference in New Issue
Block a user