JVM: remove TypedNullValue, hack interpreter instead
This commit is contained in:
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
+1
-23
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -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:
|
||||
|
||||
+7
-2
@@ -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)"
|
||||
}
|
||||
}
|
||||
|
||||
-12
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user