Generate fake variables for default lambdas during inline
#KT-51557 Fixed
This commit is contained in:
@@ -77,7 +77,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
|||||||
.mapTo(mutableSetOf()) { parameters.getDeclarationSlot(it) }
|
.mapTo(mutableSetOf()) { parameters.getDeclarationSlot(it) }
|
||||||
)
|
)
|
||||||
for (info in infos) {
|
for (info in infos) {
|
||||||
val lambda = DefaultLambda(info, sourceCompiler)
|
val lambda = DefaultLambda(info, sourceCompiler, node.name.substringBeforeLast("\$default"))
|
||||||
parameters.getParameterByDeclarationSlot(info.offset).functionalArgument = lambda
|
parameters.getParameterByDeclarationSlot(info.offset).functionalArgument = lambda
|
||||||
if (info.needReification) {
|
if (info.needReification) {
|
||||||
lambda.reifiedTypeParametersUsages.mergeAll(reifiedTypeInliner.reifyInstructions(lambda.node.node))
|
lambda.reifiedTypeParametersUsages.mergeAll(reifiedTypeInliner.reifyInstructions(lambda.node.node))
|
||||||
|
|||||||
@@ -7,13 +7,12 @@ package org.jetbrains.kotlin.codegen.inline
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.isCoroutineSuperClass
|
import org.jetbrains.kotlin.codegen.coroutines.isCoroutineSuperClass
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.org.objectweb.asm.ClassReader
|
import org.jetbrains.org.objectweb.asm.*
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
|
||||||
import org.jetbrains.org.objectweb.asm.Label
|
|
||||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||||
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
|
|
||||||
interface FunctionalArgument
|
interface FunctionalArgument
|
||||||
|
|
||||||
@@ -75,7 +74,8 @@ abstract class ExpressionLambda : LambdaInfo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DefaultLambda(info: ExtractedDefaultLambda, sourceCompiler: SourceCompilerForInline) : LambdaInfo() {
|
class DefaultLambda(info: ExtractedDefaultLambda, sourceCompiler: SourceCompilerForInline, private val functionName: String) :
|
||||||
|
LambdaInfo() {
|
||||||
val isBoundCallableReference: Boolean
|
val isBoundCallableReference: Boolean
|
||||||
|
|
||||||
override val lambdaClassType: Type = info.type
|
override val lambdaClassType: Type = info.type
|
||||||
@@ -132,7 +132,30 @@ class DefaultLambda(info: ExtractedDefaultLambda, sourceCompiler: SourceCompiler
|
|||||||
capturedParamDesc(fieldNode.name, Type.getType(fieldNode.desc), isSuspend = false)
|
capturedParamDesc(fieldNode.name, Type.getType(fieldNode.desc), isSuspend = false)
|
||||||
}?.toList() ?: emptyList()
|
}?.toList() ?: emptyList()
|
||||||
isBoundCallableReference = isReference && capturedVars.isNotEmpty()
|
isBoundCallableReference = isReference && capturedVars.isNotEmpty()
|
||||||
node = loadDefaultLambdaBody(classBytes, lambdaClassType, isPropertyReference)
|
val (originNode, classSmap) = loadDefaultLambdaBody(classBytes, lambdaClassType, isPropertyReference)
|
||||||
|
node = SMAPAndMethodNode(createNodeWithFakeVariables(originNode), classSmap)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createNodeWithFakeVariables(originNode: MethodNode): MethodNode {
|
||||||
|
val withFakeVariable =
|
||||||
|
MethodNode(originNode.access, originNode.name, originNode.desc, originNode.signature, originNode.exceptions?.toTypedArray())
|
||||||
|
val fakeVarIndex = originNode.maxLocals
|
||||||
|
originNode.accept(withFakeVariable)
|
||||||
|
val startLabel =
|
||||||
|
withFakeVariable.instructions.first as? LabelNode ?: LabelNode().apply { withFakeVariable.instructions.insert(this) }
|
||||||
|
val endLabel = withFakeVariable.instructions.last as? LabelNode ?: LabelNode().apply { withFakeVariable.instructions.add(this) }
|
||||||
|
withFakeVariable.instructions.insert(startLabel, VarInsnNode(Opcodes.ISTORE, fakeVarIndex))
|
||||||
|
withFakeVariable.instructions.insert(startLabel, LdcInsnNode(0))
|
||||||
|
|
||||||
|
withFakeVariable.localVariables.add(
|
||||||
|
LocalVariableNode(
|
||||||
|
"$LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT-$functionName-" + lambdaClassType.internalName.substringAfterLast(
|
||||||
|
'/'
|
||||||
|
), Type.INT_TYPE.descriptor, null, startLabel, endLabel, fakeVarIndex
|
||||||
|
)
|
||||||
|
)
|
||||||
|
withFakeVariable.maxLocals = withFakeVariable.maxLocals + 1
|
||||||
|
return withFakeVariable
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
|||||||
+6
@@ -3442,6 +3442,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("defaultLambda.kt")
|
||||||
|
public void testDefaultLambda() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/inline/defaultLambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("deleteClassOnTransformation.kt")
|
@TestMetadata("deleteClassOnTransformation.kt")
|
||||||
public void testDeleteClassOnTransformation() throws Exception {
|
public void testDeleteClassOnTransformation() throws Exception {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
inline fun <reified T> inlineFun(lambda: () -> String = { T::class.java.simpleName }): String {
|
||||||
|
return lambda()
|
||||||
|
}
|
||||||
|
|
||||||
|
class OK
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return inlineFun<OK>()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1 LOCALVARIABLE \$i\$a\$-inlineFun-DefaultLambdaKt\$inlineFun\$1 I
|
||||||
|
// inlineFun, inlineFun$default, inlined inlineFun:
|
||||||
|
// 3 LOCALVARIABLE \$i\$f\$inlineFun
|
||||||
+6
@@ -3172,6 +3172,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("defaultLambda.kt")
|
||||||
|
public void testDefaultLambda() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/inline/defaultLambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("deleteClassOnTransformation.kt")
|
@TestMetadata("deleteClassOnTransformation.kt")
|
||||||
public void testDeleteClassOnTransformation() throws Exception {
|
public void testDeleteClassOnTransformation() throws Exception {
|
||||||
|
|||||||
+6
@@ -3442,6 +3442,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inline"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("defaultLambda.kt")
|
||||||
|
public void testDefaultLambda() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeText/inline/defaultLambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("deleteClassOnTransformation.kt")
|
@TestMetadata("deleteClassOnTransformation.kt")
|
||||||
public void testDeleteClassOnTransformation() throws Exception {
|
public void testDeleteClassOnTransformation() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user