diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt index 990220dde2c..4d069b34d44 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt @@ -18,12 +18,16 @@ package org.jetbrains.kotlin.codegen.optimization.boxing import com.google.common.collect.ImmutableSet import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.coroutines.RELEASE_COROUTINES_VERSION_SETTINGS +import org.jetbrains.kotlin.codegen.coroutines.coroutinesJvmInternalPackageFqName import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.codegen.topLevelClassInternalName import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.org.objectweb.asm.Opcodes @@ -174,7 +178,7 @@ fun AbstractInsnNode.isUnboxing(state: GenerationState) = isPrimitiveUnboxing() || isJavaLangClassUnboxing() || isInlineClassUnboxing(state) fun AbstractInsnNode.isBoxing(state: GenerationState) = - isPrimitiveBoxing() || isJavaLangClassBoxing() || isInlineClassBoxing(state) + isPrimitiveBoxing() || isJavaLangClassBoxing() || isInlineClassBoxing(state) || isCoroutinePrimitiveBoxing() fun AbstractInsnNode.isPrimitiveUnboxing() = isMethodInsnWith(Opcodes.INVOKEVIRTUAL) { @@ -211,6 +215,19 @@ fun AbstractInsnNode.isPrimitiveBoxing() = isBoxingMethodDescriptor() } +private val BOXING_CLASS_INTERNAL_NAME = + RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName().child(Name.identifier("Boxing")).topLevelClassInternalName() + +private fun isJvmPrimitiveName(name: String) = JvmPrimitiveType.values().any { it.javaKeywordName == name } + +fun AbstractInsnNode.isCoroutinePrimitiveBoxing(): Boolean { + return isMethodInsnWith(Opcodes.INVOKESTATIC) { + owner == BOXING_CLASS_INTERNAL_NAME && + name.startsWith("box") && + isJvmPrimitiveName(name.substring(3).lowercase()) + } +} + private fun MethodInsnNode.isBoxingMethodDescriptor(): Boolean { val ownerType = Type.getObjectType(owner) return desc == Type.getMethodDescriptor(ownerType, AsmUtil.unboxType(ownerType)) diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java index 456682bacca..946d4094edd 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java @@ -742,6 +742,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/simpleUninitializedMerge.kt"); } + @Test + @TestMetadata("suspendBoxing.kt") + public void testSuspendBoxing() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/suspendBoxing.kt"); + } + @Test @TestMetadata("unsafeRemoving.kt") public void testUnsafeRemoving() throws Exception { diff --git a/compiler/testData/codegen/bytecodeText/boxingOptimization/suspendBoxing.kt b/compiler/testData/codegen/bytecodeText/boxingOptimization/suspendBoxing.kt new file mode 100644 index 00000000000..251ed68a1f7 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/boxingOptimization/suspendBoxing.kt @@ -0,0 +1,66 @@ +inline fun fInt(g: (Int) -> Unit) { + g(1) +} + +inline fun fBoolean(g: (Boolean) -> Unit) { + g(true) +} + +inline fun fChar(g: (Char) -> Unit) { + g('a') +} + +inline fun fByte(g: (Byte) -> Unit) { + g(1) +} + +inline fun fShort(g: (Short) -> Unit) { + g(1) +} + +inline fun fFloat(g: (Float) -> Unit) { + g(1.0f) +} + +inline fun fLong(g: (Long) -> Unit) { + g(1L) +} + +inline fun fDouble(g: (Double) -> Unit) { + g(1.0) +} + +fun bar() { + fInt { } + fBoolean { } + fChar { } + fByte { } + fShort { } + fFloat { } + fLong { } + fDouble { } +} + +suspend fun baz() { + fInt { } + fBoolean { } + fChar { } + fByte { } + fShort { } + fFloat { } + fLong { } + fDouble { } +} + +// The inline functions will contain boxing for the value passed to the lambda. +// 8 valueOf + +// After inlining there will be boxing and unboxing that is not needed. That should be optimized out. +// 0 intValue +// 0 booleanValue +// 0 charValue +// 0 byteValue +// 0 shortValue +// 0 floatValue +// 0 longValue +// 0 doubleValue diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java index 47b402553a6..767a79d6fb2 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java @@ -742,6 +742,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/simpleUninitializedMerge.kt"); } + @Test + @TestMetadata("suspendBoxing.kt") + public void testSuspendBoxing() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/suspendBoxing.kt"); + } + @Test @TestMetadata("unsafeRemoving.kt") public void testUnsafeRemoving() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java index c9e86fe7df6..c571c834edb 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java @@ -742,6 +742,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/simpleUninitializedMerge.kt"); } + @Test + @TestMetadata("suspendBoxing.kt") + public void testSuspendBoxing() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/suspendBoxing.kt"); + } + @Test @TestMetadata("unsafeRemoving.kt") public void testUnsafeRemoving() throws Exception {