[IR] Eliminate redundant boxing/unboxing of MFVC after inlining
Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com> #KT-1179
This commit is contained in:
committed by
Space Team
parent
a3e396e7e4
commit
40f38c8adb
@@ -1,7 +1,6 @@
|
||||
@kotlin.Metadata
|
||||
public final class ClassFlatteningKt {
|
||||
// source: 'classFlattening.kt'
|
||||
private final static method box$lambda$3$lambda$2(p0: int, p1: int, p2: java.lang.String, p3: int, p4: int, p5: java.lang.String, p6: int, p7: int, p8: java.lang.String): void
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static method gmfvc-Ket90g4(p0: int, p1: int, p2: int, @org.jetbrains.annotations.NotNull p3: java.lang.String, p4: int, p5: int, p6: int, @org.jetbrains.annotations.NotNull p7: java.lang.String, p8: int): int
|
||||
public final static method ic-K5cTq2M(p0: int): int
|
||||
|
||||
@@ -63,7 +63,6 @@ public final class DefaultParametersKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method complexFun-552ch2I(p0: double, p1: double, p2: double, p3: double, p4: double, p5: double): java.lang.String
|
||||
public synthetic static method complexInlineFun-552ch2I$default(p0: double, p1: double, p2: double, p3: double, p4: double, p5: double, p6: int, p7: java.lang.Object): java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method complexInlineFun-552ch2I(p0: double, p1: double, p2: double, p3: double, p4: double, p5: double): java.lang.String
|
||||
public final inner class kotlin/jvm/internal/Ref$DoubleRef
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,38 +3,13 @@
|
||||
// WITH_COROUTINES
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// LANGUAGE: +ValueClasses
|
||||
// FIR_IDENTICAL
|
||||
|
||||
// FILE: caller.kt
|
||||
import kotlin.coroutines.*
|
||||
|
||||
fun runSuspend(block: suspend () -> Unit) {
|
||||
val run = RunSuspend()
|
||||
block.startCoroutine(run)
|
||||
run.await()
|
||||
}
|
||||
|
||||
private class RunSuspend : Continuation<Unit> {
|
||||
override val context: CoroutineContext
|
||||
get() = EmptyCoroutineContext
|
||||
|
||||
var result: Result<Unit>? = null
|
||||
|
||||
override fun resumeWith(result: Result<Unit>) = synchronized(this) {
|
||||
this.result = result
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") (this as Object).notifyAll()
|
||||
}
|
||||
|
||||
fun await() = synchronized(this) {
|
||||
while (true) {
|
||||
when (val result = this.result) {
|
||||
null -> @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") (this as Object).wait()
|
||||
else -> {
|
||||
result.getOrThrow() // throw up failure
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
block.startCoroutine(Continuation(EmptyCoroutineContext) { it.getOrThrow() })
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
@@ -233,6 +233,17 @@ public final class AnotherKt {
|
||||
public final static @org.jetbrains.annotations.Nullable method requiresF-lIoT8es(p0: double, p1: double, @org.jetbrains.annotations.NotNull p2: F, @org.jetbrains.annotations.NotNull p3: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class CallerKt$runSuspend$$inlined$Continuation$1 {
|
||||
// source: 'Continuation.kt'
|
||||
enclosing method CallerKt.runSuspend(Lkotlin/jvm/functions/Function1;)V
|
||||
synthetic final field $context: kotlin.coroutines.CoroutineContext
|
||||
inner (anonymous) class CallerKt$runSuspend$$inlined$Continuation$1
|
||||
public method <init>(p0: kotlin.coroutines.CoroutineContext): void
|
||||
public @org.jetbrains.annotations.NotNull method getContext(): kotlin.coroutines.CoroutineContext
|
||||
public method resumeWith(@org.jetbrains.annotations.NotNull p0: java.lang.Object): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class CallerKt {
|
||||
// source: 'caller.kt'
|
||||
@@ -306,18 +317,6 @@ public interface F {
|
||||
public abstract @org.jetbrains.annotations.Nullable method run-GPBa7dw(p0: double, p1: double, @org.jetbrains.annotations.NotNull p2: kotlin.coroutines.Continuation): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
final class RunSuspend {
|
||||
// source: 'caller.kt'
|
||||
private @org.jetbrains.annotations.Nullable field result: kotlin.Result
|
||||
public method <init>(): void
|
||||
public final method await(): void
|
||||
public @org.jetbrains.annotations.NotNull method getContext(): kotlin.coroutines.CoroutineContext
|
||||
public final @org.jetbrains.annotations.Nullable method getResult-xLWZpok(): kotlin.Result
|
||||
public method resumeWith(@org.jetbrains.annotations.NotNull p0: java.lang.Object): void
|
||||
public final method setResult(@org.jetbrains.annotations.Nullable p0: kotlin.Result): void
|
||||
}
|
||||
|
||||
@kotlin.coroutines.jvm.internal.DebugMetadata
|
||||
@kotlin.Metadata
|
||||
final class TestKt$box$10 {
|
||||
@@ -2049,11 +2048,6 @@ public final class TestKt {
|
||||
inner (anonymous) class TestKt$box$97
|
||||
inner (anonymous) class TestKt$box$98
|
||||
inner (anonymous) class TestKt$box$99
|
||||
private final static method box$lambda$2$lambda$1(p0: double, p1: double, p2: double, p3: double): DPoint
|
||||
private final static method box$lambda$4$lambda$3(p0: double, p1: double, p2: double, p3: double): DPoint
|
||||
private final static method box$lambda$7$lambda$6(p0: double, p1: double): DPoint
|
||||
private final static method box$stub_for_inlining$0$stub_for_inlining(p0: double, p1: double, p2: double, p3: double): DPoint
|
||||
private final static method box$stub_for_inlining$9$stub_for_inlining$8(p0: double, p1: double): DPoint
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static @org.jetbrains.annotations.NotNull method consume-lIoT8es(p0: double, p1: double, p2: double, p3: double, @org.jetbrains.annotations.NotNull p4: kotlin.jvm.functions.Function2): DPoint
|
||||
public final static @org.jetbrains.annotations.NotNull method consumeInline-lIoT8es(p0: double, p1: double, p2: double, p3: double, @org.jetbrains.annotations.NotNull p4: kotlin.jvm.functions.Function2): DPoint
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// LANGUAGE: +ValueClasses
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// CHECK_BYTECODE_LISTING
|
||||
// WITH_STDLIB
|
||||
// CHECK_BYTECODE_TEXT
|
||||
// FIR_IDENTICAL
|
||||
|
||||
// FILE: caller.kt
|
||||
import kotlin.coroutines.*
|
||||
|
||||
fun runSuspend(block: suspend () -> Unit) {
|
||||
block.startCoroutine(Continuation(EmptyCoroutineContext) { it.getOrThrow() })
|
||||
}
|
||||
|
||||
// FILE: dependency.kt
|
||||
|
||||
@JvmInline
|
||||
value class DPoint(val x: Double, val y: Double)
|
||||
|
||||
@JvmInline
|
||||
value class DSegment(val p1: DPoint, val p2: DPoint)
|
||||
|
||||
|
||||
inline fun DSegment.myLet(f: (DSegment) -> DPoint) = f(this)
|
||||
|
||||
// FILE: test.kt
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
fun supply(x: Any?) = Unit
|
||||
|
||||
fun box(): String {
|
||||
val point = DPoint(1.0, 2.0)
|
||||
val pointX2 = DPoint(2.0, 4.0)
|
||||
val segment = DSegment(point, pointX2)
|
||||
|
||||
supply("a")
|
||||
point.let { it.x }
|
||||
supply("b")
|
||||
point.let { it }
|
||||
supply("c")
|
||||
run { DPoint (1.0, 2.0) }
|
||||
supply("d")
|
||||
val x = run { DPoint(100.0, 200.0) }
|
||||
supply("e")
|
||||
require(x == DPoint(100.0, 200.0))
|
||||
supply("f")
|
||||
point.let { DPoint(2 * it.x, 2 * it.y) }
|
||||
supply("g")
|
||||
require(point == point.let { it })
|
||||
supply("h")
|
||||
require(pointX2 == point.let { DPoint(2 * it.x, 2 * it.y) })
|
||||
supply("i")
|
||||
segment.myLet { it.p1 }
|
||||
supply("j")
|
||||
segment.myLet { it.p2 }
|
||||
supply("k")
|
||||
require(segment.myLet { it.p1 } == point)
|
||||
supply("l")
|
||||
require(segment.myLet { it.p2 } == pointX2)
|
||||
supply("m")
|
||||
require(segment.let { it.let { it } } == segment)
|
||||
supply("n")
|
||||
var a = 1
|
||||
segment.let { a++ }
|
||||
val b = segment.let { ++a }
|
||||
require(a == 3)
|
||||
supply("o")
|
||||
runSuspend { require(suspendFun() == DPoint(1.0, 2.0).toString()) }
|
||||
supply("p")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
suspend fun f() = suspendCoroutine { it.resume(Unit) }
|
||||
suspend fun suspendFun(): String {
|
||||
val x = run { f(); DPoint(1.0, 2.0) }
|
||||
return x.toString()
|
||||
}
|
||||
|
||||
// @TestKt.class:
|
||||
// 0 valueOf
|
||||
// 0 INVOKE(STATIC|VIRTUAL) (DPoint|DSegment).*\.(un)?box
|
||||
// 0 INVOKE(STATIC|VIRTUAL) .*(stub_for_inlining|lambda)
|
||||
// 0 DCONST_0
|
||||
@@ -0,0 +1,110 @@
|
||||
@kotlin.Metadata
|
||||
public final class CallerKt$runSuspend$$inlined$Continuation$1 {
|
||||
// source: 'Continuation.kt'
|
||||
enclosing method CallerKt.runSuspend(Lkotlin/jvm/functions/Function1;)V
|
||||
synthetic final field $context: kotlin.coroutines.CoroutineContext
|
||||
inner (anonymous) class CallerKt$runSuspend$$inlined$Continuation$1
|
||||
public method <init>(p0: kotlin.coroutines.CoroutineContext): void
|
||||
public @org.jetbrains.annotations.NotNull method getContext(): kotlin.coroutines.CoroutineContext
|
||||
public method resumeWith(@org.jetbrains.annotations.NotNull p0: java.lang.Object): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class CallerKt {
|
||||
// source: 'caller.kt'
|
||||
public final static method runSuspend(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmInline
|
||||
@kotlin.Metadata
|
||||
public final class DPoint {
|
||||
// source: 'dependency.kt'
|
||||
private final field x: double
|
||||
private final field y: double
|
||||
private synthetic method <init>(p0: double, p1: double): void
|
||||
public synthetic final static method box-impl(p0: double, p1: double): DPoint
|
||||
public final static method constructor-impl(p0: double, p1: double): void
|
||||
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
|
||||
public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
|
||||
public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
|
||||
public final method getX(): double
|
||||
public final method getY(): double
|
||||
public method hashCode(): int
|
||||
public static method hashCode-impl(p0: double, p1: double): int
|
||||
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
|
||||
public static method toString-impl(p0: double, p1: double): java.lang.String
|
||||
public synthetic final method unbox-impl-x(): double
|
||||
public synthetic final method unbox-impl-y(): double
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmInline
|
||||
@kotlin.Metadata
|
||||
public final class DSegment {
|
||||
// source: 'dependency.kt'
|
||||
private final field p1-x: double
|
||||
private final field p1-y: double
|
||||
private final field p2-x: double
|
||||
private final field p2-y: double
|
||||
private synthetic method <init>(p0: double, p1: double, p2: double, p3: double): void
|
||||
public synthetic final static method box-impl(p0: double, p1: double, p2: double, p3: double): DSegment
|
||||
public final static method constructor-impl(p0: double, p1: double, p2: double, p3: double): void
|
||||
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
|
||||
public static method equals-impl(p0: double, p1: double, p2: double, p3: double, p4: java.lang.Object): boolean
|
||||
public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double, p4: double, p5: double, p6: double, p7: double): boolean
|
||||
public final @org.jetbrains.annotations.NotNull method getP1(): DPoint
|
||||
public final @org.jetbrains.annotations.NotNull method getP2(): DPoint
|
||||
public method hashCode(): int
|
||||
public static method hashCode-impl(p0: double, p1: double, p2: double, p3: double): int
|
||||
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
|
||||
public static method toString-impl(p0: double, p1: double, p2: double, p3: double): java.lang.String
|
||||
public synthetic final method unbox-impl-p1(): DPoint
|
||||
public synthetic final method unbox-impl-p1-x(): double
|
||||
public synthetic final method unbox-impl-p1-y(): double
|
||||
public synthetic final method unbox-impl-p2(): DPoint
|
||||
public synthetic final method unbox-impl-p2-x(): double
|
||||
public synthetic final method unbox-impl-p2-y(): double
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class DependencyKt {
|
||||
// source: 'dependency.kt'
|
||||
public final static @org.jetbrains.annotations.NotNull method myLet-GPBa7dw(p0: double, p1: double, p2: double, p3: double, @org.jetbrains.annotations.NotNull p4: kotlin.jvm.functions.Function1): DPoint
|
||||
}
|
||||
|
||||
@kotlin.coroutines.jvm.internal.DebugMetadata
|
||||
@kotlin.Metadata
|
||||
final class TestKt$box$13 {
|
||||
// source: 'test.kt'
|
||||
enclosing method TestKt.box()Ljava/lang/String;
|
||||
field label: int
|
||||
inner (anonymous) class TestKt$box$13
|
||||
method <init>(p0: kotlin.coroutines.Continuation): void
|
||||
public final @org.jetbrains.annotations.NotNull method create(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): kotlin.coroutines.Continuation
|
||||
public final @org.jetbrains.annotations.Nullable method invoke(@org.jetbrains.annotations.Nullable p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public synthetic bridge method invoke(p0: java.lang.Object): java.lang.Object
|
||||
public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.coroutines.jvm.internal.DebugMetadata
|
||||
@kotlin.Metadata
|
||||
final class TestKt$suspendFun$1 {
|
||||
// source: 'test.kt'
|
||||
enclosing method TestKt.suspendFun(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
field label: int
|
||||
synthetic field result: java.lang.Object
|
||||
inner (anonymous) class TestKt$suspendFun$1
|
||||
method <init>(p0: kotlin.coroutines.Continuation): void
|
||||
public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class TestKt {
|
||||
// source: 'test.kt'
|
||||
inner (anonymous) class TestKt$box$13
|
||||
inner (anonymous) class TestKt$suspendFun$1
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static @org.jetbrains.annotations.Nullable method f(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final static method supply(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendFun(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
|
||||
public final inner class kotlin/jvm/internal/Ref$IntRef
|
||||
}
|
||||
@@ -12,13 +12,23 @@ class Box(var value: DPoint)
|
||||
fun supplier(index: Int) {} // to make usage of the argument
|
||||
fun supplier(index: Int, x: DPoint) {} // to make usage of the argument
|
||||
|
||||
|
||||
fun `1`() = 1.0
|
||||
fun `2`() = 2.0
|
||||
fun `3`() = 3.0
|
||||
fun `4`() = 4.0
|
||||
fun `5`() = 5.0
|
||||
fun `6`() = 6.0
|
||||
fun `7`() = 7.0
|
||||
fun `8`() = 8.0
|
||||
|
||||
fun reassignVariable(x: DPoint, box: Box) {
|
||||
supplier(100)
|
||||
var p = DPoint(1.0, 2.0) // should not use temporary variables
|
||||
var p = DPoint(`1`(), `2`()) // should not use temporary variables
|
||||
supplier(101, p)
|
||||
p = p // should not use temporary variables
|
||||
supplier(102, p)
|
||||
p = DPoint(3.0, 4.0) // should use tempVars
|
||||
p = DPoint(`3`(), `4`()) // should use tempVars
|
||||
supplier(103, p)
|
||||
p = x // should not use temporary variables
|
||||
supplier(104, p)
|
||||
@@ -30,13 +40,13 @@ fun reassignVariable(x: DPoint, box: Box) {
|
||||
|
||||
fun reassignField(x: DPoint, box: Box) {
|
||||
supplier(107)
|
||||
val p = DPoint(5.0, 6.0)
|
||||
val p = DPoint(`5`(), `6`())
|
||||
supplier(108, p)
|
||||
var b = Box(p) // should not use temporary variables
|
||||
supplier(109)
|
||||
b.value = b.value // should not use temporary variables
|
||||
supplier(110)
|
||||
b.value = DPoint(7.0, 8.0) // should use tempVars
|
||||
b.value = DPoint(`7`(), `8`()) // should use tempVars
|
||||
supplier(111)
|
||||
b.value = x // should not use temporary variables
|
||||
supplier(112)
|
||||
|
||||
+12
-7
@@ -7,12 +7,17 @@
|
||||
@JvmInline
|
||||
value class DPoint(val x: Double, val y: Double)
|
||||
|
||||
fun `1`() = 1.0
|
||||
fun `2`() = 2.0
|
||||
fun `3`() = 3.0
|
||||
fun `4`() = 4.0
|
||||
|
||||
fun acceptBoxed(x: Any?) {}
|
||||
fun acceptFlattened(x: DPoint) {}
|
||||
fun returnBoxed() = DPoint(3.0, 4.0)
|
||||
fun returnBoxed() = DPoint(`3`(), `4`())
|
||||
|
||||
fun testFlattened2Boxed() {
|
||||
acceptBoxed(DPoint(1.0, 2.0))
|
||||
acceptBoxed(DPoint(`1`(), `2`()))
|
||||
}
|
||||
|
||||
fun testBoxed2Boxed() {
|
||||
@@ -20,7 +25,7 @@ fun testBoxed2Boxed() {
|
||||
}
|
||||
|
||||
fun testFlattened2Flattened() {
|
||||
acceptFlattened(DPoint(1.0, 2.0))
|
||||
acceptFlattened(DPoint(`1`(), `2`()))
|
||||
}
|
||||
|
||||
fun testBoxed2Flattened() {
|
||||
@@ -28,8 +33,8 @@ fun testBoxed2Flattened() {
|
||||
}
|
||||
|
||||
fun testIgnoredFlattened() {
|
||||
DPoint(1.0, 2.0)
|
||||
DPoint(1.0, 2.0)
|
||||
DPoint(`1`(), `2`())
|
||||
DPoint(`1`(), `2`())
|
||||
}
|
||||
|
||||
fun testIgnoredBoxed() {
|
||||
@@ -38,8 +43,8 @@ fun testIgnoredBoxed() {
|
||||
|
||||
object Init {
|
||||
init {
|
||||
DPoint(1.0, 2.0)
|
||||
DPoint(1.0, 2.0)
|
||||
DPoint(`1`(), `2`())
|
||||
DPoint(`1`(), `2`())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user