JVM IR: Move direct invoke optimization into a separate pass

This also changes the transformation to inline the body of a directly
invoked lambda rather than producing a call to an anonymous local
function. The latter is unsupported in inline functions and problematic
from an ABI perspective, since it results in functions whose name
depends on the entire source code up to this point.
This commit is contained in:
Steven Schäfer
2022-06-13 13:57:54 +02:00
committed by Alexander Udalov
parent 7d59c7689c
commit f0760e0550
12 changed files with 192 additions and 132 deletions
@@ -30,12 +30,7 @@ class IrInvokable(val invokable: IrValueDeclaration) : IrInlinable()
class IrInlinableLambda(val function: IrSimpleFunction, val boundReceiver: IrValueDeclaration?) : IrInlinable()
// Return the underlying function for a lambda argument without bound or default parameters or varargs.
private fun IrExpression.asInlinableLambda(builder: IrStatementsBuilder<*>): IrInlinableLambda? {
if (this is IrFunctionExpression) {
if (function.valueParameters.any { it.isVararg || it.defaultValue != null })
return null
return IrInlinableLambda(function, null)
}
fun IrExpression.asInlinableFunctionReference(): IrFunctionReference? {
// A lambda is represented as a block with a function declaration and a reference to it.
// Inlinable function references are also a kind of lambda; bound receivers are represented as extension receivers.
if (this !is IrBlock || statements.size != 2)
@@ -49,7 +44,18 @@ private fun IrExpression.asInlinableLambda(builder: IrStatementsBuilder<*>): IrI
return null
if (function.valueParameters.any { it.isVararg || it.defaultValue != null })
return null
return IrInlinableLambda(function, reference.extensionReceiver?.let { builder.irTemporary(it) })
return reference
}
private fun IrExpression.asInlinableLambda(builder: IrStatementsBuilder<*>): IrInlinableLambda? {
if (this is IrFunctionExpression) {
if (function.valueParameters.any { it.isVararg || it.defaultValue != null })
return null
return IrInlinableLambda(function, null)
}
return asInlinableFunctionReference()?.let { reference ->
IrInlinableLambda(reference.symbol.owner as IrSimpleFunction, reference.extensionReceiver?.let { builder.irTemporary(it) })
}
}
fun IrExpression.asInlinable(builder: IrStatementsBuilder<*>): IrInlinable =
@@ -98,7 +104,7 @@ private fun IrBody.move(
// TODO use a generic inliner (e.g. JS/Native's FunctionInlining.Inliner)
// Inline simple function calls without type parameters, default parameters, or varargs.
private fun IrFunction.inline(target: IrDeclarationParent, arguments: List<IrValueDeclaration> = listOf()): IrReturnableBlock =
fun IrFunction.inline(target: IrDeclarationParent, arguments: List<IrValueDeclaration> = listOf()): IrReturnableBlock =
IrReturnableBlockImpl(startOffset, endOffset, returnType, IrReturnableBlockSymbolImpl(), null, symbol).apply {
statements += body!!.move(this@inline, target, symbol, explicitParameters.zip(arguments).toMap()).statements
}