JVM: make inline function argument processing a bit shorter
This commit is contained in:
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
+5
-13
@@ -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
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM
|
||||
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: BINDING_RECEIVERS
|
||||
// KT-30629
|
||||
|
||||
+5
-5
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user