'box'/'unbox' methods are called by inline class

This commit is contained in:
Dmitry Petrov
2018-08-30 14:06:15 +03:00
parent 580b782585
commit b1016936b2
20 changed files with 58 additions and 24 deletions
@@ -402,25 +402,23 @@ public abstract class StackValue {
private static void boxInlineClass(@NotNull KotlinType kotlinType, @NotNull InstructionAdapter v) {
Type boxedType = KotlinTypeMapper.mapInlineClassTypeAsDeclaration(kotlinType);
Type owner = KotlinTypeMapper.mapToErasedInlineClassType(kotlinType);
Type underlyingType = KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(kotlinType);
if (TypeUtils.isNullableType(kotlinType) && !isPrimitive(underlyingType)) {
boxOrUnboxWithNullCheck(v, vv -> invokeBoxMethod(vv, boxedType, owner, underlyingType));
boxOrUnboxWithNullCheck(v, vv -> invokeBoxMethod(vv, boxedType, underlyingType));
}
else {
invokeBoxMethod(v, boxedType, owner, underlyingType);
invokeBoxMethod(v, boxedType, underlyingType);
}
}
private static void invokeBoxMethod(
@NotNull InstructionAdapter v,
Type boxedType,
Type owner,
Type underlyingType
) {
v.invokestatic(
owner.getInternalName(),
boxedType.getInternalName(),
InlineClassDescriptorResolver.BOX_METHOD_NAME.asString(),
Type.getMethodDescriptor(boxedType, underlyingType),
false
@@ -237,9 +237,8 @@ private fun AbstractInsnNode.isInlineClassUnboxing(state: GenerationState) =
private fun MethodInsnNode.isInlineClassBoxingMethodDescriptor(state: GenerationState): Boolean {
if (name != InlineClassDescriptorResolver.BOX_METHOD_NAME.asString()) return false
if (!owner.endsWith(JvmAbi.ERASED_INLINE_CLASS_SUFFIX)) return false
val ownerType = Type.getObjectType(owner.removeSuffix(JvmAbi.ERASED_INLINE_CLASS_SUFFIX))
val ownerType = Type.getObjectType(owner)
val descriptor = state.jvmBackendClassResolver.resolveToClassDescriptors(ownerType).singleOrNull() ?: return false
if (!descriptor.isInline) return false
@@ -15,7 +15,7 @@ fun test(u1: UInt, u2: UInt, u3: UInt?) {
}
// @TestKt.class:
// 3 INVOKESTATIC UInt\$Erased.box
// 3 INVOKESTATIC UInt\.box
// 0 INVOKEVIRTUAL UInt.unbox
// 0 valueOf
// 0 intValue
@@ -0,0 +1,12 @@
// !LANGUAGE: +InlineClasses
// FILE: Z.kt
inline class Z(val x: Int)
// FILE: Test.kt
fun test(): Any = Z(42)
// @TestKt.class:
// 0 INVOKESTATIC Z\$Erased\.box
// 0 INVOKESTATIC Z\-Erased\.box
// 1 INVOKESTATIC Z\.box \(I\)LZ;
@@ -15,10 +15,10 @@ fun test() {
}
// @TestKt.class:
// 1 INVOKESTATIC AsInt\$Erased.box
// 1 INVOKESTATIC AsInt\.box
// 0 INVOKEVIRTUAL AsInt.unbox
// 1 INVOKESTATIC AsAny\$Erased.box
// 1 INVOKESTATIC AsAny\.box
// 0 INVOKEVIRTUAL AsAny.unbox
// 1 valueOf
@@ -13,7 +13,7 @@ inline class UInt(val a: Int) {
fun takeNullable(a: UInt?) {}
// 2 INVOKESTATIC UInt\$Erased.box
// 2 INVOKESTATIC UInt\.box
// 0 INVOKEVIRTUAL Foo.unbox
// 1 valueOf
@@ -25,7 +25,7 @@ fun test(f: Foo) {
}
// @TestKt.class:
// 6 INVOKESTATIC Foo\$Erased.box
// 6 INVOKESTATIC Foo\.box
// 4 INVOKEVIRTUAL Foo.unbox
// 0 valueOf
// 0 intValue
@@ -18,6 +18,7 @@ fun test(x: UInt?, y: UInt) {
// @TestKt.class:
// 0 INVOKESTATIC UInt\$Erased.box
// 0 INVOKESTATIC UInt\.box
// 1 INVOKEVIRTUAL UInt.unbox
// 0 valueOf
@@ -17,10 +17,10 @@ fun test() {
}
// @TestKt.class:
// 1 INVOKESTATIC UInt\$Erased.box
// 1 INVOKESTATIC UInt\.box
// 2 INVOKEVIRTUAL UInt.unbox
// 1 INVOKESTATIC ULong\$Erased.box
// 1 INVOKESTATIC ULong\.box
// 2 INVOKEVIRTUAL ULong.unbox
// 0 valueOf
@@ -23,7 +23,7 @@ fun test(f: Foo) {
}
// @TestKt.class:
// 2 INVOKESTATIC Foo\$Erased.box
// 2 INVOKESTATIC Foo\.box
// 1 INVOKEVIRTUAL Foo.unbox
// 0 valueOf
// 0 intValue
@@ -27,7 +27,7 @@ fun labeled(): ULong? {
}
// @TestKt.class:
// 2 INVOKESTATIC ULong\$Erased.box
// 2 INVOKESTATIC ULong\.box
// 0 INVOKEVIRTUAL ULong.unbox
// 0 valueOf
@@ -11,7 +11,7 @@ fun test(a: InlineNotNullPrimitive, b: InlineNotNullReference) {
testNotNullReference(b, b, b, b) // 2 box
}
// 3 INVOKESTATIC InlineNotNullPrimitive\$Erased.box
// 2 INVOKESTATIC InlineNotNullReference\$Erased.box
// 3 INVOKESTATIC InlineNotNullPrimitive\.box
// 2 INVOKESTATIC InlineNotNullReference\.box
// 0 valueOf
@@ -29,7 +29,7 @@ fun takeNullableUInt(y: UInt?) {}
inline fun <T> T.myLet(f: (T) -> Unit) = f(this)
// @TestKt.class:
// 1 INVOKESTATIC UInt\$Erased.box
// 1 INVOKESTATIC UInt\.box
// 5 INVOKEVIRTUAL UInt.unbox
// 0 intValue
@@ -22,9 +22,9 @@ fun transformToNullableTarget(a: AsInt): AsInt? = a as AsInt? // box
fun transformNullableToNullableTarget(a: AsInt?): AsInt? = a as AsInt?
// @ReferenceKt.class:
// 2 INVOKESTATIC AsAny\$Erased.box
// 2 INVOKESTATIC AsAny\.box
// 1 INVOKEVIRTUAL AsAny.unbox
// @PrimitiveKt.class:
// 2 INVOKESTATIC AsInt\$Erased.box
// 2 INVOKESTATIC AsInt\.box
// 1 INVOKEVIRTUAL AsInt.unbox
@@ -10,6 +10,7 @@ fun test1(us: UIntArray) {
// @NoBoxingKt.class:
// 0 INVOKESTATIC kotlin.UInt\$Erased.box
// 0 INVOKESTATIC kotlin.UInt\.box
// 0 INVOKEVIRTUAL kotlin.UInt.unbox
// FILE: Boxing.kt
@@ -21,5 +22,5 @@ fun test2(nullable: UInt?, ns: Array<UInt>) {
}
// @BoxingKt.class:
// 2 INVOKESTATIC kotlin.UInt\$Erased.box
// 2 INVOKESTATIC kotlin.UInt\.box
// 0 INVOKEVIRTUAL kotlin.UInt.unbox
@@ -14,7 +14,7 @@ fun test(u1: UInt, u2: UInt, us: Array<UInt>) {
}
// @TestKt.class:
// 2 INVOKESTATIC UInt\$Erased.box
// 2 INVOKESTATIC UInt\.box
// 0 INVOKEVIRTUAL UInt.unbox
// 2 CHECKCAST \[LUInt
@@ -27,7 +27,7 @@ fun test() {
fun takeUInt(u: UInt) {}
// 1 INVOKESTATIC UInt\$Erased.box
// 1 INVOKESTATIC UInt\.box
// 1 INVOKEVIRTUAL UInt.unbox
// 0 INVOKEVIRTUAL UIntIterator.iterator
@@ -23,5 +23,6 @@ fun UIntArray.swap(i: Int, j: Int) {
// @TestKt.class:
// 0 INVOKEVIRTUAL UInt.unbox
// 0 INVOKESTATIC UInt\$Erased.box
// 0 INVOKESTATIC UInt\.box
// 0 intValue
// 0 valueOf
@@ -0,0 +1,12 @@
// !LANGUAGE: +InlineClasses
// FILE: Z.kt
inline class Z(val x: Int)
// FILE: Test.kt
fun test(xs: List<Z>) = xs[0]
// @TestKt.class:
// 0 INVOKEVIRTUAL Z\$Erased\.unbox
// 0 INVOKEVIRTUAL Z\-Erased\.unbox
// 1 INVOKEVIRTUAL Z\.unbox \(\)I
@@ -2008,6 +2008,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/boxInlineClassesOnPassingToVarargs.kt");
}
@TestMetadata("boxMethodCalledByInlineClass.kt")
public void testBoxMethodCalledByInlineClass() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/boxMethodCalledByInlineClass.kt");
}
@TestMetadata("boxResultAfterConstructorCall.kt")
public void testBoxResultAfterConstructorCall() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/boxResultAfterConstructorCall.kt");
@@ -2197,6 +2202,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
public void testUnboxInlineClassesAfterSmartCasts() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassesAfterSmartCasts.kt");
}
@TestMetadata("unboxMethodCalledByInlineClass.kt")
public void testUnboxMethodCalledByInlineClass() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/inlineClasses/unboxMethodCalledByInlineClass.kt");
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/interfaces")