JVM_IR: skip SAM lambdas when computing enclosing method of objects
This is what Java 15+ does, and it permits accessing captured type parameters via reflection. The alternative is to emit generic signatures on the lambda methods, but that was disabled and I have no clue why. ^KT-52417 Fixed
This commit is contained in:
+7
-1
@@ -148,6 +148,12 @@ class ExpressionCodegen(
|
||||
|
||||
var finallyDepth = 0
|
||||
|
||||
val inlineRoot: ExpressionCodegen
|
||||
get() = inlinedInto ?: this
|
||||
|
||||
val enclosingFunctionForLocalObjects: IrFunction
|
||||
get() = generateSequence(inlineRoot.irFunction) { context.enclosingMethodOverride[it] }.last()
|
||||
|
||||
val context = classCodegen.context
|
||||
val typeMapper = context.typeMapper
|
||||
val methodSignatureMapper = context.methodSignatureMapper
|
||||
@@ -862,7 +868,7 @@ class ExpressionCodegen(
|
||||
|
||||
override fun visitClass(declaration: IrClass, data: BlockInfo): PromisedValue {
|
||||
if (declaration.origin != JvmLoweredDeclarationOrigin.CONTINUATION_CLASS) {
|
||||
val childCodegen = ClassCodegen.getOrCreate(declaration, context, generateSequence(this) { it.inlinedInto }.last().irFunction)
|
||||
val childCodegen = ClassCodegen.getOrCreate(declaration, context, enclosingFunctionForLocalObjects)
|
||||
childCodegen.generate()
|
||||
closureReifiedMarkers[declaration] = childCodegen.reifiedTypeParametersUsages
|
||||
}
|
||||
|
||||
+9
-5
@@ -42,12 +42,16 @@ class IrSourceCompilerForInline(
|
||||
|
||||
override val inlineCallSiteInfo: InlineCallSiteInfo
|
||||
get() {
|
||||
val root = generateSequence(codegen) { it.inlinedInto }.last()
|
||||
val root = codegen.inlineRoot
|
||||
val rootFunction = root.enclosingFunctionForLocalObjects
|
||||
return InlineCallSiteInfo(
|
||||
root.classCodegen.type.internalName,
|
||||
root.signature.asmMethod,
|
||||
root.irFunction.inlineScopeVisibility,
|
||||
root.irFunction.fileParent.getIoFile(),
|
||||
if (rootFunction === root.irFunction)
|
||||
root.signature.asmMethod
|
||||
else
|
||||
codegen.methodSignatureMapper.mapAsmMethod(rootFunction),
|
||||
rootFunction.inlineScopeVisibility,
|
||||
rootFunction.fileParent.getIoFile(),
|
||||
callElement.psiElement?.let { CodegenUtil.getLineNumberForElement(it, false) } ?: 0
|
||||
)
|
||||
}
|
||||
@@ -62,7 +66,7 @@ class IrSourceCompilerForInline(
|
||||
reifiedTypeParameters.addUsedReifiedParameter(typeParameter.name.asString())
|
||||
}
|
||||
}
|
||||
return FunctionCodegen(lambdaInfo.function, codegen.classCodegen).generate(codegen, reifiedTypeParameters)
|
||||
return FunctionCodegen(lambdaInfo.function, codegen.classCodegen).generate(codegen.inlineRoot, reifiedTypeParameters)
|
||||
}
|
||||
|
||||
override fun compileInlineFunction(jvmSignature: JvmMethodSignature): SMAPAndMethodNode {
|
||||
|
||||
@@ -367,6 +367,7 @@ private val jvmFilePhases = listOf(
|
||||
jvmSafeCallFoldingPhase,
|
||||
jvmOptimizationLoweringPhase,
|
||||
additionalClassAnnotationPhase,
|
||||
recordEnclosingMethodsPhase,
|
||||
typeOperatorLowering,
|
||||
replaceKFunctionInvokeWithFunctionInvokePhase,
|
||||
kotlinNothingValueExceptionPhase,
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isInlineFunctionCall
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.unwrapInlineLambda
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.util.isLambda
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
|
||||
internal val recordEnclosingMethodsPhase = makeIrFilePhase(
|
||||
::RecordEnclosingMethodsLowering,
|
||||
name = "RecordEnclosingMethods",
|
||||
description = "Find enclosing methods for objects inside inline and dynamic lambdas"
|
||||
)
|
||||
|
||||
private class RecordEnclosingMethodsLowering(val context: JvmBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) =
|
||||
irFile.accept(object : IrElementVisitor<Unit, IrFunction?> {
|
||||
override fun visitElement(element: IrElement, data: IrFunction?) =
|
||||
element.acceptChildren(this, element as? IrFunction ?: data)
|
||||
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: IrFunction?) {
|
||||
require(data != null) { "function call not in a method: ${expression.render()}" }
|
||||
when {
|
||||
expression.symbol == context.ir.symbols.indyLambdaMetafactoryIntrinsic -> {
|
||||
val reference = expression.getValueArgument(1)
|
||||
if (reference is IrFunctionReference && reference.origin.isLambda) {
|
||||
recordEnclosingMethodOverride(reference.symbol.owner, data)
|
||||
}
|
||||
}
|
||||
expression.symbol.owner.isInlineFunctionCall(context) -> {
|
||||
for (parameter in expression.symbol.owner.valueParameters) {
|
||||
val lambda = expression.getValueArgument(parameter.index)?.unwrapInlineLambda() ?: continue
|
||||
recordEnclosingMethodOverride(lambda.symbol.owner, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.visitFunctionAccess(expression, data)
|
||||
}
|
||||
|
||||
private fun recordEnclosingMethodOverride(from: IrFunction, to: IrFunction) =
|
||||
context.enclosingMethodOverride.merge(from, to) { old, new ->
|
||||
// A single lambda can be referenced multiple times if it is in a field initializer
|
||||
// or an anonymous initializer block and there are multiple non-delegating constructors.
|
||||
assert(old.parentAsClass == new.parentAsClass && old is IrConstructor && new is IrConstructor)
|
||||
old.parentAsClass.primaryConstructor ?: old
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
@@ -99,6 +99,7 @@ class JvmBackendContext(
|
||||
}
|
||||
|
||||
val isEnclosedInConstructor = ConcurrentHashMap.newKeySet<IrAttributeContainer>()
|
||||
val enclosingMethodOverride = ConcurrentHashMap<IrFunction, IrFunction>()
|
||||
|
||||
private val classCodegens = ConcurrentHashMap<IrClass, Any>()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user