Support default lambda inlining in IR
This commit is contained in:
@@ -130,16 +130,16 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
|
||||
fun performInline(
|
||||
typeArguments: List<TypeParameterMarker>?,
|
||||
callDefault: Boolean,
|
||||
typeSystem: TypeSystemCommonBackendContext,
|
||||
codegen: BaseExpressionCodegen
|
||||
inlineDefaultLambdas: Boolean,
|
||||
mapDefaultSignature: Boolean,
|
||||
typeSystem: TypeSystemCommonBackendContext
|
||||
) {
|
||||
var nodeAndSmap: SMAPAndMethodNode? = null
|
||||
try {
|
||||
nodeAndSmap = createInlineMethodNode(
|
||||
functionDescriptor, methodOwner, jvmSignature, callDefault, typeArguments, typeSystem, state, sourceCompiler
|
||||
functionDescriptor, methodOwner, jvmSignature, mapDefaultSignature, typeArguments, typeSystem, state, sourceCompiler
|
||||
)
|
||||
endCall(inlineCall(nodeAndSmap, callDefault))
|
||||
endCall(inlineCall(nodeAndSmap, inlineDefaultLambdas))
|
||||
} catch (e: CompilationException) {
|
||||
throw e
|
||||
} catch (e: InlineException) {
|
||||
@@ -210,16 +210,12 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
?: error("No stack value for continuation parameter of suspend function")
|
||||
}
|
||||
|
||||
protected fun inlineCall(nodeAndSmap: SMAPAndMethodNode, callDefault: Boolean): InlineResult {
|
||||
protected fun inlineCall(nodeAndSmap: SMAPAndMethodNode, inlineDefaultLambda: Boolean): InlineResult {
|
||||
assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" }
|
||||
defaultSourceMapper.callSiteMarker = CallSiteMarker(codegen.lastLineNumber)
|
||||
val node = nodeAndSmap.node
|
||||
if (callDefault) {
|
||||
val defaultLambdas = expandMaskConditionsAndUpdateVariableNodes(
|
||||
node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex,
|
||||
extractDefaultLambdaOffsetAndDescriptor(jvmSignature, functionDescriptor)
|
||||
)
|
||||
for (lambda in defaultLambdas) {
|
||||
if (inlineDefaultLambda) {
|
||||
for (lambda in extractDefaultLambdas(node)) {
|
||||
invocationParamBuilder.buildParameters().getParameterByDeclarationSlot(lambda.offset).functionalArgument = lambda
|
||||
val prev = expressionMap.put(lambda.offset, lambda)
|
||||
assert(prev == null) { "Lambda with offset ${lambda.offset} already exists: $prev" }
|
||||
@@ -283,6 +279,8 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
return result
|
||||
}
|
||||
|
||||
abstract fun extractDefaultLambdas(node: MethodNode): List<DefaultLambda>
|
||||
|
||||
fun generateAndInsertFinallyBlocks(
|
||||
intoNode: MethodNode,
|
||||
insertPoints: List<MethodInliner.PointForExternalFinallyBlocks>,
|
||||
@@ -486,7 +484,9 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
if (kind !== ValueKind.DEFAULT_MASK && kind !== ValueKind.METHOD_HANDLE_IN_DEFAULT) {
|
||||
return false
|
||||
}
|
||||
assert(value is StackValue.Constant) { "Additional default method argument should be constant, but " + value }
|
||||
assert(value is StackValue.Constant) {
|
||||
"Additional default method argument should be constant, but " + value
|
||||
}
|
||||
val constantValue = (value as StackValue.Constant).value
|
||||
if (kind === ValueKind.DEFAULT_MASK) {
|
||||
assert(constantValue is Int) { "Mask should be of Integer type, but " + constantValue }
|
||||
@@ -714,6 +714,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
return NestedSourceMapper(parent, nodeAndSmap.sortedRanges, nodeAndSmap.classSMAP.sourceInfo)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val BaseExpressionCodegen.v: InstructionAdapter
|
||||
|
||||
@@ -85,7 +85,20 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgu
|
||||
class NonInlineableArgumentForInlineableParameterCalledInSuspend(val isSuspend: Boolean) : FunctionalArgument
|
||||
object NonInlineableArgumentForInlineableSuspendParameter : FunctionalArgument
|
||||
|
||||
class DefaultLambda(
|
||||
|
||||
class PsiDefaultLambda(
|
||||
lambdaClassType: Type,
|
||||
capturedArgs: Array<Type>,
|
||||
parameterDescriptor: ValueParameterDescriptor,
|
||||
offset: Int,
|
||||
needReification: Boolean
|
||||
) : DefaultLambda(lambdaClassType, capturedArgs, parameterDescriptor, offset, needReification) {
|
||||
override fun mapAsmSignature(sourceCompiler: SourceCompilerForInline): Method {
|
||||
return sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DefaultLambda(
|
||||
override val lambdaClassType: Type,
|
||||
private val capturedArgs: Array<Type>,
|
||||
val parameterDescriptor: ValueParameterDescriptor,
|
||||
@@ -93,17 +106,17 @@ class DefaultLambda(
|
||||
val needReification: Boolean
|
||||
) : LambdaInfo(parameterDescriptor.isCrossinline) {
|
||||
|
||||
override var isBoundCallableReference by Delegates.notNull<Boolean>()
|
||||
final override var isBoundCallableReference by Delegates.notNull<Boolean>()
|
||||
private set
|
||||
|
||||
val parameterOffsetsInDefault: MutableList<Int> = arrayListOf()
|
||||
|
||||
override lateinit var invokeMethod: Method
|
||||
final override lateinit var invokeMethod: Method
|
||||
private set
|
||||
|
||||
override lateinit var invokeMethodDescriptor: FunctionDescriptor
|
||||
|
||||
override lateinit var capturedVars: List<CapturedParamDesc>
|
||||
final override lateinit var capturedVars: List<CapturedParamDesc>
|
||||
private set
|
||||
|
||||
override fun isReturnFromMe(labelName: String): Boolean = false
|
||||
@@ -168,12 +181,13 @@ class DefaultLambda(
|
||||
isBoundCallableReference = (isFunctionReference || isPropertyReference) && capturedVars.isNotEmpty()
|
||||
|
||||
val methodName = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString()
|
||||
val signature = sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor
|
||||
|
||||
val signature = mapAsmSignature(sourceCompiler)
|
||||
|
||||
node = getMethodNode(
|
||||
classReader.b,
|
||||
methodName,
|
||||
signature,
|
||||
signature.descriptor,
|
||||
lambdaClassType,
|
||||
signatureAmbiguity = true
|
||||
) ?: error("Can't find method '$methodName$signature' in '${classReader.className}'")
|
||||
@@ -185,6 +199,8 @@ class DefaultLambda(
|
||||
reifiedTypeInliner.reifyInstructions(node.node)
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun mapAsmSignature(sourceCompiler: SourceCompilerForInline): Method
|
||||
}
|
||||
|
||||
internal fun Type.boxReceiverForBoundReference() =
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class PsiInlineCodegen(
|
||||
codegen: ExpressionCodegen,
|
||||
@@ -64,7 +65,7 @@ class PsiInlineCodegen(
|
||||
return
|
||||
}
|
||||
try {
|
||||
performInline(resolvedCall?.typeArguments?.keys?.toList(), callDefault, codegen.typeSystem, codegen)
|
||||
performInline(resolvedCall?.typeArguments?.keys?.toList(), callDefault, callDefault, codegen.typeSystem)
|
||||
} finally {
|
||||
state.globalInlineContext.exitFromInliningOf(resolvedCall)
|
||||
}
|
||||
@@ -193,4 +194,12 @@ class PsiInlineCodegen(
|
||||
delayedHiddenWriting!!.invoke()
|
||||
delayedHiddenWriting = null
|
||||
}
|
||||
|
||||
override fun extractDefaultLambdas(node: MethodNode): List<DefaultLambda> {
|
||||
return expandMaskConditionsAndUpdateVariableNodes(
|
||||
node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex,
|
||||
extractDefaultLambdaOffsetAndDescriptor(jvmSignature, functionDescriptor),
|
||||
::PsiDefaultLambda
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,13 +61,14 @@ fun extractDefaultLambdaOffsetAndDescriptor(
|
||||
}
|
||||
|
||||
|
||||
fun expandMaskConditionsAndUpdateVariableNodes(
|
||||
fun <T, R : DefaultLambda> expandMaskConditionsAndUpdateVariableNodes(
|
||||
node: MethodNode,
|
||||
maskStartIndex: Int,
|
||||
masks: List<Int>,
|
||||
methodHandlerIndex: Int,
|
||||
defaultLambdas: Map<Int, ValueParameterDescriptor>
|
||||
): List<DefaultLambda> {
|
||||
defaultLambdas: Map<Int, T>,
|
||||
lambdaConstructor: (Type, Array<Type>, T, Int, Boolean) -> R
|
||||
): List<R> {
|
||||
fun isMaskIndex(varIndex: Int): Boolean {
|
||||
return maskStartIndex <= varIndex && varIndex < maskStartIndex + masks.size
|
||||
}
|
||||
@@ -110,7 +111,7 @@ fun expandMaskConditionsAndUpdateVariableNodes(
|
||||
val toDelete = linkedSetOf<AbstractInsnNode>()
|
||||
val toInsert = arrayListOf<Pair<AbstractInsnNode, AbstractInsnNode>>()
|
||||
|
||||
val defaultLambdasInfo = extractDefaultLambdasInfo(conditions, defaultLambdas, toDelete, toInsert)
|
||||
val defaultLambdasInfo = extractDefaultLambdasInfo(conditions, defaultLambdas, toDelete, toInsert, lambdaConstructor)
|
||||
|
||||
val indexToVarNode = node.localVariables?.filter { it.index < maskStartIndex }?.associateBy { it.index } ?: emptyMap()
|
||||
conditions.forEach {
|
||||
@@ -137,12 +138,13 @@ fun expandMaskConditionsAndUpdateVariableNodes(
|
||||
}
|
||||
|
||||
|
||||
private fun extractDefaultLambdasInfo(
|
||||
private fun <T, R : DefaultLambda> extractDefaultLambdasInfo(
|
||||
conditions: List<Condition>,
|
||||
defaultLambdas: Map<Int, ValueParameterDescriptor>,
|
||||
defaultLambdas: Map<Int, T>,
|
||||
toDelete: MutableCollection<AbstractInsnNode>,
|
||||
toInsert: MutableList<Pair<AbstractInsnNode, AbstractInsnNode>>
|
||||
): List<DefaultLambda> {
|
||||
toInsert: MutableList<Pair<AbstractInsnNode, AbstractInsnNode>>,
|
||||
lambdaConstructor: (Type, Array<Type>, T, Int, Boolean) -> R
|
||||
): List<R> {
|
||||
val defaultLambdaConditions = conditions.filter { it.expandNotDelete && defaultLambdas.contains(it.varIndex) }
|
||||
return defaultLambdaConditions.map {
|
||||
val varAssignmentInstruction = it.varInsNode!!
|
||||
@@ -186,7 +188,7 @@ private fun extractDefaultLambdasInfo(
|
||||
|
||||
toInsert.add(varAssignmentInstruction to defaultLambdaFakeCallStub(argTypes, it.varIndex))
|
||||
|
||||
DefaultLambda(owner, argTypes, defaultLambdas[it.varIndex]!!, it.varIndex, needReification)
|
||||
lambdaConstructor(owner, argTypes, defaultLambdas[it.varIndex]!!, it.varIndex, needReification)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user