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) }
|
||||
)
|
||||
for (info in infos) {
|
||||
val lambda = DefaultLambda(info, sourceCompiler)
|
||||
val lambda = DefaultLambda(info, sourceCompiler, node.name.substringBeforeLast("\$default"))
|
||||
parameters.getParameterByDeclarationSlot(info.offset).functionalArgument = lambda
|
||||
if (info.needReification) {
|
||||
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.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.types.KotlinType
|
||||
import org.jetbrains.org.objectweb.asm.ClassReader
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
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)
|
||||
}?.toList() ?: emptyList()
|
||||
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 {
|
||||
|
||||
+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);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("defaultLambda.kt")
|
||||
public void testDefaultLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/inline/defaultLambda.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("deleteClassOnTransformation.kt")
|
||||
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);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("defaultLambda.kt")
|
||||
public void testDefaultLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/inline/defaultLambda.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("deleteClassOnTransformation.kt")
|
||||
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);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("defaultLambda.kt")
|
||||
public void testDefaultLambda() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/inline/defaultLambda.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("deleteClassOnTransformation.kt")
|
||||
public void testDeleteClassOnTransformation() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user