[JVM] Extend boxing/unboxing optimizations to coroutine boxing.

This commit is contained in:
Mads Ager
2021-05-06 11:21:26 +02:00
committed by Ilmir Usmanov
parent 4994cb3774
commit afa1b8bfdc
5 changed files with 102 additions and 1 deletions
@@ -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))
@@ -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 {
@@ -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
@@ -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 {
@@ -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 {