JVM: refactor extraction of default inline lambdas a bit more

This commit is contained in:
pyos
2021-07-06 12:30:20 +02:00
committed by max-kammerer
parent 91cf1a1a4d
commit c1c56ca388
7 changed files with 31 additions and 66 deletions
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
import org.jetbrains.kotlin.types.upperIfFlexible import org.jetbrains.kotlin.types.upperIfFlexible
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -51,7 +52,7 @@ class CallBasedArgumentGenerator(
callGenerator.putValueIfNeeded( callGenerator.putValueIfNeeded(
getJvmKotlinType(i), getJvmKotlinType(i),
StackValue.createDefaultValue(valueParameterTypes[i]), StackValue.createDefaultValue(valueParameterTypes[i]),
ValueKind.DEFAULT_PARAMETER, if (InlineUtil.isInlineParameter(valueParameters[i])) ValueKind.DEFAULT_INLINE_PARAMETER else ValueKind.DEFAULT_PARAMETER,
i i
) )
} }
@@ -15,9 +15,9 @@ enum class ValueKind {
GENERAL, GENERAL,
GENERAL_VARARG, GENERAL_VARARG,
DEFAULT_PARAMETER, DEFAULT_PARAMETER,
DEFAULT_INLINE_PARAMETER,
DEFAULT_MASK, DEFAULT_MASK,
METHOD_HANDLE_IN_DEFAULT, METHOD_HANDLE_IN_DEFAULT,
CAPTURED,
NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND, NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND,
NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER
} }
@@ -71,10 +71,12 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, isInlineOnly: Boolean): InlineResult { private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, isInlineOnly: Boolean): InlineResult {
val node = nodeAndSmap.node val node = nodeAndSmap.node
if (maskStartIndex != -1) { if (maskStartIndex != -1) {
val infos = expandMaskConditionsAndUpdateVariableNodes(
node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex, computeDefaultLambdaOffsets()
)
val parameters = invocationParamBuilder.buildParameters() val parameters = invocationParamBuilder.buildParameters()
val infos = expandMaskConditionsAndUpdateVariableNodes(
node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex,
parameters.parameters.filter { it.functionalArgument === DefaultValueOfInlineParameter }
.mapTo(mutableSetOf()) { parameters.getDeclarationSlot(it) }
)
for (info in infos) { for (info in infos) {
val lambda = DefaultLambda(info, sourceCompiler) val lambda = DefaultLambda(info, sourceCompiler)
parameters.getParameterByDeclarationSlot(info.offset).functionalArgument = lambda parameters.getParameterByDeclarationSlot(info.offset).functionalArgument = lambda
@@ -83,7 +85,11 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
if (info.needReification) { if (info.needReification) {
lambda.reifiedTypeParametersUsages.mergeAll(reifiedTypeInliner.reifyInstructions(lambda.node.node)) lambda.reifiedTypeParametersUsages.mergeAll(reifiedTypeInliner.reifyInstructions(lambda.node.node))
} }
rememberCapturedForDefaultLambda(lambda) for (captured in lambda.capturedVars) {
val param = invocationParamBuilder.addCapturedParam(captured, captured.fieldName, false)
param.remapValue = StackValue.local(codegen.frameMap.enterTemp(param.type), param.type)
param.isSynthetic = true
}
} }
} }
@@ -141,8 +147,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
return result return result
} }
abstract fun computeDefaultLambdaOffsets(): Set<Int>
private fun generateAndInsertFinallyBlocks( private fun generateAndInsertFinallyBlocks(
intoNode: MethodNode, intoNode: MethodNode,
insertPoints: List<MethodInliner.PointForExternalFinallyBlocks>, insertPoints: List<MethodInliner.PointForExternalFinallyBlocks>,
@@ -235,10 +239,12 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
NonInlineableArgumentForInlineableParameterCalledInSuspend NonInlineableArgumentForInlineableParameterCalledInSuspend
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER -> ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER ->
NonInlineableArgumentForInlineableSuspendParameter NonInlineableArgumentForInlineableSuspendParameter
ValueKind.DEFAULT_INLINE_PARAMETER ->
DefaultValueOfInlineParameter
else -> null else -> null
} }
when { when {
kind === ValueKind.DEFAULT_PARAMETER -> kind === ValueKind.DEFAULT_PARAMETER || kind === ValueKind.DEFAULT_INLINE_PARAMETER ->
codegen.frameMap.enterTemp(info.type) // the inline function will put the value into this slot codegen.frameMap.enterTemp(info.type) // the inline function will put the value into this slot
stackValue.isLocalWithNoBoxing(jvmKotlinType) -> stackValue.isLocalWithNoBoxing(jvmKotlinType) ->
info.remapValue = stackValue info.remapValue = stackValue
@@ -257,14 +263,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
} }
} }
private fun rememberCapturedForDefaultLambda(defaultLambda: DefaultLambda) {
for (captured in defaultLambda.capturedVars) {
val info = invocationParamBuilder.addCapturedParam(captured, captured.fieldName, false)
info.remapValue = StackValue.local(codegen.frameMap.enterTemp(info.type), info.type)
info.isSynthetic = true
}
}
private fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind) { private fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind) {
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 val constantValue = (value as StackValue.Constant).value
@@ -65,6 +65,7 @@ abstract class LambdaInfo : FunctionalArgument {
object NonInlineableArgumentForInlineableParameterCalledInSuspend : FunctionalArgument object NonInlineableArgumentForInlineableParameterCalledInSuspend : FunctionalArgument
object NonInlineableArgumentForInlineableSuspendParameter : FunctionalArgument object NonInlineableArgumentForInlineableSuspendParameter : FunctionalArgument
object DefaultValueOfInlineParameter : FunctionalArgument
abstract class ExpressionLambda : LambdaInfo() { abstract class ExpressionLambda : LambdaInfo() {
fun generateLambdaBody(sourceCompiler: SourceCompilerForInline) { fun generateLambdaBody(sourceCompiler: SourceCompilerForInline) {
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
@@ -18,15 +17,6 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.VarInsnNode import org.jetbrains.org.objectweb.asm.tree.VarInsnNode
import org.jetbrains.org.objectweb.asm.tree.analysis.* import org.jetbrains.org.objectweb.asm.tree.analysis.*
fun parameterOffsets(isStatic: Boolean, valueParameters: List<JvmMethodParameterSignature>): Array<Int> {
var nextOffset = if (isStatic) 0 else 1
return Array(valueParameters.size) { index ->
nextOffset.also {
nextOffset += valueParameters[index].asmType.size
}
}
}
fun MethodNode.remove(instructions: Sequence<AbstractInsnNode>) = fun MethodNode.remove(instructions: Sequence<AbstractInsnNode>) =
instructions.forEach { instructions.forEach {
this@remove.instructions.remove(it) this@remove.instructions.remove(it)
@@ -111,14 +111,6 @@ class PsiInlineCodegen(
hiddenParameters.clear() hiddenParameters.clear()
} }
/*lambda or callable reference*/
private fun isInliningParameter(expression: KtExpression, valueParameterDescriptor: ValueParameterDescriptor): Boolean {
//TODO deparenthesize typed
val deparenthesized = KtPsiUtil.deparenthesize(expression)
return InlineUtil.isInlineParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized)
}
override fun genValueAndPut( override fun genValueAndPut(
valueParameterDescriptor: ValueParameterDescriptor?, valueParameterDescriptor: ValueParameterDescriptor?,
argumentExpression: KtExpression, argumentExpression: KtExpression,
@@ -130,7 +122,9 @@ class PsiInlineCodegen(
"which cannot be declared in Kotlin and thus be inline: $codegen" "which cannot be declared in Kotlin and thus be inline: $codegen"
} }
if (isInliningParameter(argumentExpression, valueParameterDescriptor)) { val isInlineParameter = InlineUtil.isInlineParameter(valueParameterDescriptor)
//TODO deparenthesize typed
if (isInlineParameter && isInlinableParameterExpression(KtPsiUtil.deparenthesize(argumentExpression))) {
rememberClosure(argumentExpression, parameterType.type, valueParameterDescriptor) rememberClosure(argumentExpression, parameterType.type, valueParameterDescriptor)
} else { } else {
val value = codegen.gen(argumentExpression) val value = codegen.gen(argumentExpression)
@@ -191,15 +185,6 @@ class PsiInlineCodegen(
putCapturedToLocalVal(stackValue, activeLambda!!.capturedVars[paramIndex], stackValue.kotlinType) putCapturedToLocalVal(stackValue, activeLambda!!.capturedVars[paramIndex], stackValue.kotlinType)
override fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List<ArgumentAndDeclIndex>, valueParameterTypes: List<Type>) = Unit override fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List<ArgumentAndDeclIndex>, valueParameterTypes: List<Type>) = Unit
override fun computeDefaultLambdaOffsets(): Set<Int> {
val contextKind = (sourceCompiler as PsiSourceCompilerForInline).context.contextKind
return parameterOffsets(DescriptorAsmUtil.isStaticMethod(contextKind, functionDescriptor), jvmSignature.valueParameters)
.drop(jvmSignature.valueParameters.indexOfFirst { it.kind == JvmMethodParameterKind.VALUE })
.filterIndexedTo(mutableSetOf()) { index, _ ->
functionDescriptor.valueParameters[index].let { InlineUtil.isInlineParameter(it) && it.declaresDefaultValue() }
}
}
} }
private val FunctionDescriptor.explicitParameters private val FunctionDescriptor.explicitParameters
@@ -70,7 +70,7 @@ class IrInlineCodegen(
IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION -> ValueKind.METHOD_HANDLE_IN_DEFAULT IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION -> ValueKind.METHOD_HANDLE_IN_DEFAULT
else -> when { else -> when {
argumentExpression is IrContainerExpression && argumentExpression.origin == IrStatementOrigin.DEFAULT_VALUE -> argumentExpression is IrContainerExpression && argumentExpression.origin == IrStatementOrigin.DEFAULT_VALUE ->
ValueKind.DEFAULT_PARAMETER if (isInlineParameter) ValueKind.DEFAULT_INLINE_PARAMETER else ValueKind.DEFAULT_PARAMETER
// TODO ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND? // TODO ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND?
isInlineParameter && irValueParameter.type.isSuspendFunctionTypeOrSubtype() -> isInlineParameter && irValueParameter.type.isSuspendFunctionTypeOrSubtype() ->
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER
@@ -78,20 +78,17 @@ class IrInlineCodegen(
} }
} }
val onStack = when { val onStack = when (kind) {
kind == ValueKind.METHOD_HANDLE_IN_DEFAULT -> StackValue.constant(null, AsmTypes.OBJECT_TYPE) ValueKind.METHOD_HANDLE_IN_DEFAULT -> StackValue.constant(null, AsmTypes.OBJECT_TYPE)
kind == ValueKind.DEFAULT_MASK -> StackValue.constant((argumentExpression as IrConst<*>).value, Type.INT_TYPE) ValueKind.DEFAULT_MASK -> StackValue.constant((argumentExpression as IrConst<*>).value, Type.INT_TYPE)
kind == ValueKind.DEFAULT_PARAMETER -> StackValue.createDefaultValue(parameterType) ValueKind.DEFAULT_PARAMETER, ValueKind.DEFAULT_INLINE_PARAMETER -> StackValue.createDefaultValue(parameterType)
irValueParameter.index >= 0 // Here we replicate the old backend: reusing the locals for everything except extension receivers.
// Reuse an existing local if possible. NOTE: when stopping at a breakpoint placed // TODO when stopping at a breakpoint placed in an inline function, arguments which reuse an existing
// in an inline function, arguments which reuse an existing local will not be visible // local will not be visible in the debugger, so this needs to be reconsidered.
// in the debugger. else -> if (irValueParameter.index >= 0)
-> codegen.genOrGetLocal(argumentExpression, parameterType, irValueParameter.type, blockInfo) codegen.genOrGetLocal(argumentExpression, parameterType, irValueParameter.type, blockInfo)
else else
// Do not reuse locals for receivers. While it's actually completely fine, the non-IR codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo)
// backend does not do it for internal reasons, and here we replicate the debugging
// experience.
-> codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo)
} }
val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toIrBasedKotlinType()) val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toIrBasedKotlinType())
@@ -115,13 +112,6 @@ class IrInlineCodegen(
override fun genCycleStub(text: String, codegen: ExpressionCodegen) { override fun genCycleStub(text: String, codegen: ExpressionCodegen) {
generateStub(text, codegen) generateStub(text, codegen)
} }
override fun computeDefaultLambdaOffsets(): Set<Int> =
parameterOffsets(function.isStatic, jvmSignature.valueParameters)
.drop(if (function.extensionReceiverParameter != null) 1 else 0)
.filterIndexedTo(mutableSetOf()) { index, _ ->
function.valueParameters[index].let { it.defaultValue != null && it.isInlineParameter() }
}
} }
class IrExpressionLambdaImpl( class IrExpressionLambdaImpl(