JVM: remove TypedNullValue, hack interpreter instead

This commit is contained in:
pyos
2022-05-10 16:38:39 +02:00
committed by teamcity
parent 513ef575ce
commit 0fc676a20c
5 changed files with 13 additions and 39 deletions
@@ -669,7 +669,7 @@ class CoroutineTransformerMethodVisitor(
val value = frame.getLocal(slot)
if (value.type == null || !livenessFrame.isAlive(slot)) continue
if (value == StrictBasicValue.NULL_VALUE || value is TypedNullValue) {
if (value == StrictBasicValue.NULL_VALUE) {
referencesToSpill += slot to null
continue
}
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.codegen.coroutines
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
@@ -135,7 +134,7 @@ internal fun performSpilledVariableFieldTypesAnalysis(
for ((insn, type) in interpreter.needsToBeCoerced) {
methodNode.instructions.insert(insn, withInstructionAdapter { coerceInt(type, this) })
}
return FastMethodAnalyzer(thisName, methodNode, NullCheckcastAwareOptimizationBasicInterpreter()).analyze()
return FastMethodAnalyzer(thisName, methodNode, OptimizationBasicInterpreter()).analyze()
}
private fun coerceInt(to: Type, v: InstructionAdapter) {
@@ -159,24 +158,3 @@ private fun Type.isIntLike(): Boolean = when (sort) {
Type.BOOLEAN, Type.BYTE, Type.CHAR, Type.SHORT -> true
else -> false
}
// Represents [ACONST_NULL, CHECKCAST Type] sequence result.
internal class TypedNullValue(type: Type) : StrictBasicValue(type)
// Preserves nulls through CHECKCASTS.
private class NullCheckcastAwareOptimizationBasicInterpreter : OptimizationBasicInterpreter() {
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? {
if (insn.opcode == Opcodes.CHECKCAST && (value == StrictBasicValue.NULL_VALUE || value is TypedNullValue)) {
return TypedNullValue(Type.getObjectType((insn as TypeInsnNode).desc))
}
return super.unaryOperation(insn, value)
}
override fun merge(v: BasicValue, w: BasicValue): BasicValue =
when {
v is TypedNullValue && w is TypedNullValue -> if (v.type == w.type) v else StrictBasicValue.NULL_VALUE
v is TypedNullValue -> super.merge(StrictBasicValue.NULL_VALUE, w)
w is TypedNullValue -> super.merge(v, StrictBasicValue.NULL_VALUE)
else -> super.merge(v, w)
}
}
@@ -204,7 +204,7 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
case DREM:
return StrictBasicValue.DOUBLE_VALUE;
case AALOAD:
return StrictBasicValue.REFERENCE_VALUE;
return StrictBasicValue.NULL_VALUE;
case LCMP:
case FCMPL:
case FCMPG:
@@ -331,6 +331,9 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
case ATHROW:
return null;
case CHECKCAST:
if (value == StrictBasicValue.NULL_VALUE) {
return StrictBasicValue.NULL_VALUE;
}
desc = ((TypeInsnNode) insn).desc;
return newValue(Type.getObjectType(desc));
case INSTANCEOF:
@@ -68,7 +68,12 @@ open class StrictBasicValue(type: Type?) : BasicValue(type) {
override fun hashCode() = (type?.hashCode() ?: 0)
override fun toString(): String {
if (this === UNINITIALIZED_VALUE) return "."
return super.toString()
val inner = when {
this === REFERENCE_VALUE -> "R"
this === NULL_VALUE -> "null"
this === UNINITIALIZED_VALUE -> "."
else -> super.toString()
}
return "${this::class.java.simpleName}($inner)"
}
}
@@ -657,18 +657,6 @@ 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) {