JVM IR: Remove bridge construction from CallableReferenceLowering

This commit is contained in:
Steven Schäfer
2019-07-25 16:52:15 +02:00
committed by Georgy Bronnikov
parent ebb59d51d2
commit 6aa8ecd745
9 changed files with 214 additions and 304 deletions
@@ -141,7 +141,6 @@ private val jvmFilePhases =
singletonReferencesPhase then
callableReferencePhase then
functionNVarargInvokePhase then
localDeclarationsPhase then
singleAbstractMethodPhase then
@@ -172,6 +171,7 @@ private val jvmFilePhases =
objectClassPhase then
makeInitializersPhase(JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, true) then
collectionStubMethodLowering then
functionNVarargBridgePhase then
bridgePhase then
jvmStaticAnnotationPhase then
staticDefaultFunctionPhase then
@@ -11,17 +11,13 @@ import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression
import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter
import org.jetbrains.kotlin.backend.jvm.localDeclarationsPhase
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
@@ -32,7 +28,6 @@ import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
@@ -66,52 +61,26 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext)
override fun lower(irFile: IrFile) = irFile.transformChildrenVoid(this)
// Change calls to big arity invoke functions to vararg calls.
// Mark function references appearing as inlined arguments to inline functions.
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
markInlineFunctionReferences(expression)
expression.transformChildrenVoid(this)
if (expression.valueArgumentsCount < FunctionInvokeDescriptor.BIG_ARITY ||
!expression.symbol.owner.parentAsClass.defaultType.isFunctionOrKFunction())
return expression
return IrCallImpl(
expression.startOffset, expression.endOffset,
expression.type, functionNInvokeFun.symbol, functionNInvokeFun.descriptor,
1, expression.origin
).apply {
putTypeArgument(0, expression.type)
dispatchReceiver = expression.dispatchReceiver
extensionReceiver = expression.extensionReceiver
val vararg = IrVarargImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.ir.symbols.array.typeWith(context.irBuiltIns.anyNType),
context.irBuiltIns.anyNType,
(0 until expression.valueArgumentsCount).map { expression.getValueArgument(it)!! }
)
putValueArgument(0, vararg)
}
}
private fun markInlineFunctionReferences(expression: IrFunctionAccessExpression) {
val function = expression.symbol.owner
if (!function.isInlineFunctionCall(context))
return
if (function.isInlineFunctionCall(context)) {
for (parameter in function.valueParameters) {
if (!parameter.isInlineParameter())
continue
for (parameter in function.valueParameters) {
if (!parameter.isInlineParameter())
continue
val valueArgument = expression.getValueArgument(parameter.index) ?: continue
if (!isInlineIrExpression(valueArgument))
continue
val valueArgument = expression.getValueArgument(parameter.index) ?: continue
if (!isInlineIrExpression(valueArgument))
continue
if (valueArgument is IrFunctionReference) {
ignoredFunctionReferences.add(valueArgument)
} else if (valueArgument is IrBlock) {
ignoredFunctionReferences.addIfNotNull(valueArgument.statements.filterIsInstance<IrFunctionReference>().singleOrNull())
if (valueArgument is IrFunctionReference) {
ignoredFunctionReferences.add(valueArgument)
} else if (valueArgument is IrBlock) {
ignoredFunctionReferences.addIfNotNull(valueArgument.statements.filterIsInstance<IrFunctionReference>().singleOrNull())
}
}
}
return super.visitFunctionAccess(expression)
}
// Ignore function references handled in SAM conversion
@@ -161,10 +130,6 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext)
// The type of the reference is KFunction<in A1, ..., in An, out R>
private val parameterTypes = (irFunctionReference.type as IrSimpleType).arguments.map { (it as IrTypeProjection).type }
private val argumentTypes = parameterTypes.dropLast(1)
private val returnType = parameterTypes.last()
private val useVararg
get() = argumentTypes.size >= FunctionInvokeDescriptor.BIG_ARITY
private val typeParameters = if (callee is IrConstructor)
callee.parentAsClass.typeParameters + callee.typeParameters
@@ -190,7 +155,10 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext)
fun build(): IrExpression {
val constructor = createConstructor()
val invokeMethod = createInvokeMethod()
createBridge(invokeMethod)
val functionClass = context.ir.symbols.getJvmFunctionClass(argumentTypes.size)
functionReferenceClass.superTypes += functionClass.typeWith(parameterTypes)
invokeMethod.overriddenSymbols += functionClass.functions.single { it.owner.name.asString() == "invoke" }
if (!isLambda) {
createGetSignatureMethod(functionGetSignature)
@@ -339,80 +307,6 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext)
}
}
// Build a bridge to the monomorphic invoke method. This is more elaborate than the usual BridgeLowering,
// since we have special handling for functions with large arity (> 22 arguments). Large arity functions
// are translated to functions with a single vararg argument, which checks the number of arguments and types
// dynamically.
private fun createBridge(invoke: IrSimpleFunction) {
// Add supertypes
val actualFunctionClass = if (useVararg)
context.ir.symbols.functionN
else
context.ir.symbols.getJvmFunctionClass(argumentTypes.size)
functionReferenceClass.superTypes += actualFunctionClass.typeWith(if (useVararg) listOf(returnType) else parameterTypes)
val superFunction = actualFunctionClass.owner.functions.find { it.name.asString() == "invoke" }!!
// Only add a bridge method when necessary
if (context.state.typeMapper.mapAsmMethod(superFunction.descriptor) ==
context.state.typeMapper.mapAsmMethod(invoke.descriptor)
) {
invoke.overriddenSymbols += superFunction.symbol
return
}
// Add the invoke bridge
functionReferenceClass.addFunction {
name = superFunction.name
returnType = context.irBuiltIns.anyNType
modality = Modality.FINAL
visibility = Visibilities.PUBLIC
origin = IrDeclarationOrigin.BRIDGE
}.apply {
overriddenSymbols += superFunction.symbol
dispatchReceiverParameter = parentAsClass.thisReceiver!!.copyTo(this)
if (useVararg)
valueParameters += superFunction.valueParameters[0].copyTo(this)
else
superFunction.valueParameters.forEach { valueParameters += it.copyTo(this, type = context.irBuiltIns.anyNType) }
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
// Check the number of arguments for large arity functions
if (useVararg) {
+irIfThen(
irNotEquals(
irCall(arraySizeProperty.getter!!).apply {
dispatchReceiver = irGet(valueParameters.single())
},
irInt(argumentTypes.size)
),
irCall(context.irBuiltIns.illegalArgumentExceptionSymbol).apply {
putValueArgument(0, irString("Expected ${argumentTypes.size} arguments"))
}
)
}
+irReturn(irCall(invoke).apply {
dispatchReceiver = irGet(dispatchReceiverParameter!!)
for (parameter in invoke.valueParameters) {
val index = parameter.index
val argument = if (useVararg) {
val argArray = irGet(valueParameters.single())
val argIndex = irInt(index)
irCallOp(arrayGetFun.symbol, context.irBuiltIns.anyNType, argArray, argIndex)
} else {
irGet(valueParameters[index])
}
putValueArgument(index, irImplicitCast(argument, argumentTypes[index]))
}
})
}
}
}
private fun buildOverride(superFunction: IrSimpleFunction, newReturnType: IrType = superFunction.returnType): IrSimpleFunction =
functionReferenceClass.addFunction {
setSourceRange(irFunctionReference)
@@ -497,14 +391,6 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext)
private fun IrClassSymbol.functionByName(name: String) = owner.functions.single { it.name.asString() == name }
private val arraySizeProperty by lazy {
context.irBuiltIns.arrayClass.owner.properties.single { it.name.toString() == "size" }
}
private val arrayGetFun by lazy {
context.irBuiltIns.arrayClass.functionByName("get")
}
private val functionReferenceReceiverField =
context.ir.symbols.functionReference.owner.declarations.single { it is IrField && it.name.toString() == "receiver" } as IrField
@@ -0,0 +1,180 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal val functionNVarargBridgePhase = makeIrFilePhase(
::FunctionNVarargBridgeLowering,
name = "FunctionBridgePhase",
description = "Add bridges for invoke functions with a large number of arguments"
)
// There are concrete function classes for functions with up to 22 arguments. Above that, we
// inherit from the generic FunctionN class which has a vararg invoke method. This phase
// adds a bridge method for such large arity functions, which checks the number of arguments
// dynamically.
private class FunctionNVarargBridgeLowering(val context: JvmBackendContext) :
FileLoweringPass, IrElementTransformerVoidWithContext() {
override fun lower(irFile: IrFile) = irFile.transformChildrenVoid(this)
// Change calls to big arity invoke functions to vararg calls.
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
if (expression.valueArgumentsCount < FunctionInvokeDescriptor.BIG_ARITY ||
!expression.symbol.owner.parentAsClass.defaultType.isFunctionOrKFunction() ||
expression.symbol.owner.name.asString() != "invoke")
return super.visitFunctionAccess(expression)
return IrCallImpl(
expression.startOffset, expression.endOffset,
expression.type, functionNInvokeFun, functionNInvokeFun.descriptor,
1, expression.origin
).apply {
putTypeArgument(0, expression.type)
dispatchReceiver = expression.dispatchReceiver
putValueArgument(0, IrVarargImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.ir.symbols.array.typeWith(context.irBuiltIns.anyNType),
context.irBuiltIns.anyNType,
(0 until expression.valueArgumentsCount).map { expression.getValueArgument(it)!! }
))
}
}
override fun visitClassNew(declaration: IrClass): IrStatement {
val bigArityFunctionSuperTypes = declaration.superTypes.filterIsInstance<IrSimpleType>().filter {
it.isFunctionType && it.arguments.size > FunctionInvokeDescriptor.BIG_ARITY
}
if (bigArityFunctionSuperTypes.isEmpty())
return super.visitClassNew(declaration)
declaration.transformChildrenVoid(this)
// Note that we allow classes with multiple function supertypes, so long as only one
// of them has more than 22 arguments.
// TODO: Add a proper diagnostic message in the frontend
assert(bigArityFunctionSuperTypes.size == 1) {
"Class has multiple big-arity function super types: ${bigArityFunctionSuperTypes.joinToString { it.render() }}"
}
// Fix super class
val superType = bigArityFunctionSuperTypes.single()
declaration.superTypes.remove(superType)
declaration.superTypes += context.ir.symbols.functionN.typeWith(
(superType.arguments.last() as IrTypeProjection).type
)
// Add vararg invoke bridge
val invokeFunction = declaration.functions.single {
it.name.asString() == "invoke" && it.valueParameters.size == superType.arguments.size - 1
}
invokeFunction.overriddenSymbols.clear()
declaration.addBridge(invokeFunction, functionNInvokeFun.owner)
return declaration
}
private fun IrClass.addBridge(invoke: IrSimpleFunction, superFunction: IrSimpleFunction) =
addFunction {
name = superFunction.name
returnType = context.irBuiltIns.anyNType
modality = Modality.FINAL
visibility = Visibilities.PUBLIC
origin = IrDeclarationOrigin.BRIDGE
}.apply {
overriddenSymbols += superFunction.symbol
dispatchReceiverParameter = thisReceiver!!.copyTo(this)
valueParameters += superFunction.valueParameters.single().copyTo(this)
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
// Check the number of arguments
val argumentCount = invoke.valueParameters.size
+irIfThen(
irNotEquals(
irCall(arraySizePropertyGetter).apply {
dispatchReceiver = irGet(valueParameters.single())
},
irInt(argumentCount)
),
irCall(context.irBuiltIns.illegalArgumentExceptionSymbol).apply {
putValueArgument(0, irString("Expected ${argumentCount} arguments"))
}
)
+irReturn(irCall(invoke).apply {
dispatchReceiver = irGet(dispatchReceiverParameter!!)
for (parameter in invoke.valueParameters) {
val index = parameter.index
val argArray = irGet(valueParameters.single())
val argument = irCallOp(arrayGetFun, context.irBuiltIns.anyNType, argArray, irInt(index))
putValueArgument(index, irImplicitCast(argument, invoke.valueParameters[index].type))
}
})
}
}
// Check if a type is an instance of kotlin.Function*, kotlin.jvm.functions.Function*
// or kotlin.reflect.KFunction*. Note that `IrType.isFunctionOrKFunction()` in IrTypeUtils
// does not check for the jvm specific kotlin.jvm.functions package and can't be used here.
private val IrType.isFunctionType: Boolean
get() {
val clazz = classOrNull?.owner ?: return false
val name = clazz.name.asString()
val fqName = clazz.parent.safeAs<IrPackageFragment>()?.fqName ?: return false
return when {
name.startsWith("Function") ->
fqName == KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME || fqName == FUNCTIONS_PACKAGE_FQ_NAME
name.startsWith("KFunction") ->
fqName == REFLECT_PACKAGE_FQ_NAME
else -> false
}
}
private val functionNInvokeFun =
context.ir.symbols.functionN.functions.single { it.owner.name.toString() == "invoke" }
private val arraySizePropertyGetter by lazy {
context.irBuiltIns.arrayClass.owner.properties.single { it.name.toString() == "size" }.getter!!
}
private val arrayGetFun by lazy {
context.irBuiltIns.arrayClass.functions.single { it.owner.name.toString() == "get" }
}
private val FUNCTIONS_PACKAGE_FQ_NAME =
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME
.child(Name.identifier("jvm"))
.child(Name.identifier("functions"))
private val REFLECT_PACKAGE_FQ_NAME =
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME
.child(Name.identifier("reflect"))
}
@@ -1,157 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.filterDeclarations
import org.jetbrains.kotlin.ir.util.findDeclaration
import org.jetbrains.kotlin.ir.util.isSubclassOf
import org.jetbrains.kotlin.name.Name
internal val functionNVarargInvokePhase = makeIrFilePhase(
::FunctionNVarargInvokeLowering,
name = "FunctionNVarargInvoke",
description = "Handle invoke functions with large number of arguments"
)
private class FunctionNVarargInvokeLowering(var context: JvmBackendContext) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
val invokeFunctions = irClass.filterDeclarations<IrSimpleFunction> { it.name.toString() == "invoke" }
if (invokeFunctions.isEmpty() ||
invokeFunctions.any { it.valueParameters.size > 0 && it.valueParameters.last().varargElementType != null } ||
invokeFunctions.all { it.valueParameters.size + (if (it.extensionReceiverParameter != null) 1 else 0) < FunctionInvokeDescriptor.Factory.BIG_ARITY }
) {
// No need to add a new vararg invoke method
return
}
val functionInvokes = invokeFunctions.filter { irClass.isSubclassOf(context.ir.symbols.getFunction(it.valueParameters.size).owner) }
if (functionInvokes.isEmpty()) return
irClass.declarations.add(generateVarargInvoke(irClass, functionInvokes))
}
private fun generateVarargInvoke(irClass: IrClass, invokesToDelegateTo: List<IrSimpleFunction>): IrFunction {
val backendContext = context
val descriptor = WrappedSimpleFunctionDescriptor()
return IrFunctionImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL,
symbol = IrSimpleFunctionSymbolImpl(descriptor),
name = Name.identifier("invoke"),
visibility = Visibilities.PUBLIC,
modality = Modality.OPEN,
returnType = context.irBuiltIns.anyNType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
).apply {
descriptor.bind(this)
parent = irClass
dispatchReceiverParameter = irClass.thisReceiver?.copyTo(this)
val varargParameterDescriptor = WrappedValueParameterDescriptor()
val varargParam = IrValueParameterImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL,
symbol = IrValueParameterSymbolImpl(varargParameterDescriptor),
name = Name.identifier("args"),
index = 0,
type = context.irBuiltIns.arrayClass.typeWith(context.irBuiltIns.anyNType),
varargElementType = context.irBuiltIns.anyNType,
isCrossinline = false,
isNoinline = false
).apply {
varargParameterDescriptor.bind(this)
}
varargParam.parent = this
valueParameters.add(varargParam)
val irBuilder = context.createIrBuilder(symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET)
body = irBuilder.irBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
val arrayGetFun =
backendContext.irBuiltIns.arrayClass.owner.findDeclaration<IrSimpleFunction> { it.name.toString() == "get" }!!
val arraySizeProperty = context.irBuiltIns.arrayClass.owner.findDeclaration<IrProperty> { it.name.toString() == "size" }!!
val numberOfArguments = irTemporary(irCall(arraySizeProperty.getter!!).apply {
dispatchReceiver = irGet(varargParam)
})
for (target in invokesToDelegateTo) {
+irIfThen(
backendContext.irBuiltIns.unitType,
irEquals(irGet(numberOfArguments), irInt(target.valueParameters.size)),
irReturn(
IrTypeOperatorCallImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
backendContext.irBuiltIns.anyNType,
IrTypeOperator.CAST,
target.returnType,
irCall(target).apply {
dispatchReceiver = irGet(dispatchReceiverParameter!!)
target.valueParameters.forEachIndexed { i, irValueParameter ->
val type = irValueParameter.type
putValueArgument(
i,
irBlock(resultType = type) {
val argValue = irTemporary(
irCallOp(
arrayGetFun.symbol,
context.irBuiltIns.anyNType,
irGet(varargParam),
irInt(i)
)
)
+irIfThen(
irNotIs(irGet(argValue), type),
irCall(context.irBuiltIns.illegalArgumentExceptionSymbol).apply {
putValueArgument(0, irString("Wrong type, expected $type"))
}
)
+irGet(argValue)
}
)
}
}
)
)
)
}
val throwMessage = invokesToDelegateTo.map { it.valueParameters.size.toString() }.joinToString(
prefix = "Expected ",
separator = " or ",
postfix = " arguments to invoke call"
)
+irCall(context.irBuiltIns.illegalArgumentExceptionSymbol).apply {
putValueArgument(0, irString(throwMessage))
}
}
}
}
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,6 +1,6 @@
// !LANGUAGE: +FunctionTypesWithBigArity
// WITH_RUNTIME
// TARGET_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: J.java
// import kotlin.jvm.functions.Arity;
@@ -20,7 +20,7 @@ public class J {
throw new AssertionError("Bad return value from function");
}
} catch (IllegalArgumentException e) {
if (i == 3 || i == 13 || i == 30 || i == 33) {
if (i == 30) {
throw new AssertionError(String.format("Call with %d arguments is expected to succeed", i), e);
}
// OK
@@ -35,7 +35,7 @@ public class J {
"Incorrect exception (IllegalArgumentException expected): " + e.getClass().getName() + ", i = " + i, e
);
}
if (i != 3 && i != 13 && i != 30 && i != 33) {
if (i != 30) {
throw new AssertionError ("IllegalArgumentException expected, but nothing was thrown, i = " + i);
}
}
@@ -47,9 +47,7 @@ public class J {
class Fun : (Int, Int, Int) -> Int,
(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int,
(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,
Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int,
(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,
Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int {
Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Int {
override fun invoke(p00: Int, p01: Int, p02: Int): Int = 303
override fun invoke(
@@ -62,13 +60,6 @@ class Fun : (Int, Int, Int) -> Int,
p10: Int, p11: Int, p12: Int, p13: Int, p14: Int, p15: Int, p16: Int, p17: Int, p18: Int, p19: Int,
p20: Int, p21: Int, p22: Int, p23: Int, p24: Int, p25: Int, p26: Int, p27: Int, p28: Int, p29: Int
): Int = 330
override fun invoke(
p00: Int, p01: Int, p02: Int, p03: Int, p04: Int, p05: Int, p06: Int, p07: Int, p08: Int, p09: Int,
p10: Int, p11: Int, p12: Int, p13: Int, p14: Int, p15: Int, p16: Int, p17: Int, p18: Int, p19: Int,
p20: Int, p21: Int, p22: Int, p23: Int, p24: Int, p25: Int, p26: Int, p27: Int, p28: Int, p29: Int,
p30: Int, p31: Int, p32: Int
): Int = 333
}
fun box(): String {
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
fun test() {
1.(fun Int.() = 2)()
}
@@ -11345,6 +11345,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/functions/bigArity/callFromJava.kt");
}
@TestMetadata("callFunViaVararg.kt")
public void testCallFunViaVararg() throws Exception {
runTest("compiler/testData/codegen/box/functions/bigArity/callFunViaVararg.kt");
}
@TestMetadata("callWithIncorrectNumberOfArguments.kt")
public void testCallWithIncorrectNumberOfArguments() throws Exception {
runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt");
@@ -11350,6 +11350,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/functions/bigArity/callFromJava.kt");
}
@TestMetadata("callFunViaVararg.kt")
public void testCallFunViaVararg() throws Exception {
runTest("compiler/testData/codegen/box/functions/bigArity/callFunViaVararg.kt");
}
@TestMetadata("callWithIncorrectNumberOfArguments.kt")
public void testCallWithIncorrectNumberOfArguments() throws Exception {
runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt");