Generate CHECKCAST after ACONST_NULL in coroutines

If we do not do this, the state-machine builder will not know the type
of the ACONST_NULL, defaulting to Object, leading to VerifyError.
Alternatively, we could use LVT to deduce the type, but getting types
from LVT is something I got rid of long time ago, and I have no desire
to return it back.

Generating CHECKCAST hints the state-machine builder the type of the
variable avoiding the issue of VerifyError. However, this CHECKCAST
replaces StrictBasicValue.NULL_VALUE with BasicValue in
OptimizationBasicInterpreter. To preserve optimization on not-spilling
known nulls, introduce BasicValues, which represent typed nulls and
create BasicInterpreter, which is aware of them. This way we have the
best of two worlds - we do not spill known nulls, and we know the type
of ACONST_NULL.

 #KT-51718 Fixed
This commit is contained in:
Ilmir Usmanov
2022-03-30 03:34:07 +02:00
committed by teamcity
parent 9b103b35cd
commit 7579be6c68
15 changed files with 136 additions and 15 deletions
@@ -45,8 +45,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_STRING_TYPE
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
@@ -653,6 +652,18 @@ class ExpressionCodegen(
val value = initializer.accept(this, data)
initializer.markLineNumber(startOffset = true)
value.materializeAt(varType, declaration.type)
// We need to generate CHECKCAST from ACONST_NULL here for coroutines,
// since otherwise, upon spilling and then unspilling, we will get VerifyError,
// because state-machine builder does not know the type of the ACONST_NULL
// and assumes it to be Ljava/lang/Object;, which is incorrect.
// Generating CHECKCAST hints the state-machine builder the type of the variable
// avoiding the issue of VerifyError. See KT-51718
// Exception is Ljava/lang/Object;, since CHECKCAST Ljava/lang/Object; is effectively no-op.
if (initializer.isNullConst() && varType != OBJECT_TYPE &&
(irFunction.isSuspend || irFunction.isInvokeSuspendOfLambda())
) {
mv.checkcast(varType)
}
declaration.markLineNumber(startOffset = true)
mv.store(index, varType)
} else if (declaration.isVisibleInLVT) {