[JVM] Extend boxing/unboxing optimizations to coroutine boxing.
This commit is contained in:
+18
-1
@@ -18,12 +18,16 @@ package org.jetbrains.kotlin.codegen.optimization.boxing
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableSet
|
import com.google.common.collect.ImmutableSet
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
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.intrinsics.IntrinsicMethods
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
|
import org.jetbrains.kotlin.codegen.topLevelClassInternalName
|
||||||
import org.jetbrains.kotlin.name.FqName
|
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.AsmTypes
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
@@ -174,7 +178,7 @@ fun AbstractInsnNode.isUnboxing(state: GenerationState) =
|
|||||||
isPrimitiveUnboxing() || isJavaLangClassUnboxing() || isInlineClassUnboxing(state)
|
isPrimitiveUnboxing() || isJavaLangClassUnboxing() || isInlineClassUnboxing(state)
|
||||||
|
|
||||||
fun AbstractInsnNode.isBoxing(state: GenerationState) =
|
fun AbstractInsnNode.isBoxing(state: GenerationState) =
|
||||||
isPrimitiveBoxing() || isJavaLangClassBoxing() || isInlineClassBoxing(state)
|
isPrimitiveBoxing() || isJavaLangClassBoxing() || isInlineClassBoxing(state) || isCoroutinePrimitiveBoxing()
|
||||||
|
|
||||||
fun AbstractInsnNode.isPrimitiveUnboxing() =
|
fun AbstractInsnNode.isPrimitiveUnboxing() =
|
||||||
isMethodInsnWith(Opcodes.INVOKEVIRTUAL) {
|
isMethodInsnWith(Opcodes.INVOKEVIRTUAL) {
|
||||||
@@ -211,6 +215,19 @@ fun AbstractInsnNode.isPrimitiveBoxing() =
|
|||||||
isBoxingMethodDescriptor()
|
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 {
|
private fun MethodInsnNode.isBoxingMethodDescriptor(): Boolean {
|
||||||
val ownerType = Type.getObjectType(owner)
|
val ownerType = Type.getObjectType(owner)
|
||||||
return desc == Type.getMethodDescriptor(ownerType, AsmUtil.unboxType(ownerType))
|
return desc == Type.getMethodDescriptor(ownerType, AsmUtil.unboxType(ownerType))
|
||||||
|
|||||||
+6
@@ -742,6 +742,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/simpleUninitializedMerge.kt");
|
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
|
@Test
|
||||||
@TestMetadata("unsafeRemoving.kt")
|
@TestMetadata("unsafeRemoving.kt")
|
||||||
public void testUnsafeRemoving() throws Exception {
|
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
|
||||||
+6
@@ -742,6 +742,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/simpleUninitializedMerge.kt");
|
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
|
@Test
|
||||||
@TestMetadata("unsafeRemoving.kt")
|
@TestMetadata("unsafeRemoving.kt")
|
||||||
public void testUnsafeRemoving() throws Exception {
|
public void testUnsafeRemoving() throws Exception {
|
||||||
|
|||||||
+6
@@ -742,6 +742,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/simpleUninitializedMerge.kt");
|
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
|
@Test
|
||||||
@TestMetadata("unsafeRemoving.kt")
|
@TestMetadata("unsafeRemoving.kt")
|
||||||
public void testUnsafeRemoving() throws Exception {
|
public void testUnsafeRemoving() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user