Revert "JVM IR: Move direct invoke optimization into a separate pass"
This reverts commit f0760e0550.
The reason is that it leads to KT-53202.
This commit is contained in:
-6
@@ -43,12 +43,6 @@ public class FirLocalVariableTestGenerated extends AbstractFirLocalVariableTest
|
|||||||
runTest("compiler/testData/debug/localVariables/copyFunction.kt");
|
runTest("compiler/testData/debug/localVariables/copyFunction.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestMetadata("directInvoke.kt")
|
|
||||||
public void testDirectInvoke() throws Exception {
|
|
||||||
runTest("compiler/testData/debug/localVariables/directInvoke.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("doWhile.kt")
|
@TestMetadata("doWhile.kt")
|
||||||
public void testDoWhile() throws Exception {
|
public void testDoWhile() throws Exception {
|
||||||
|
|||||||
+8
-14
@@ -30,7 +30,12 @@ class IrInvokable(val invokable: IrValueDeclaration) : IrInlinable()
|
|||||||
class IrInlinableLambda(val function: IrSimpleFunction, val boundReceiver: 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.
|
// Return the underlying function for a lambda argument without bound or default parameters or varargs.
|
||||||
fun IrExpression.asInlinableFunctionReference(): IrFunctionReference? {
|
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)
|
||||||
|
}
|
||||||
// A lambda is represented as a block with a function declaration and a reference to it.
|
// 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.
|
// Inlinable function references are also a kind of lambda; bound receivers are represented as extension receivers.
|
||||||
if (this !is IrBlock || statements.size != 2)
|
if (this !is IrBlock || statements.size != 2)
|
||||||
@@ -44,18 +49,7 @@ fun IrExpression.asInlinableFunctionReference(): IrFunctionReference? {
|
|||||||
return null
|
return null
|
||||||
if (function.valueParameters.any { it.isVararg || it.defaultValue != null })
|
if (function.valueParameters.any { it.isVararg || it.defaultValue != null })
|
||||||
return null
|
return null
|
||||||
return reference
|
return IrInlinableLambda(function, reference.extensionReceiver?.let { builder.irTemporary(it) })
|
||||||
}
|
|
||||||
|
|
||||||
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 =
|
fun IrExpression.asInlinable(builder: IrStatementsBuilder<*>): IrInlinable =
|
||||||
@@ -104,7 +98,7 @@ private fun IrBody.move(
|
|||||||
|
|
||||||
// TODO use a generic inliner (e.g. JS/Native's FunctionInlining.Inliner)
|
// TODO use a generic inliner (e.g. JS/Native's FunctionInlining.Inliner)
|
||||||
// Inline simple function calls without type parameters, default parameters, or varargs.
|
// Inline simple function calls without type parameters, default parameters, or varargs.
|
||||||
fun IrFunction.inline(target: IrDeclarationParent, arguments: List<IrValueDeclaration> = listOf()): IrReturnableBlock =
|
private fun IrFunction.inline(target: IrDeclarationParent, arguments: List<IrValueDeclaration> = listOf()): IrReturnableBlock =
|
||||||
IrReturnableBlockImpl(startOffset, endOffset, returnType, IrReturnableBlockSymbolImpl(), null, symbol).apply {
|
IrReturnableBlockImpl(startOffset, endOffset, returnType, IrReturnableBlockSymbolImpl(), null, symbol).apply {
|
||||||
statements += body!!.move(this@inline, target, symbol, explicitParameters.zip(arguments).toMap()).statements
|
statements += body!!.move(this@inline, target, symbol, explicitParameters.zip(arguments).toMap()).statements
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
|||||||
import org.jetbrains.kotlin.diagnostics.BackendErrors
|
import org.jetbrains.kotlin.diagnostics.BackendErrors
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
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.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
@@ -312,6 +313,12 @@ class ExpressionCodegen(
|
|||||||
if (irFunction.isSuspend)
|
if (irFunction.isSuspend)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
// As a small optimization, don't generate nullability assertions in methods for directly invoked lambdas
|
||||||
|
if (irFunction is IrFunctionImpl && irFunction.attributeOwnerId in context.directInvokedLambdas) {
|
||||||
|
context.directInvokedLambdas.remove(irFunction.attributeOwnerId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
irFunction.extensionReceiverParameter?.let { generateNonNullAssertion(it) }
|
irFunction.extensionReceiverParameter?.let { generateNonNullAssertion(it) }
|
||||||
|
|
||||||
// Private operator functions don't have null checks on value parameters,
|
// Private operator functions don't have null checks on value parameters,
|
||||||
|
|||||||
@@ -287,7 +287,6 @@ private val jvmFilePhases = listOf(
|
|||||||
jvmLateinitLowering,
|
jvmLateinitLowering,
|
||||||
|
|
||||||
inlineCallableReferenceToLambdaPhase,
|
inlineCallableReferenceToLambdaPhase,
|
||||||
directInvokeLowering,
|
|
||||||
functionReferencePhase,
|
functionReferencePhase,
|
||||||
suspendLambdaPhase,
|
suspendLambdaPhase,
|
||||||
propertyReferenceDelegationPhase,
|
propertyReferenceDelegationPhase,
|
||||||
|
|||||||
-135
@@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2022 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.asInlinableFunctionReference
|
|
||||||
import org.jetbrains.kotlin.backend.common.ir.inline
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.at
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irBlock
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
|
||||||
import org.jetbrains.kotlin.ir.util.dump
|
|
||||||
import org.jetbrains.kotlin.ir.util.explicitParameters
|
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
|
||||||
|
|
||||||
internal val directInvokeLowering = makeIrFilePhase(
|
|
||||||
::DirectInvokeLowering,
|
|
||||||
name = "DirectInvokes",
|
|
||||||
description = "Inline directly invoked lambdas and replace invoked function references with calls"
|
|
||||||
)
|
|
||||||
|
|
||||||
private class DirectInvokeLowering(private val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
|
||||||
override fun lower(irFile: IrFile) = irFile.transformChildrenVoid()
|
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
|
||||||
val function = expression.symbol.owner
|
|
||||||
val receiver = expression.dispatchReceiver
|
|
||||||
if (receiver == null || function.name != OperatorNameConventions.INVOKE)
|
|
||||||
return super.visitCall(expression)
|
|
||||||
|
|
||||||
val result = when {
|
|
||||||
// TODO deal with type parameters somehow?
|
|
||||||
// It seems we can't encounter them in the code written by user,
|
|
||||||
// but this might be important later if we actually perform inlining and optimizations on IR.
|
|
||||||
receiver is IrFunctionReference && receiver.symbol.owner.typeParameters.isEmpty() ->
|
|
||||||
visitFunctionReferenceInvoke(expression, receiver)
|
|
||||||
|
|
||||||
receiver is IrBlock ->
|
|
||||||
receiver.asInlinableFunctionReference()?.takeIf { it.extensionReceiver == null }?.let { reference ->
|
|
||||||
visitLambdaInvoke(expression, reference)
|
|
||||||
} ?: expression
|
|
||||||
|
|
||||||
else ->
|
|
||||||
expression
|
|
||||||
}
|
|
||||||
|
|
||||||
result.transformChildrenVoid()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitLambdaInvoke(expression: IrCall, reference: IrFunctionReference): IrExpression {
|
|
||||||
val scope = currentScope!!.scope
|
|
||||||
val declarationParent = scope.getLocalDeclarationParent()
|
|
||||||
val function = reference.symbol.owner
|
|
||||||
if (expression.valueArgumentsCount == 0) {
|
|
||||||
return function.inline(declarationParent)
|
|
||||||
}
|
|
||||||
return context.createIrBuilder(scope.scopeOwnerSymbol).run {
|
|
||||||
at(expression)
|
|
||||||
irBlock {
|
|
||||||
val arguments = function.explicitParameters.withIndex().map { (index, parameter) ->
|
|
||||||
val argument = expression.getValueArgument(index)!!
|
|
||||||
IrVariableImpl(
|
|
||||||
argument.startOffset, argument.endOffset, IrDeclarationOrigin.DEFINED, IrVariableSymbolImpl(), parameter.name,
|
|
||||||
parameter.type, isVar = false, isConst = false, isLateinit = false
|
|
||||||
).apply {
|
|
||||||
parent = declarationParent
|
|
||||||
initializer = argument
|
|
||||||
+this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+function.inline(declarationParent, arguments)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitFunctionReferenceInvoke(expression: IrCall, receiver: IrFunctionReference): IrExpression =
|
|
||||||
when (val irFun = receiver.symbol.owner) {
|
|
||||||
is IrSimpleFunction ->
|
|
||||||
IrCallImpl(
|
|
||||||
expression.startOffset, expression.endOffset, expression.type, irFun.symbol,
|
|
||||||
typeArgumentsCount = irFun.typeParameters.size, valueArgumentsCount = irFun.valueParameters.size
|
|
||||||
).apply {
|
|
||||||
copyReceiverAndValueArgumentsForDirectInvoke(receiver, expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
is IrConstructor ->
|
|
||||||
IrConstructorCallImpl(
|
|
||||||
expression.startOffset, expression.endOffset, expression.type, irFun.symbol,
|
|
||||||
typeArgumentsCount = irFun.typeParameters.size,
|
|
||||||
constructorTypeArgumentsCount = 0,
|
|
||||||
valueArgumentsCount = irFun.valueParameters.size
|
|
||||||
).apply {
|
|
||||||
copyReceiverAndValueArgumentsForDirectInvoke(receiver, expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
else ->
|
|
||||||
throw AssertionError("Simple function or constructor expected: ${irFun.render()}")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrFunctionAccessExpression.copyReceiverAndValueArgumentsForDirectInvoke(
|
|
||||||
irFunRef: IrFunctionReference,
|
|
||||||
irInvokeCall: IrFunctionAccessExpression
|
|
||||||
) {
|
|
||||||
val irFun = irFunRef.symbol.owner
|
|
||||||
var invokeArgIndex = 0
|
|
||||||
if (irFun.dispatchReceiverParameter != null) {
|
|
||||||
dispatchReceiver = irFunRef.dispatchReceiver ?: irInvokeCall.getValueArgument(invokeArgIndex++)
|
|
||||||
}
|
|
||||||
if (irFun.extensionReceiverParameter != null) {
|
|
||||||
extensionReceiver = irFunRef.extensionReceiver ?: irInvokeCall.getValueArgument(invokeArgIndex++)
|
|
||||||
}
|
|
||||||
if (invokeArgIndex + valueArgumentsCount != irInvokeCall.valueArgumentsCount) {
|
|
||||||
throw AssertionError("Mismatching value arguments: $invokeArgIndex arguments used for receivers\n${irInvokeCall.dump()}")
|
|
||||||
}
|
|
||||||
for (i in 0 until valueArgumentsCount) {
|
|
||||||
putValueArgument(i, irInvokeCall.getValueArgument(invokeArgIndex++))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+106
-1
@@ -7,9 +7,10 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
import org.jetbrains.kotlin.backend.common.ir.moveBodyTo
|
import org.jetbrains.kotlin.backend.common.ir.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.SamEqualsHashCodeMethodsGenerator
|
import org.jetbrains.kotlin.backend.common.lower.SamEqualsHashCodeMethodsGenerator
|
||||||
import org.jetbrains.kotlin.backend.common.lower.VariableRemapper
|
import org.jetbrains.kotlin.backend.common.lower.VariableRemapper
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.parents
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
|||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.*
|
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
@@ -37,6 +39,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
|||||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
internal val functionReferencePhase = makeIrFilePhase(
|
internal val functionReferencePhase = makeIrFilePhase(
|
||||||
::FunctionReferenceLowering,
|
::FunctionReferenceLowering,
|
||||||
@@ -100,6 +103,108 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
return FunctionReferenceBuilder(reference).build()
|
return FunctionReferenceBuilder(reference).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
if (expression.symbol.owner.isInvokeOperator()) {
|
||||||
|
when (val receiver = expression.dispatchReceiver) {
|
||||||
|
is IrFunctionReference -> {
|
||||||
|
rewriteDirectInvokeToFunctionReference(expression, receiver)?.let {
|
||||||
|
it.transformChildrenVoid()
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is IrBlock -> {
|
||||||
|
val last = receiver.statements.last()
|
||||||
|
if (last is IrFunctionReference) {
|
||||||
|
rewriteDirectInvokeToLambda(expression, receiver, last)?.let {
|
||||||
|
it.transformChildrenVoid()
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunction.isInvokeOperator(): Boolean {
|
||||||
|
// For now, it's enough to check that the function name is 'invoke',
|
||||||
|
// because later we are looking at the dispatch receiver and check whether it's a function reference
|
||||||
|
// or a block returning a function reference.
|
||||||
|
return name == OperatorNameConventions.INVOKE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rewriteDirectInvokeToLambda(irInvokeCall: IrCall, irBlock: IrBlock, lastFunRef: IrFunctionReference): IrExpression? {
|
||||||
|
val callee = lastFunRef.symbol.owner
|
||||||
|
if (callee.origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA && !callee.isAnonymousFunction)
|
||||||
|
return null
|
||||||
|
if (callee.parents.any { it is IrSimpleFunction && it.isInline }) {
|
||||||
|
// TODO investigate why inliner gets confused when we pass it a function with some optimized direct invoke.
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val irDirectCall = rewriteDirectInvokeToFunctionReference(irInvokeCall, lastFunRef)
|
||||||
|
?: return null
|
||||||
|
|
||||||
|
// We track instances of IrFunctionImpl corresponding to direct invoked lambdas,
|
||||||
|
// so we can perform optimization on it later in ExpressionCodegen.kt
|
||||||
|
if (callee is IrFunctionImpl) context.directInvokedLambdas.add(callee.attributeOwnerId)
|
||||||
|
val newBlock = IrBlockImpl(irBlock.startOffset, irBlock.endOffset, irDirectCall.type)
|
||||||
|
newBlock.statements.addAll(irBlock.statements)
|
||||||
|
newBlock.statements[newBlock.statements.lastIndex] = irDirectCall
|
||||||
|
return newBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rewriteDirectInvokeToFunctionReference(irInvokeCall: IrCall, irFunRef: IrFunctionReference): IrExpression? {
|
||||||
|
// TODO deal with type parameters somehow?
|
||||||
|
// It seems we can't encounter them in the code written by user,
|
||||||
|
// but this might be important later if we actually perform inlining and optimizations on IR.
|
||||||
|
return when (val irFun = irFunRef.symbol.owner) {
|
||||||
|
is IrSimpleFunction -> {
|
||||||
|
if (irFun.typeParameters.isNotEmpty()) return null
|
||||||
|
IrCallImpl(
|
||||||
|
irInvokeCall.startOffset, irInvokeCall.endOffset, irInvokeCall.type,
|
||||||
|
irFun.symbol,
|
||||||
|
typeArgumentsCount = irFun.typeParameters.size, valueArgumentsCount = irFun.valueParameters.size
|
||||||
|
).apply {
|
||||||
|
copyReceiverAndValueArgumentsForDirectInvoke(irFunRef, irInvokeCall)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is IrConstructor ->
|
||||||
|
IrConstructorCallImpl(
|
||||||
|
irInvokeCall.startOffset, irInvokeCall.endOffset, irInvokeCall.type,
|
||||||
|
irFun.symbol,
|
||||||
|
typeArgumentsCount = irFun.typeParameters.size,
|
||||||
|
constructorTypeArgumentsCount = 0,
|
||||||
|
valueArgumentsCount = irFun.valueParameters.size
|
||||||
|
).apply {
|
||||||
|
copyReceiverAndValueArgumentsForDirectInvoke(irFunRef, irInvokeCall)
|
||||||
|
}
|
||||||
|
else ->
|
||||||
|
throw AssertionError("Simple function or constructor expected: ${irFun.render()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunctionAccessExpression.copyReceiverAndValueArgumentsForDirectInvoke(
|
||||||
|
irFunRef: IrFunctionReference,
|
||||||
|
irInvokeCall: IrFunctionAccessExpression
|
||||||
|
) {
|
||||||
|
val irFun = irFunRef.symbol.owner
|
||||||
|
var invokeArgIndex = 0
|
||||||
|
if (irFun.dispatchReceiverParameter != null) {
|
||||||
|
dispatchReceiver = irFunRef.dispatchReceiver ?: irInvokeCall.getValueArgument(invokeArgIndex++)
|
||||||
|
}
|
||||||
|
if (irFun.extensionReceiverParameter != null) {
|
||||||
|
extensionReceiver = irFunRef.extensionReceiver ?: irInvokeCall.getValueArgument(invokeArgIndex++)
|
||||||
|
}
|
||||||
|
if (invokeArgIndex + valueArgumentsCount != irInvokeCall.valueArgumentsCount) {
|
||||||
|
throw AssertionError("Mismatching value arguments: $invokeArgIndex arguments used for receivers\n${irInvokeCall.dump()}")
|
||||||
|
}
|
||||||
|
for (i in 0 until valueArgumentsCount) {
|
||||||
|
putValueArgument(i, irInvokeCall.getValueArgument(invokeArgIndex++))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun wrapLambdaReferenceWithIndySamConversion(
|
private fun wrapLambdaReferenceWithIndySamConversion(
|
||||||
expression: IrBlock,
|
expression: IrBlock,
|
||||||
reference: IrFunctionReference,
|
reference: IrFunctionReference,
|
||||||
|
|||||||
@@ -149,6 +149,8 @@ class JvmBackendContext(
|
|||||||
|
|
||||||
val inlineMethodGenerationLock = Any()
|
val inlineMethodGenerationLock = Any()
|
||||||
|
|
||||||
|
val directInvokedLambdas = mutableListOf<IrAttributeContainer>()
|
||||||
|
|
||||||
val publicAbiSymbols = mutableSetOf<IrClassSymbol>()
|
val publicAbiSymbols = mutableSetOf<IrClassSymbol>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
public final class Class /* Class*/ {
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
private final java.lang.String notNullVal;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
private final java.lang.String privateNN;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
private java.lang.String notNullVar;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
private final java.lang.String nullableVal;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
private final java.lang.String privateN;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
private java.lang.String nullableVar;
|
||||||
|
|
||||||
|
public java.lang.String lateInitVar;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public final java.lang.String getNotNullValWithGet();// getNotNullValWithGet()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public final java.lang.String getNotNullVarWithGetSet();// getNotNullVarWithGetSet()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public final java.lang.String getNullableValWithGet();// getNullableValWithGet()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public final java.lang.String getNullableVarWithGetSet();// getNullableVarWithGetSet()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public final java.lang.String notNullWithN();// notNullWithN()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public final java.lang.String nullableWithNN();// nullableWithNN()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public final java.lang.String getLateInitVar();// getLateInitVar()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public final java.lang.String getNotNullVal();// getNotNullVal()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public final java.lang.String getNotNullVar();// getNotNullVar()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public final java.lang.String notNull(@org.jetbrains.annotations.NotNull() java.lang.String);// notNull(java.lang.String)
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public final java.lang.String notNullWithNN();// notNullWithNN()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public final void setNullableVarWithGetSet(@org.jetbrains.annotations.Nullable() java.lang.String);// setNullableVarWithGetSet(java.lang.String)
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public final java.lang.String getNullableVal();// getNullableVal()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public final java.lang.String getNullableVar();// getNullableVar()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public final java.lang.String nullable(@org.jetbrains.annotations.Nullable() java.lang.String);// nullable(java.lang.String)
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public final java.lang.String nullableWithN();// nullableWithN()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public final void setNotNullVarWithGetSet(@org.jetbrains.annotations.NotNull() java.lang.String);// setNotNullVarWithGetSet(java.lang.String)
|
||||||
|
|
||||||
|
private static final java.lang.String notNullVal$lambda$2();// notNullVal$lambda$2()
|
||||||
|
|
||||||
|
private static final java.lang.String notNullVar$lambda$3();// notNullVar$lambda$3()
|
||||||
|
|
||||||
|
private static final java.lang.String nullableVal$lambda$0();// nullableVal$lambda$0()
|
||||||
|
|
||||||
|
private static final java.lang.String nullableVar$lambda$1();// nullableVar$lambda$1()
|
||||||
|
|
||||||
|
private static final java.lang.String privateN$lambda$5();// privateN$lambda$5()
|
||||||
|
|
||||||
|
private static final java.lang.String privateNN$lambda$4();// privateNN$lambda$4()
|
||||||
|
|
||||||
|
public Class();// .ctor()
|
||||||
|
|
||||||
|
public final void setLateInitVar(@org.jetbrains.annotations.NotNull() java.lang.String);// setLateInitVar(java.lang.String)
|
||||||
|
|
||||||
|
public final void setNotNullVar(@org.jetbrains.annotations.NotNull() java.lang.String);// setNotNullVar(java.lang.String)
|
||||||
|
|
||||||
|
public final void setNullableVar(@org.jetbrains.annotations.Nullable() java.lang.String);// setNullableVar(java.lang.String)
|
||||||
|
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
public final class ClassObjectField /* ClassObjectField*/ {
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public static final ClassObjectField.Companion Companion;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
private static final java.lang.String x;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
private static final java.lang.String y;
|
||||||
|
|
||||||
|
private static final java.lang.String x$lambda$0();// x$lambda$0()
|
||||||
|
|
||||||
|
private static final java.lang.String y$lambda$1();// y$lambda$1()
|
||||||
|
|
||||||
|
public ClassObjectField();// .ctor()
|
||||||
|
|
||||||
|
|
||||||
|
public static final class Companion /* ClassObjectField.Companion*/ {
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public final java.lang.String getX();// getX()
|
||||||
|
|
||||||
|
private Companion();// .ctor()
|
||||||
|
|
||||||
|
}}
|
||||||
+92
@@ -0,0 +1,92 @@
|
|||||||
|
public final class FileFacadeKt /* FileFacadeKt*/ {
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
private static final java.lang.String notNullVal;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
private static final java.lang.String privateNn;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
private static java.lang.String notNullVar;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
private static final java.lang.String nullableVal;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
private static final java.lang.String privateN;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
private static java.lang.String nullableVar;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public static final java.lang.String getNotNullValWithGet();// getNotNullValWithGet()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public static final java.lang.String getNotNullVarWithGetSet();// getNotNullVarWithGetSet()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public static final java.lang.String getNullableValWithGet();// getNullableValWithGet()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public static final java.lang.String getNullableVarWithGetSet();// getNullableVarWithGetSet()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public static final java.lang.String notNullWithN();// notNullWithN()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public static final java.lang.String nullableWithNN();// nullableWithNN()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public static final java.lang.String getNotNullVal();// getNotNullVal()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public static final java.lang.String getNotNullVar();// getNotNullVar()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public static final java.lang.String notNull(@org.jetbrains.annotations.NotNull() java.lang.String);// notNull(java.lang.String)
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public static final java.lang.String notNullWithNN();// notNullWithNN()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public static final void setNullableVarWithGetSet(@org.jetbrains.annotations.Nullable() java.lang.String);// setNullableVarWithGetSet(java.lang.String)
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public static final java.lang.String getNullableVal();// getNullableVal()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public static final java.lang.String getNullableVar();// getNullableVar()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public static final java.lang.String nullable(@org.jetbrains.annotations.Nullable() java.lang.String);// nullable(java.lang.String)
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public static final java.lang.String nullableWithN();// nullableWithN()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.Nullable()
|
||||||
|
public static final void setNotNullVarWithGetSet(@org.jetbrains.annotations.NotNull() java.lang.String);// setNotNullVarWithGetSet(java.lang.String)
|
||||||
|
|
||||||
|
private static final java.lang.String notNullVal$lambda$2();// notNullVal$lambda$2()
|
||||||
|
|
||||||
|
private static final java.lang.String notNullVar$lambda$3();// notNullVar$lambda$3()
|
||||||
|
|
||||||
|
private static final java.lang.String nullableVal$lambda$0();// nullableVal$lambda$0()
|
||||||
|
|
||||||
|
private static final java.lang.String nullableVar$lambda$1();// nullableVar$lambda$1()
|
||||||
|
|
||||||
|
private static final java.lang.String privateFun(java.lang.String, java.lang.String);// privateFun(java.lang.String, java.lang.String)
|
||||||
|
|
||||||
|
private static final java.lang.String privateN$lambda$5();// privateN$lambda$5()
|
||||||
|
|
||||||
|
private static final java.lang.String privateNn$lambda$4();// privateNn$lambda$4()
|
||||||
|
|
||||||
|
public static final void setNotNullVar(@org.jetbrains.annotations.NotNull() java.lang.String);// setNotNullVar(java.lang.String)
|
||||||
|
|
||||||
|
public static final void setNullableVar(@org.jetbrains.annotations.Nullable() java.lang.String);// setNullableVar(java.lang.String)
|
||||||
|
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
public final class C /* C*/ implements Tr {
|
||||||
|
private final int v;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public java.lang.Integer foo();// foo()
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public java.lang.Integer getV();// getV()
|
||||||
|
|
||||||
|
private static final int v$lambda$0();// v$lambda$0()
|
||||||
|
|
||||||
|
public C();// .ctor()
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
public final class A /* pack.A*/ {
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
private static java.lang.String v;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public static final java.lang.String cv = "A" /* initializer type: java.lang.String */ /* constant value A */;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public static final pack.A INSTANCE;
|
||||||
|
|
||||||
|
private static final int c;
|
||||||
|
|
||||||
|
public static final int cc = 1 /* initializer type: int */ /* constant value 1 */;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public final java.lang.String getV();// getV()
|
||||||
|
|
||||||
|
private A();// .ctor()
|
||||||
|
|
||||||
|
private static final int c$lambda$0();// c$lambda$0()
|
||||||
|
|
||||||
|
private static final java.lang.String v$lambda$1();// v$lambda$1()
|
||||||
|
|
||||||
|
public final int f();// f()
|
||||||
|
|
||||||
|
public final int getC();// getC()
|
||||||
|
|
||||||
|
public final void setV(@org.jetbrains.annotations.NotNull() java.lang.String);// setV(java.lang.String)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
public final class C /* C*/ {
|
||||||
|
@kotlin.jvm.JvmField()
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public static final java.lang.String foo;
|
||||||
|
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public static final C.Companion Companion;
|
||||||
|
|
||||||
|
private static final java.lang.String foo$lambda$0();// foo$lambda$0()
|
||||||
|
|
||||||
|
public C();// .ctor()
|
||||||
|
|
||||||
|
|
||||||
|
public static final class Companion /* C.Companion*/ {
|
||||||
|
private Companion();// .ctor()
|
||||||
|
|
||||||
|
}}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
public final class C /* C*/ {
|
||||||
|
@kotlin.jvm.JvmField()
|
||||||
|
@org.jetbrains.annotations.NotNull()
|
||||||
|
public final java.lang.String foo;
|
||||||
|
|
||||||
|
private static final java.lang.String foo$lambda$0();// foo$lambda$0()
|
||||||
|
|
||||||
|
public C();// .ctor()
|
||||||
|
|
||||||
|
}
|
||||||
@@ -30,6 +30,10 @@ public final class foo/Kotlin : java/lang/Object {
|
|||||||
@Lfoo/TypeAnn;([name="2"]) : METHOD_RETURN, null
|
@Lfoo/TypeAnn;([name="2"]) : METHOD_RETURN, null
|
||||||
@Lfoo/TypeAnnBinary;([]) : METHOD_RETURN, null // invisible
|
@Lfoo/TypeAnnBinary;([]) : METHOD_RETURN, null // invisible
|
||||||
|
|
||||||
|
private final static java.lang.String foo4$lambda$0(foo.Kotlin this$0)
|
||||||
|
@Lfoo/TypeAnn;([name="2"]) : METHOD_RETURN, null
|
||||||
|
@Lfoo/TypeAnnBinary;([]) : METHOD_RETURN, null // invisible
|
||||||
|
|
||||||
public final void foo5()
|
public final void foo5()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
// FILE: test.kt
|
|
||||||
fun box() {
|
|
||||||
{ a: String, b: String->
|
|
||||||
a + b
|
|
||||||
}("O", "K")
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPECTATIONS
|
|
||||||
// EXPECTATIONS JVM_IR
|
|
||||||
// test.kt:5 box:
|
|
||||||
// test.kt:4 box: a:java.lang.String="O":java.lang.String, b:java.lang.String="K":java.lang.String
|
|
||||||
// EXPECTATIONS JVM
|
|
||||||
// test.kt:3 box:
|
|
||||||
// test.kt:5 box:
|
|
||||||
// test.kt:4 invoke: a:java.lang.String="O":java.lang.String, b:java.lang.String="K":java.lang.String
|
|
||||||
// test.kt:5 box:
|
|
||||||
// EXPECTATIONS
|
|
||||||
// test.kt:6 box:
|
|
||||||
@@ -7,11 +7,11 @@ fun box() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXPECTATIONS
|
// EXPECTATIONS
|
||||||
// EXPECTATIONS JVM_IR
|
// test.kt:4 box
|
||||||
// test.kt:5 box
|
|
||||||
// EXPECTATIONS JVM
|
// EXPECTATIONS JVM
|
||||||
// test.kt:4 box
|
|
||||||
// test.kt:5 invoke
|
// test.kt:5 invoke
|
||||||
// test.kt:4 box
|
// EXPECTATIONS JVM_IR
|
||||||
|
// test.kt:5 box$lambda$0
|
||||||
// EXPECTATIONS
|
// EXPECTATIONS
|
||||||
|
// test.kt:4 box
|
||||||
// test.kt:7 box
|
// test.kt:7 box
|
||||||
|
|||||||
-6
@@ -43,12 +43,6 @@ public class IrLocalVariableTestGenerated extends AbstractIrLocalVariableTest {
|
|||||||
runTest("compiler/testData/debug/localVariables/copyFunction.kt");
|
runTest("compiler/testData/debug/localVariables/copyFunction.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestMetadata("directInvoke.kt")
|
|
||||||
public void testDirectInvoke() throws Exception {
|
|
||||||
runTest("compiler/testData/debug/localVariables/directInvoke.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("doWhile.kt")
|
@TestMetadata("doWhile.kt")
|
||||||
public void testDoWhile() throws Exception {
|
public void testDoWhile() throws Exception {
|
||||||
|
|||||||
-6
@@ -43,12 +43,6 @@ public class LocalVariableTestGenerated extends AbstractLocalVariableTest {
|
|||||||
runTest("compiler/testData/debug/localVariables/copyFunction.kt");
|
runTest("compiler/testData/debug/localVariables/copyFunction.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestMetadata("directInvoke.kt")
|
|
||||||
public void testDirectInvoke() throws Exception {
|
|
||||||
runTest("compiler/testData/debug/localVariables/directInvoke.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("doWhile.kt")
|
@TestMetadata("doWhile.kt")
|
||||||
public void testDoWhile() throws Exception {
|
public void testDoWhile() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user