JVM: make inline function argument processing a bit shorter

This commit is contained in:
pyos
2021-06-07 12:37:51 +02:00
committed by max-kammerer
parent 392e4fba42
commit 6c1a5e1211
5 changed files with 68 additions and 97 deletions
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -28,9 +29,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
protected val sourceCompiler: SourceCompilerForInline, protected val sourceCompiler: SourceCompilerForInline,
private val reifiedTypeInliner: ReifiedTypeInliner<*> private val reifiedTypeInliner: ReifiedTypeInliner<*>
) { ) {
// TODO: implement AS_FUNCTION inline strategy
private val asFunctionInline = false
private val initialFrameSize = codegen.frameMap.currentSize private val initialFrameSize = codegen.frameMap.currentSize
protected val invocationParamBuilder = ParametersBuilder.newBuilder() protected val invocationParamBuilder = ParametersBuilder.newBuilder()
@@ -108,12 +106,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
return true return true
} }
protected fun rememberClosure(parameterType: Type, index: Int, lambdaInfo: LambdaInfo) {
val closureInfo = invocationParamBuilder.addNextValueParameter(parameterType, true, null, index)
closureInfo.functionalArgument = lambdaInfo
expressionMap[closureInfo.index] = lambdaInfo
}
private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, isInlineOnly: Boolean, isSuspend: Boolean): InlineResult { private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, isInlineOnly: Boolean, isSuspend: Boolean): InlineResult {
val node = nodeAndSmap.node val node = nodeAndSmap.node
if (maskStartIndex != -1) { if (maskStartIndex != -1) {
@@ -264,50 +256,46 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
} }
} }
protected fun putArgumentOrCapturedToLocalVal( protected fun rememberClosure(parameterType: Type, index: Int, lambdaInfo: LambdaInfo) {
jvmKotlinType: JvmKotlinType, val closureInfo = invocationParamBuilder.addNextValueParameter(parameterType, true, null, index)
stackValue: StackValue, closureInfo.functionalArgument = lambdaInfo
capturedParam: CapturedParamDesc?, expressionMap[closureInfo.index] = lambdaInfo
parameterIndex: Int, }
kind: ValueKind
) { protected fun putCapturedToLocalVal(stackValue: StackValue, capturedParam: CapturedParamDesc, kotlinType: KotlinType?) {
val isDefaultParameter = kind === ValueKind.DEFAULT_PARAMETER val info = invocationParamBuilder.addCapturedParam(capturedParam, capturedParam.fieldName, false)
val jvmType = jvmKotlinType.type if (stackValue.isLocalWithNoBoxing(JvmKotlinType(info.type, kotlinType))) {
val kotlinType = jvmKotlinType.kotlinType info.remapValue = stackValue
val canRemap = isPrimitive(jvmType) == isPrimitive(stackValue.type) && } else {
!StackValue.requiresInlineClassBoxingOrUnboxing(stackValue.type, stackValue.kotlinType, jvmType, kotlinType) && stackValue.put(info.type, kotlinType, codegen.visitor)
(stackValue is StackValue.Local || stackValue.isCapturedInlineParameter()) val local = StackValue.local(codegen.frameMap.enterTemp(info.type), info.type)
if (!canRemap && !isDefaultParameter) { local.store(StackValue.onStack(info.type), codegen.visitor)
stackValue.put(jvmType, kotlinType, codegen.visitor) info.remapValue = local
info.isSynthetic = true
}
}
protected fun putArgumentToLocalVal(jvmKotlinType: JvmKotlinType, stackValue: StackValue, parameterIndex: Int, kind: ValueKind) {
if (kind === ValueKind.DEFAULT_MASK || kind === ValueKind.METHOD_HANDLE_IN_DEFAULT) {
return processDefaultMaskOrMethodHandler(stackValue, kind)
} }
if (!asFunctionInline && Type.VOID_TYPE !== jvmType) { val info = invocationParamBuilder.addNextValueParameter(jvmKotlinType.type, false, null, parameterIndex)
//TODO remap only inlinable closure => otherwise we could get a lot of problem info.functionalArgument = when (kind) {
val remappedValue = if (canRemap && !isDefaultParameter) stackValue else null ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND ->
val info: ParameterInfo NonInlineableArgumentForInlineableParameterCalledInSuspend
if (capturedParam != null) { ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER ->
info = invocationParamBuilder.addCapturedParam(capturedParam, capturedParam.fieldName, false) NonInlineableArgumentForInlineableSuspendParameter
info.remapValue = remappedValue else -> null
} else { }
info = invocationParamBuilder.addNextValueParameter(jvmType, false, remappedValue, parameterIndex) when {
info.functionalArgument = when (kind) { kind === ValueKind.DEFAULT_PARAMETER ->
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND -> codegen.frameMap.enterTemp(info.type) // the inline function will put the value into this slot
NonInlineableArgumentForInlineableParameterCalledInSuspend stackValue.isLocalWithNoBoxing(jvmKotlinType) ->
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER -> info.remapValue = stackValue
NonInlineableArgumentForInlineableSuspendParameter else -> {
else -> null stackValue.put(info.type, jvmKotlinType.kotlinType, codegen.visitor)
} codegen.visitor.store(codegen.frameMap.enterTemp(info.type), info.type)
}
if (!info.isSkippedOrRemapped) {
val local = StackValue.local(codegen.frameMap.enterTemp(info.type), info.type)
if (!isDefaultParameter) {
local.store(StackValue.onStack(info.typeOnStack), codegen.visitor)
}
if (info is CapturedParamInfo) {
info.remapValue = local
info.isSynthetic = true
}
} }
} }
} }
@@ -321,19 +309,14 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
} }
private fun rememberCapturedForDefaultLambda(defaultLambda: DefaultLambda) { private fun rememberCapturedForDefaultLambda(defaultLambda: DefaultLambda) {
if (!asFunctionInline) { for (captured in defaultLambda.capturedVars) {
for (captured in defaultLambda.capturedVars) { val info = invocationParamBuilder.addCapturedParam(captured, captured.fieldName, false)
val info = invocationParamBuilder.addCapturedParam(captured, captured.fieldName, false) info.remapValue = StackValue.local(codegen.frameMap.enterTemp(info.type), info.type)
info.remapValue = StackValue.local(codegen.frameMap.enterTemp(info.type), info.type) info.isSynthetic = true
info.isSynthetic = true
}
} }
} }
protected fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind): Boolean { private fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind) {
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 val constantValue = (value as StackValue.Constant).value
if (kind === ValueKind.DEFAULT_MASK) { if (kind === ValueKind.DEFAULT_MASK) {
@@ -348,10 +331,14 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
assert(constantValue == null) { "Additional method handle for default argument should be null, but " + constantValue!! } assert(constantValue == null) { "Additional method handle for default argument should be null, but " + constantValue!! }
methodHandleInDefaultMethodIndex = maskStartIndex + maskValues.size methodHandleInDefaultMethodIndex = maskStartIndex + maskValues.size
} }
return true
} }
companion object { companion object {
private fun StackValue.isLocalWithNoBoxing(expected: JvmKotlinType): Boolean =
isPrimitive(expected.type) == isPrimitive(type) &&
!StackValue.requiresInlineClassBoxingOrUnboxing(type, kotlinType, expected.type, expected.kotlinType) &&
(this is StackValue.Local || isCapturedInlineParameter())
private fun StackValue.isCapturedInlineParameter(): Boolean { private fun StackValue.isCapturedInlineParameter(): Boolean {
val field = if (this is StackValue.FieldForSharedVar) receiver else this val field = if (this is StackValue.FieldForSharedVar) receiver else this
return field is StackValue.Field && field.descriptor is ParameterDescriptor && return field is StackValue.Field && field.descriptor is ParameterDescriptor &&
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isAncestor import org.jetbrains.kotlin.psi.psiUtil.isAncestor
@@ -192,20 +193,11 @@ class PsiInlineCodegen(
activeLambda = null activeLambda = null
} }
override fun putValueIfNeeded(parameterType: JvmKotlinType, value: StackValue, kind: ValueKind, parameterIndex: Int) { override fun putValueIfNeeded(parameterType: JvmKotlinType, value: StackValue, kind: ValueKind, parameterIndex: Int) =
if (processDefaultMaskOrMethodHandler(value, kind)) return putArgumentToLocalVal(parameterType, value, parameterIndex, kind)
assert(maskValues.isEmpty()) { "Additional default call arguments should be last ones, but $value" } override fun putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) =
putCapturedToLocalVal(stackValue, activeLambda!!.capturedVars[paramIndex], stackValue.kotlinType)
putArgumentOrCapturedToLocalVal(parameterType, value, null, parameterIndex, kind)
}
override fun putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) {
val param = activeLambda!!.capturedVars[paramIndex]
putArgumentOrCapturedToLocalVal(
JvmKotlinType(stackValue.type, stackValue.kotlinType), stackValue, param, paramIndex, ValueKind.CAPTURED
)
}
override fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List<ArgumentAndDeclIndex>, valueParameterTypes: List<Type>) = Unit override fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List<ArgumentAndDeclIndex>, valueParameterTypes: List<Type>) = Unit
@@ -294,9 +286,10 @@ class PsiExpressionLambda(
val capturedReceiver = closure.capturedReceiverFromOuterContext val capturedReceiver = closure.capturedReceiverFromOuterContext
if (capturedReceiver != null) { if (capturedReceiver != null) {
val fieldName = closure.getCapturedReceiverFieldName(state.typeMapper.bindingContext, state.languageVersionSettings) val fieldName = closure.getCapturedReceiverFieldName(state.typeMapper.bindingContext, state.languageVersionSettings)
val type = state.typeMapper.mapType(capturedReceiver).let { val type = if (isBoundCallableReference)
if (isBoundCallableReference) AsmUtil.boxType(it) else it state.typeMapper.mapType(capturedReceiver, null, TypeMappingMode.GENERIC_ARGUMENT)
} else
state.typeMapper.mapType(capturedReceiver)
add(capturedParamDesc(fieldName, type, isSuspend = false)) add(capturedParamDesc(fieldName, type, isSuspend = false))
} }
@@ -67,7 +67,9 @@ class IrInlineCodegen(
rememberClosure(parameterType, irValueParameter.index, lambdaInfo) rememberClosure(parameterType, irValueParameter.index, lambdaInfo)
lambdaInfo.generateLambdaBody(sourceCompiler) lambdaInfo.generateLambdaBody(sourceCompiler)
lambdaInfo.reference.getArgumentsWithIr().forEachIndexed { index, (_, ir) -> lambdaInfo.reference.getArgumentsWithIr().forEachIndexed { index, (_, ir) ->
putCapturedValueOnStack(ir, lambdaInfo.capturedVars[index], index) val param = lambdaInfo.capturedVars[index]
val onStack = codegen.genOrGetLocal(ir, param.type, ir.type, BlockInfo())
putCapturedToLocalVal(onStack, param, ir.type.toIrBasedKotlinType())
} }
} else { } else {
val kind = when (irValueParameter.origin) { val kind = when (irValueParameter.origin) {
@@ -99,21 +101,11 @@ class IrInlineCodegen(
-> codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo) -> codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo)
} }
val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toIrBasedKotlinType())
//TODO support default argument erasure putArgumentToLocalVal(expectedType, onStack, irValueParameter.index, kind)
if (!processDefaultMaskOrMethodHandler(onStack, kind)) {
val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toIrBasedKotlinType())
putArgumentOrCapturedToLocalVal(expectedType, onStack, null, irValueParameter.index, kind)
}
} }
} }
private fun putCapturedValueOnStack(argumentExpression: IrExpression, param: CapturedParamDesc, capturedParamIndex: Int) {
val onStack = codegen.genOrGetLocal(argumentExpression, param.type, argumentExpression.type, BlockInfo())
val expectedType = JvmKotlinType(param.type, argumentExpression.type.toIrBasedKotlinType())
putArgumentOrCapturedToLocalVal(expectedType, onStack, param, capturedParamIndex, ValueKind.CAPTURED)
}
override fun beforeValueParametersStart() { override fun beforeValueParametersStart() {
invocationParamBuilder.markValueParametersStart() invocationParamBuilder.markValueParametersStart()
} }
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM
// DONT_TARGET_EXACT_BACKEND: WASM // DONT_TARGET_EXACT_BACKEND: WASM
// WASM_MUTE_REASON: BINDING_RECEIVERS // WASM_MUTE_REASON: BINDING_RECEIVERS
// KT-30629 // KT-30629
@@ -2535,11 +2535,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
public static class Bound extends AbstractLightAnalysisModeTest { public static class Bound extends AbstractLightAnalysisModeTest {
@TestMetadata("genericBoundPropertyAsCrossinline.kt")
public void ignoreGenericBoundPropertyAsCrossinline() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/bound/genericBoundPropertyAsCrossinline.kt");
}
private void runTest(String testDataFilePath) throws Exception { private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
} }
@@ -2613,6 +2608,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/callableReference/bound/enumEntryMember.kt"); runTest("compiler/testData/codegen/box/callableReference/bound/enumEntryMember.kt");
} }
@TestMetadata("genericBoundPropertyAsCrossinline.kt")
public void testGenericBoundPropertyAsCrossinline() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/bound/genericBoundPropertyAsCrossinline.kt");
}
@TestMetadata("genericValOnLHS.kt") @TestMetadata("genericValOnLHS.kt")
public void testGenericValOnLHS() throws Exception { public void testGenericValOnLHS() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/bound/genericValOnLHS.kt"); runTest("compiler/testData/codegen/box/callableReference/bound/genericValOnLHS.kt");