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.inline.InlineUtil
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.Opcodes
import org.jetbrains.org.objectweb.asm.Type
@@ -28,9 +29,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
protected val sourceCompiler: SourceCompilerForInline,
private val reifiedTypeInliner: ReifiedTypeInliner<*>
) {
// TODO: implement AS_FUNCTION inline strategy
private val asFunctionInline = false
private val initialFrameSize = codegen.frameMap.currentSize
protected val invocationParamBuilder = ParametersBuilder.newBuilder()
@@ -108,12 +106,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
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 {
val node = nodeAndSmap.node
if (maskStartIndex != -1) {
@@ -264,50 +256,46 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
}
}
protected fun putArgumentOrCapturedToLocalVal(
jvmKotlinType: JvmKotlinType,
stackValue: StackValue,
capturedParam: CapturedParamDesc?,
parameterIndex: Int,
kind: ValueKind
) {
val isDefaultParameter = kind === ValueKind.DEFAULT_PARAMETER
val jvmType = jvmKotlinType.type
val kotlinType = jvmKotlinType.kotlinType
val canRemap = isPrimitive(jvmType) == isPrimitive(stackValue.type) &&
!StackValue.requiresInlineClassBoxingOrUnboxing(stackValue.type, stackValue.kotlinType, jvmType, kotlinType) &&
(stackValue is StackValue.Local || stackValue.isCapturedInlineParameter())
if (!canRemap && !isDefaultParameter) {
stackValue.put(jvmType, kotlinType, codegen.visitor)
protected fun rememberClosure(parameterType: Type, index: Int, lambdaInfo: LambdaInfo) {
val closureInfo = invocationParamBuilder.addNextValueParameter(parameterType, true, null, index)
closureInfo.functionalArgument = lambdaInfo
expressionMap[closureInfo.index] = lambdaInfo
}
protected fun putCapturedToLocalVal(stackValue: StackValue, capturedParam: CapturedParamDesc, kotlinType: KotlinType?) {
val info = invocationParamBuilder.addCapturedParam(capturedParam, capturedParam.fieldName, false)
if (stackValue.isLocalWithNoBoxing(JvmKotlinType(info.type, kotlinType))) {
info.remapValue = stackValue
} else {
stackValue.put(info.type, kotlinType, codegen.visitor)
val local = StackValue.local(codegen.frameMap.enterTemp(info.type), info.type)
local.store(StackValue.onStack(info.type), 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) {
//TODO remap only inlinable closure => otherwise we could get a lot of problem
val remappedValue = if (canRemap && !isDefaultParameter) stackValue else null
val info: ParameterInfo
if (capturedParam != null) {
info = invocationParamBuilder.addCapturedParam(capturedParam, capturedParam.fieldName, false)
info.remapValue = remappedValue
} else {
info = invocationParamBuilder.addNextValueParameter(jvmType, false, remappedValue, parameterIndex)
info.functionalArgument = when (kind) {
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND ->
NonInlineableArgumentForInlineableParameterCalledInSuspend
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER ->
NonInlineableArgumentForInlineableSuspendParameter
else -> null
}
}
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
}
val info = invocationParamBuilder.addNextValueParameter(jvmKotlinType.type, false, null, parameterIndex)
info.functionalArgument = when (kind) {
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND ->
NonInlineableArgumentForInlineableParameterCalledInSuspend
ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER ->
NonInlineableArgumentForInlineableSuspendParameter
else -> null
}
when {
kind === ValueKind.DEFAULT_PARAMETER ->
codegen.frameMap.enterTemp(info.type) // the inline function will put the value into this slot
stackValue.isLocalWithNoBoxing(jvmKotlinType) ->
info.remapValue = stackValue
else -> {
stackValue.put(info.type, jvmKotlinType.kotlinType, codegen.visitor)
codegen.visitor.store(codegen.frameMap.enterTemp(info.type), info.type)
}
}
}
@@ -321,19 +309,14 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
}
private fun rememberCapturedForDefaultLambda(defaultLambda: DefaultLambda) {
if (!asFunctionInline) {
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
}
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
}
}
protected fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind): Boolean {
if (kind !== ValueKind.DEFAULT_MASK && kind !== ValueKind.METHOD_HANDLE_IN_DEFAULT) {
return false
}
private fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind) {
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) {
@@ -348,10 +331,14 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
assert(constantValue == null) { "Additional method handle for default argument should be null, but " + constantValue!! }
methodHandleInDefaultMethodIndex = maskStartIndex + maskValues.size
}
return true
}
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 {
val field = if (this is StackValue.FieldForSharedVar) receiver else this
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.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
@@ -192,20 +193,11 @@ class PsiInlineCodegen(
activeLambda = null
}
override fun putValueIfNeeded(parameterType: JvmKotlinType, value: StackValue, kind: ValueKind, parameterIndex: Int) {
if (processDefaultMaskOrMethodHandler(value, kind)) return
override fun putValueIfNeeded(parameterType: JvmKotlinType, value: StackValue, kind: ValueKind, parameterIndex: Int) =
putArgumentToLocalVal(parameterType, value, parameterIndex, kind)
assert(maskValues.isEmpty()) { "Additional default call arguments should be last ones, but $value" }
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 putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) =
putCapturedToLocalVal(stackValue, activeLambda!!.capturedVars[paramIndex], stackValue.kotlinType)
override fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List<ArgumentAndDeclIndex>, valueParameterTypes: List<Type>) = Unit
@@ -294,9 +286,10 @@ class PsiExpressionLambda(
val capturedReceiver = closure.capturedReceiverFromOuterContext
if (capturedReceiver != null) {
val fieldName = closure.getCapturedReceiverFieldName(state.typeMapper.bindingContext, state.languageVersionSettings)
val type = state.typeMapper.mapType(capturedReceiver).let {
if (isBoundCallableReference) AsmUtil.boxType(it) else it
}
val type = if (isBoundCallableReference)
state.typeMapper.mapType(capturedReceiver, null, TypeMappingMode.GENERIC_ARGUMENT)
else
state.typeMapper.mapType(capturedReceiver)
add(capturedParamDesc(fieldName, type, isSuspend = false))
}
@@ -67,7 +67,9 @@ class IrInlineCodegen(
rememberClosure(parameterType, irValueParameter.index, lambdaInfo)
lambdaInfo.generateLambdaBody(sourceCompiler)
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 {
val kind = when (irValueParameter.origin) {
@@ -99,21 +101,11 @@ class IrInlineCodegen(
-> codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo)
}
//TODO support default argument erasure
if (!processDefaultMaskOrMethodHandler(onStack, kind)) {
val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toIrBasedKotlinType())
putArgumentOrCapturedToLocalVal(expectedType, onStack, null, irValueParameter.index, kind)
}
val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toIrBasedKotlinType())
putArgumentToLocalVal(expectedType, onStack, 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() {
invocationParamBuilder.markValueParametersStart()
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM
// DONT_TARGET_EXACT_BACKEND: WASM
// WASM_MUTE_REASON: BINDING_RECEIVERS
// KT-30629
@@ -2535,11 +2535,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
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 {
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");
}
@TestMetadata("genericBoundPropertyAsCrossinline.kt")
public void testGenericBoundPropertyAsCrossinline() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/bound/genericBoundPropertyAsCrossinline.kt");
}
@TestMetadata("genericValOnLHS.kt")
public void testGenericValOnLHS() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/bound/genericValOnLHS.kt");