[JVM] Fix uninitialized locals after coroutine transformation.

The coroutine transformation would leave locals in the local
variable table across the code that reloads local variables from
the continuation on reentry. However, when reentering the function
the local has no value until after the reloads from the
continuation.

This change splits the locals in the local variable table to
avoid such uninitialized locals. A local alive across a
suspension point has its range split in two. One that goes
from the original start to the state label for the restart
after the suspension. The other goes from after the local
has been reloaded from the continuation until the previous
end of the local.
This commit is contained in:
Mads Ager
2021-04-27 16:24:31 +02:00
committed by Ilmir Usmanov
parent 83e3a702c5
commit df225c0c7f
4 changed files with 81 additions and 40 deletions
@@ -23,11 +23,11 @@ class A {
// foo, c's lambda and foo's continuation
// 3 LOCALVARIABLE \$result Ljava/lang/Object;
// foo and <init>
// 2 LOCALVARIABLE this LA;
// 1 LOCALVARIABLE a LA;
// 1 LOCALVARIABLE s Ljava/lang/String;
// 1 LOCALVARIABLE block Lkotlin/jvm/functions/Function2;
// foo x 3 since we split the local over restore code for the two calls to block(), and <init>
// 4 LOCALVARIABLE this LA;
// 3 LOCALVARIABLE a LA;
// 3 LOCALVARIABLE s Ljava/lang/String;
// 3 LOCALVARIABLE block Lkotlin/jvm/functions/Function2;
// 1 LOCALVARIABLE \$continuation Lkotlin/coroutines/Continuation;
// JVM_TEMPLATES
@@ -42,8 +42,8 @@ fun box(): String {
}
// 1 LOCALVARIABLE i Ljava/lang/String; L.* 3
// We merge LVT records for two consequent branches.
// 1 LOCALVARIABLE s Ljava/lang/String; L.* 3
// We merge LVT records for two consequent branches, but we split the local over the restore code.
// 2 LOCALVARIABLE s Ljava/lang/String; L.* 3
// 1 PUTFIELD VarValueConflictsWithTableSameSortKt\$box\$1.L\$0 : Ljava/lang/Object;
/* 1 load in the catch (e: Throwable) { throw e } block which is implicitly wrapped around try/finally */
// 1 ALOAD 3\s+ATHROW