提交 822c1481 编写于 作者: I Ilmir Usmanov

Revert "Completely rewrite reifiedIntTypeAnalysis, making it more streamline"

This reverts commit 1ed43246.

Otherwise, bootstrap is broken.
上级 148f49d5
......@@ -593,7 +593,7 @@ class CoroutineTransformerMethodVisitor(
private fun spillVariables(suspensionPoints: List<SuspensionPoint>, methodNode: MethodNode): List<List<SpilledVariableDescriptor>> {
val instructions = methodNode.instructions
val frames = performSpilledVariableFieldTypesAnalysis(methodNode, containingClassInternalName)
val frames = performRefinedTypeAnalysis(methodNode, containingClassInternalName)
fun AbstractInsnNode.index() = instructions.indexOf(this)
// We postpone these actions because they change instruction indices that we use when obtaining frames
......@@ -641,11 +641,11 @@ class CoroutineTransformerMethodVisitor(
.map { Pair(it, frame.getLocal(it)) }
.filter { (index, value) ->
(index == 0 && needDispatchReceiver && isForNamedFunction) ||
(value.type != null && livenessFrame.isAlive(index))
(value != StrictBasicValue.UNINITIALIZED_VALUE && livenessFrame.isAlive(index))
}
for ((index, basicValue) in variablesToSpill) {
if (basicValue.type == NULL_TYPE) {
if (basicValue === StrictBasicValue.NULL_VALUE) {
postponedActions.add {
with(instructions) {
insert(suspension.tryCatchBlockEndLabelAfterSuspensionCall, withInstructionAdapter {
......@@ -657,7 +657,7 @@ class CoroutineTransformerMethodVisitor(
continue
}
val type = basicValue.type!!
val type = basicValue.type
val normalizedType = type.normalize()
val indexBySort = varsCountByType[normalizedType]?.plus(1) ?: 0
......
......@@ -18,6 +18,7 @@ import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicInterpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
private class PossibleSpilledValue(val source: AbstractInsnNode, type: Type?) : BasicValue(type) {
val usages = mutableSetOf<AbstractInsnNode>()
......
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.coroutines
import org.jetbrains.kotlin.codegen.inline.insnOpcodeText
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Handle
import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
// BasicValue interpreter from ASM does not distinct 'int' types from other int-like types like 'byte' or 'boolean',
// neither do HotSpot and JVM spec.
// But it seems like Dalvik does not follow it, and spilling boolean value into an 'int' field fails with VerifyError on Android 4,
// so this function calculates refined frames' markup.
// Note that type of some values is only possible to determine by their usages (e.g. ICONST_1, BALOAD both may push boolean or byte on stack)
// In this case, update the type of the value.
// StrictBasicValue with mutable type
internal open class SpilledVariableFieldTypeValue(open var type: Type?, val insn: AbstractInsnNode?) : Value {
override fun getSize(): Int = type?.size ?: 1
override fun equals(other: Any?): Boolean = other is SpilledVariableFieldTypeValue && type == other.type && insn == other.insn
override fun hashCode(): Int = (type?.hashCode() ?: 0) xor insn.hashCode()
override fun toString() = if (type == null) "." else "$type"
}
private class MergedSpilledVariableFieldTypeValue(
val values: Set<SpilledVariableFieldTypeValue>
) : SpilledVariableFieldTypeValue(null, null) {
init {
require(values.none { it is MergedSpilledVariableFieldTypeValue })
}
override var type: Type?
get() = values.first().type
set(newType) {
for (value in values) {
value.type = newType
}
}
override fun equals(other: Any?): Boolean = other is MergedSpilledVariableFieldTypeValue && other.values == values
override fun hashCode(): Int = values.hashCode()
override fun toString(): String = "M$values"
}
private operator fun SpilledVariableFieldTypeValue?.plus(other: SpilledVariableFieldTypeValue?): SpilledVariableFieldTypeValue? = when {
this == null -> other
other == null -> this
this == other -> this
this is MergedSpilledVariableFieldTypeValue -> {
if (other is MergedSpilledVariableFieldTypeValue) MergedSpilledVariableFieldTypeValue(values + other.values)
else MergedSpilledVariableFieldTypeValue(values + other)
}
other is MergedSpilledVariableFieldTypeValue -> MergedSpilledVariableFieldTypeValue(other.values + this)
else -> MergedSpilledVariableFieldTypeValue(setOf(this, other))
}
internal val NULL_TYPE = Type.getObjectType("null")
// Same as BasicInterpreter, but updates types based on usages
private class SpilledVariableFieldTypesInterpreter(
private val methodNode: MethodNode
) : Interpreter<SpilledVariableFieldTypeValue>(API_VERSION) {
override fun newValue(type: Type?): SpilledVariableFieldTypeValue? =
if (type == Type.VOID_TYPE) null else SpilledVariableFieldTypeValue(type, null)
// INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE,
// MULTIANEWARRAY and INVOKEDYNAMIC
override fun naryOperation(
insn: AbstractInsnNode,
values: MutableList<out SpilledVariableFieldTypeValue?>
): SpilledVariableFieldTypeValue? {
fun updateTypes(argTypes: Array<Type>, withReceiver: Boolean) {
val offset = if (withReceiver) 1 else 0
for ((index, argType) in argTypes.withIndex()) {
val value = values[index + offset] ?: continue
if (argType.isIntType()) {
value.type = argType
} else if (
(value.type == AsmTypes.OBJECT_TYPE && argType != AsmTypes.OBJECT_TYPE) ||
value.type == NULL_TYPE || value.type == null
) {
value.type = argType
}
}
}
return SpilledVariableFieldTypeValue(
when (insn.opcode) {
MULTIANEWARRAY -> {
Type.getType((insn as MultiANewArrayInsnNode).desc)
}
INVOKEDYNAMIC -> {
updateTypes(Type.getArgumentTypes((insn as InvokeDynamicInsnNode).desc), false)
Type.getReturnType(insn.desc)
}
INVOKESTATIC -> {
updateTypes(Type.getArgumentTypes((insn as MethodInsnNode).desc), false)
Type.getReturnType(insn.desc)
}
INVOKEVIRTUAL, INVOKEINTERFACE, INVOKESPECIAL -> {
updateTypes(Type.getArgumentTypes((insn as MethodInsnNode).desc), true)
Type.getReturnType(insn.desc)
}
else -> {
unreachable(insn)
}
}, insn
)
}
private fun Type.isIntType(): Boolean = when (sort) {
Type.BOOLEAN, Type.BYTE, Type.CHAR, Type.SHORT, Type.INT -> true
else -> false
}
private fun unreachable(insn: AbstractInsnNode): Nothing = error("Unreachable instruction ${insn.insnOpcodeText}")
// IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE
override fun ternaryOperation(
insn: AbstractInsnNode,
arrayref: SpilledVariableFieldTypeValue?,
index: SpilledVariableFieldTypeValue?,
value: SpilledVariableFieldTypeValue?
): SpilledVariableFieldTypeValue? {
when (insn.opcode) {
IASTORE, LASTORE, FASTORE, DASTORE, AASTORE -> {
// nothing to do
}
BASTORE -> {
value?.type = if (arrayref?.type?.descriptor == "[Z") Type.BOOLEAN_TYPE else Type.BYTE_TYPE
}
CASTORE -> {
value?.type = Type.CHAR_TYPE
}
SASTORE -> {
value?.type = Type.SHORT_TYPE
}
else -> unreachable(insn)
}
return null
}
override fun merge(v: SpilledVariableFieldTypeValue?, w: SpilledVariableFieldTypeValue?): SpilledVariableFieldTypeValue? = when {
v?.type?.isIntType() == true && w?.type?.isIntType() == true -> v + w
v != null && v.type == null -> w
w != null && w.type == null -> v
v?.type == w?.type -> v
else -> SpilledVariableFieldTypeValue(null, v?.insn ?: w?.insn)
}
// IRETURN, LRETURN, FRETURN, DRETURN, ARETURN
override fun returnOperation(insn: AbstractInsnNode, value: SpilledVariableFieldTypeValue?, expected: SpilledVariableFieldTypeValue?) {
if (insn.opcode == IRETURN) {
value?.type = expected?.type
}
}
// INEG, LNEG, FNEG, DNEG, IINC, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L,
// F2D, D2I, D2L, D2F, I2B, I2C, I2S, IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE,
// TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN,
// PUTSTATIC, GETFIELD, NEWARRAY, ANEWARRAY, ARRAYLENGTH, ATHROW, CHECKCAST,
// INSTANCEOF, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL
override fun unaryOperation(insn: AbstractInsnNode, value: SpilledVariableFieldTypeValue?): SpilledVariableFieldTypeValue? =
when (insn.opcode) {
INEG, LNEG, FNEG, DNEG, IINC -> SpilledVariableFieldTypeValue(value?.type, insn)
I2L, F2L, D2L -> SpilledVariableFieldTypeValue(Type.LONG_TYPE, insn)
I2F, L2F, D2F -> SpilledVariableFieldTypeValue(Type.FLOAT_TYPE, insn)
L2D, I2D, F2D -> SpilledVariableFieldTypeValue(Type.DOUBLE_TYPE, insn)
L2I, F2I, D2I, ARRAYLENGTH -> SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
I2B -> SpilledVariableFieldTypeValue(Type.BYTE_TYPE, insn)
I2C -> SpilledVariableFieldTypeValue(Type.CHAR_TYPE, insn)
I2S -> SpilledVariableFieldTypeValue(Type.SHORT_TYPE, insn)
IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN,
ATHROW, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL -> null
PUTSTATIC -> {
val expectedType = Type.getType((insn as FieldInsnNode).desc)
if (expectedType.isIntType()) {
value?.type = expectedType
}
null
}
GETFIELD -> SpilledVariableFieldTypeValue(Type.getType((insn as FieldInsnNode).desc), insn)
NEWARRAY -> when ((insn as IntInsnNode).operand) {
T_BOOLEAN -> SpilledVariableFieldTypeValue(Type.getType("[Z"), insn)
T_CHAR -> SpilledVariableFieldTypeValue(Type.getType("[C"), insn)
T_BYTE -> SpilledVariableFieldTypeValue(Type.getType("[B"), insn)
T_SHORT -> SpilledVariableFieldTypeValue(Type.getType("[S"), insn)
T_INT -> SpilledVariableFieldTypeValue(Type.getType("[I"), insn)
T_FLOAT -> SpilledVariableFieldTypeValue(Type.getType("[F"), insn)
T_DOUBLE -> SpilledVariableFieldTypeValue(Type.getType("[D"), insn)
T_LONG -> SpilledVariableFieldTypeValue(Type.getType("[J"), insn)
else -> unreachable(insn)
}
ANEWARRAY -> SpilledVariableFieldTypeValue(Type.getType("[${Type.getObjectType((insn as TypeInsnNode).desc)}"), insn)
CHECKCAST -> SpilledVariableFieldTypeValue(Type.getObjectType((insn as TypeInsnNode).desc), insn)
INSTANCEOF -> SpilledVariableFieldTypeValue(Type.BOOLEAN_TYPE, insn)
else -> unreachable(insn)
}
// IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IADD,
// LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV,
// LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, ISHL, LSHL, ISHR, LSHR, IUSHR,
// LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, LCMP, FCMPL, FCMPG, DCMPL,
// DCMPG, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
// IF_ACMPEQ, IF_ACMPNE, PUTFIELD
override fun binaryOperation(
insn: AbstractInsnNode,
v: SpilledVariableFieldTypeValue?,
w: SpilledVariableFieldTypeValue?
): SpilledVariableFieldTypeValue? =
when (insn.opcode) {
IALOAD, IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IAND, IOR, IXOR, LCMP, FCMPL, FCMPG, DCMPL,
DCMPG -> SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
LALOAD, LADD, LSUB, LMUL, LDIV, LREM, LSHL, LSHR, LUSHR, LAND, LOR, LXOR -> SpilledVariableFieldTypeValue(Type.LONG_TYPE, insn)
FALOAD, FADD, FSUB, FMUL, FDIV, FREM -> SpilledVariableFieldTypeValue(Type.FLOAT_TYPE, insn)
DALOAD, DADD, DSUB, DMUL, DDIV, DREM -> SpilledVariableFieldTypeValue(Type.DOUBLE_TYPE, insn)
AALOAD -> SpilledVariableFieldTypeValue(AsmTypes.OBJECT_TYPE, insn)
BALOAD -> SpilledVariableFieldTypeValue(if (v?.type?.descriptor == "[Z") Type.BOOLEAN_TYPE else Type.BYTE_TYPE, insn)
CALOAD -> SpilledVariableFieldTypeValue(Type.CHAR_TYPE, insn)
SALOAD -> SpilledVariableFieldTypeValue(Type.SHORT_TYPE, insn)
IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE -> null
PUTFIELD -> {
val expectedType = Type.getType((insn as FieldInsnNode).desc)
if (expectedType.isIntType()) {
w?.type = expectedType
}
null
}
else -> unreachable(insn)
}
// ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE,
// ASTORE, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP
override fun copyOperation(insn: AbstractInsnNode, value: SpilledVariableFieldTypeValue?): SpilledVariableFieldTypeValue? =
when (insn.opcode) {
// If same ICONST is stored into several slots, thay can have different types
// For example,
// val b: Byte = 1
// val i: Int = b.toInt()
// In this case, `b` and `i` have the same source, but different types.
// The example also shows, that the types should be `I`.
ISTORE -> SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
// Sometimes we cannot get the type from the usage only
// For example,
// val c = '1'
// if (c == '2) ...
// In this case, update the type using information from LVT
ILOAD -> {
methodNode.localVariables.find { local ->
local.index == (insn as VarInsnNode).`var` &&
methodNode.instructions.indexOf(local.start) < methodNode.instructions.indexOf(insn) &&
methodNode.instructions.indexOf(insn) < methodNode.instructions.indexOf(local.end)
}?.let { local ->
value?.type = Type.getType(local.desc)
}
value
}
else -> value
}
// ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4,
// ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0,
// DCONST_1, BIPUSH, SIPUSH, LDC, JSR, GETSTATIC, NEW
override fun newOperation(insn: AbstractInsnNode): SpilledVariableFieldTypeValue? = when (insn.opcode) {
ACONST_NULL -> SpilledVariableFieldTypeValue(NULL_TYPE, insn)
ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5 -> SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
LCONST_0, LCONST_1 -> SpilledVariableFieldTypeValue(Type.LONG_TYPE, insn)
FCONST_0, FCONST_1, FCONST_2 -> SpilledVariableFieldTypeValue(Type.FLOAT_TYPE, insn)
DCONST_0, DCONST_1 -> SpilledVariableFieldTypeValue(Type.DOUBLE_TYPE, insn)
BIPUSH -> SpilledVariableFieldTypeValue(Type.BYTE_TYPE, insn)
SIPUSH -> SpilledVariableFieldTypeValue(Type.SHORT_TYPE, insn)
LDC -> when (val cst = (insn as LdcInsnNode).cst) {
is Int -> SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
is Long -> SpilledVariableFieldTypeValue(Type.LONG_TYPE, insn)
is Float -> SpilledVariableFieldTypeValue(Type.FLOAT_TYPE, insn)
is Double -> SpilledVariableFieldTypeValue(Type.DOUBLE_TYPE, insn)
is String -> SpilledVariableFieldTypeValue(AsmTypes.JAVA_STRING_TYPE, insn)
is Type -> SpilledVariableFieldTypeValue(AsmTypes.JAVA_CLASS_TYPE, insn)
else -> SpilledVariableFieldTypeValue(AsmTypes.OBJECT_TYPE, insn)
}
JSR -> SpilledVariableFieldTypeValue(Type.VOID_TYPE, insn)
GETSTATIC -> SpilledVariableFieldTypeValue(Type.getType((insn as FieldInsnNode).desc), insn)
NEW -> SpilledVariableFieldTypeValue(Type.getObjectType((insn as TypeInsnNode).desc), insn)
else -> unreachable(insn)
}
}
internal fun performSpilledVariableFieldTypesAnalysis(
methodNode: MethodNode,
thisName: String
): Array<out Frame<SpilledVariableFieldTypeValue>?> =
MethodAnalyzer(thisName, methodNode, SpilledVariableFieldTypesInterpreter(methodNode)).analyze()
\ No newline at end of file
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.coroutines
import org.jetbrains.kotlin.codegen.optimization.common.*
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
import java.util.*
// BasicValue interpreter from ASM does not distinct 'int' types from other int-like types like 'byte' or 'boolean',
// neither do HotSpot and JVM spec.
// But it seems like Dalvik does not follow it, and spilling boolean value into an 'int' field fails with VerifyError on Android 4,
// so this function calculates refined frames' markup.
// Note that type of some values is only possible to determine by their usages (e.g. ICONST_1, BALOAD both may push boolean or byte on stack)
internal fun performRefinedTypeAnalysis(methodNode: MethodNode, thisName: String): Array<out Frame<out BasicValue>?> {
val insnList = methodNode.instructions
val basicFrames = MethodTransformer.analyze(thisName, methodNode, OptimizationBasicInterpreter())
val sourceValueFrames = MethodTransformer.analyze(thisName, methodNode, MySourceInterpreter())
val expectedTypeAndSourcesByInsnIndex: Array<Pair<Type, List<SourceValue>>?> = arrayOfNulls(insnList.size())
fun AbstractInsnNode.index() = insnList.indexOf(this)
fun saveExpectedType(value: SourceValue?, expectedType: Type) {
if (value == null) return
if (expectedType.sort !in REFINED_INT_SORTS) return
for (insn in value.insns) {
// If source is something like ICONST_0, ignore it
if (!insn.isIntLoad()) continue
val index = insnList.indexOf(insn)
checkUpdatedExpectedType(expectedTypeAndSourcesByInsnIndex[index]?.first, expectedType)
expectedTypeAndSourcesByInsnIndex[index] =
Pair(expectedType,
expectedTypeAndSourcesByInsnIndex[index]?.second.orEmpty() + value)
}
}
fun saveExpectedTypeForArrayStore(insn: AbstractInsnNode, sourceValueFrame: Frame<SourceValue>) {
val arrayStoreType =
when (insn.opcode) {
Opcodes.BASTORE -> Type.BYTE_TYPE
Opcodes.CASTORE -> Type.CHAR_TYPE
Opcodes.SASTORE -> Type.SHORT_TYPE
else -> return
}
val insnIndex = insnList.indexOf(insn)
val arrayArg = basicFrames[insnIndex].peek(2)
// may be different from 'arrayStoreType' in case of boolean arrays (BASTORE opcode is also used for them)
val expectedType =
if (arrayArg?.type?.sort == Type.ARRAY)
arrayArg.type.elementType
else
arrayStoreType
saveExpectedType(sourceValueFrame.top(), expectedType)
}
fun saveExpectedTypeForFieldOrMethod(insn: AbstractInsnNode, sourceValueFrame: Frame<SourceValue>) {
when (insn.opcode) {
Opcodes.PUTFIELD, Opcodes.PUTSTATIC ->
saveExpectedType(sourceValueFrame.top(), Type.getType((insn as FieldInsnNode).desc))
Opcodes.INVOKESTATIC, Opcodes.INVOKEVIRTUAL, Opcodes.INVOKEINTERFACE, Opcodes.INVOKESPECIAL -> {
val argumentTypes = Type.getArgumentTypes((insn as MethodInsnNode).desc)
argumentTypes.withIndex().forEach {
val (argIndex, type) = it
saveExpectedType(sourceValueFrame.peek(argumentTypes.size - argIndex - 1), type)
}
}
}
}
fun saveExpectedTypeForVarStore(insn: AbstractInsnNode, sourceValueFrame: Frame<SourceValue>) {
if (insn.isIntStore()) {
val varIndex = (insn as VarInsnNode).`var`
// Considering next insn is important because variable initializer is emitted just before
// the beginning of variable
val nextInsn = InsnSequence(insn.next, insnList.last).firstOrNull(AbstractInsnNode::isMeaningful)
val variableNode =
methodNode.findContainingVariableFromTable(insn, varIndex)
?: methodNode.findContainingVariableFromTable(nextInsn ?: return, varIndex)
?: return
saveExpectedType(sourceValueFrame.top(), Type.getType(variableNode.desc))
}
}
for ((insnIndex, insn) in insnList.toArray().withIndex()) {
assert(insn.opcode != Opcodes.IRETURN) {
"Coroutine body must not contain IRETURN instructions because 'doResume' is always void"
}
val sourceValueFrame = sourceValueFrames[insnIndex] ?: continue
saveExpectedTypeForArrayStore(insn, sourceValueFrame)
saveExpectedTypeForFieldOrMethod(insn, sourceValueFrame)
saveExpectedTypeForVarStore(insn, sourceValueFrame)
}
val refinedVarFrames = analyze(methodNode, object : BackwardAnalysisInterpreter<VarExpectedTypeFrame> {
override fun newFrame(maxLocals: Int): VarExpectedTypeFrame = VarExpectedTypeFrame(maxLocals)
override fun def(frame: VarExpectedTypeFrame, insn: AbstractInsnNode) {
if (insn.isIntStore()) {
frame.expectedTypeByVarIndex[(insn as VarInsnNode).`var`] = null
}
}
override fun use(frame: VarExpectedTypeFrame, insn: AbstractInsnNode) {
val (expectedType, sources) = expectedTypeAndSourcesByInsnIndex[insn.index()] ?: return
sources.flatMap(SourceValue::insns).forEach { insnNode ->
if (insnNode.isIntLoad()) {
frame.updateExpectedType((insnNode as VarInsnNode).`var`, expectedType)
}
}
}
})
return Array(basicFrames.size) {
insnIndex ->
val current = Frame(basicFrames[insnIndex] ?: return@Array null)
refinedVarFrames[insnIndex].expectedTypeByVarIndex.withIndex().filter { it.value != null }.forEach {
assert(current.getLocal(it.index)?.type?.sort in ALL_INT_SORTS) {
"int type expected, but ${current.getLocal(it.index)?.type} was found in basic frames"
}
current.setLocal(it.index, StrictBasicValue(it.value))
}
current
}
}
private fun AbstractInsnNode.isIntLoad() = opcode == Opcodes.ILOAD
private fun AbstractInsnNode.isIntStore() = opcode == Opcodes.ISTORE
private fun checkUpdatedExpectedType(was: Type?, new: Type) {
assert(was == null || was == new) {
"Conflicting expected types: $was/$new"
}
}
private class MySourceInterpreter : SourceInterpreter(Opcodes.API_VERSION) {
override fun copyOperation(insn: AbstractInsnNode, value: SourceValue) =
when {
insn.isStoreOperation() || insn.isLoadOperation() -> SourceValue(value.size, insn)
// For DUP* instructions return the same value (effectively ignore DUP's)
else -> value
}
}
private val REFINED_INT_SORTS = setOf(Type.BOOLEAN, Type.CHAR, Type.BYTE, Type.SHORT)
private val ALL_INT_SORTS = REFINED_INT_SORTS + Type.INT
private fun MethodNode.findContainingVariableFromTable(insn: AbstractInsnNode, varIndex: Int): LocalVariableNode? {
val insnIndex = instructions.indexOf(insn)
return localVariables.firstOrNull {
it.index == varIndex && it.rangeContainsInsn(insnIndex, instructions)
}
}
private fun LocalVariableNode.rangeContainsInsn(insnIndex: Int, insnList: InsnList) =
insnList.indexOf(start) < insnIndex && insnIndex < insnList.indexOf(end)
private class VarExpectedTypeFrame(maxLocals: Int) : VarFrame<VarExpectedTypeFrame> {
val expectedTypeByVarIndex = arrayOfNulls<Type>(maxLocals)
override fun mergeFrom(other: VarExpectedTypeFrame) {
assert(expectedTypeByVarIndex.size == other.expectedTypeByVarIndex.size) {
"Other VarExpectedTypeFrame has different size: ${expectedTypeByVarIndex.size} / ${other.expectedTypeByVarIndex.size}"
}
for ((varIndex, type) in other.expectedTypeByVarIndex.withIndex()) {
updateExpectedType(varIndex, type ?: continue)
}
}
fun updateExpectedType(varIndex: Int, new: Type) {
val was = expectedTypeByVarIndex[varIndex]
// Widening to int is always allowed
if (new == Type.INT_TYPE) return
checkUpdatedExpectedType(was, new)
expectedTypeByVarIndex[varIndex] = new
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || other::class.java != this::class.java) return false
other as VarExpectedTypeFrame
if (!Arrays.equals(expectedTypeByVarIndex, other.expectedTypeByVarIndex)) return false
return true
}
override fun hashCode(): Int {
return Arrays.hashCode(expectedTypeByVarIndex)
}
}
......@@ -8329,11 +8329,6 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
}
@TestMetadata("kt38925.kt")
public void testKt38925_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt", "kotlin.coroutines");
}
@TestMetadata("nullSpilling.kt")
public void testNullSpilling_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
// WITH_COROUTINES
// COMMON_COROUTINES_TEST
import helpers.*
import COROUTINES_PACKAGE.*
import COROUTINES_PACKAGE.intrinsics.*
fun foo() {
bar {
val p = false
baz(p, "".ifEmpty { "OK" })
}
}
var res = "FAIL"
fun bar(f: suspend () -> Unit) {
f.startCoroutine(EmptyContinuation)
}
fun baz(p: Boolean, s: String?) {
res = s!!
}
fun box(): String {
foo()
return res
}
// FILE: test.kt
// COMMON_COROUTINES_TEST
// WITH_RUNTIME
// WITH_COROUTINES
// WITH_REFLECT
import COROUTINES_PACKAGE.*
import helpers.*
import kotlin.reflect.KProperty
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "OK"
}
}
interface SuspendRunnable {
suspend fun run(): String
}
suspend inline fun test(crossinline c: suspend (String) -> String): String {
val sr = object : SuspendRunnable {
val ok by Delegate()
override suspend fun run(): String {
return c(ok)
}
}
return sr.run()
}
// FILE: box.kt
// COMMON_COROUTINES_TEST
import COROUTINES_PACKAGE.*
import helpers.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
suspend fun dummy() {}
fun box(): String {
var res: String = "FAIL"
builder {
res = test { it }
}
return res
}
\ No newline at end of file
......@@ -9539,16 +9539,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
}
@TestMetadata("kt38925.kt")
public void testKt38925_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("kt38925.kt")
public void testKt38925_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt", "kotlin.coroutines");
}
@TestMetadata("nullSpilling.kt")
public void testNullSpilling_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines.experimental");
......@@ -3798,16 +3798,6 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
}
@TestMetadata("delegatedProperties.kt")
public void testDelegatedProperties_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("delegatedProperties.kt")
public void testDelegatedProperties_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
}
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
public void testDoubleRegenerationWithNonSuspendingLambda_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines.experimental");
......
......@@ -3798,16 +3798,6 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
}
@TestMetadata("delegatedProperties.kt")
public void testDelegatedProperties_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("delegatedProperties.kt")
public void testDelegatedProperties_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
}
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
public void testDoubleRegenerationWithNonSuspendingLambda_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines.experimental");
......
......@@ -9539,16 +9539,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
}
@TestMetadata("kt38925.kt")
public void testKt38925_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt", "kotlin.coroutines.experimental");
}
@TestMetadata("kt38925.kt")
public void testKt38925_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt", "kotlin.coroutines");
}
@TestMetadata("nullSpilling.kt")
public void testNullSpilling_1_2() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines.experimental");
......@@ -8329,11 +8329,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
}
@TestMetadata("kt38925.kt")
public void testKt38925_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt", "kotlin.coroutines");
}
@TestMetadata("nullSpilling.kt")
public void testNullSpilling_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
......@@ -3788,11 +3788,6 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
}
@TestMetadata("delegatedProperties.kt")
public void testDelegatedProperties_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
}
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
......
......@@ -3788,11 +3788,6 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
}
@TestMetadata("delegatedProperties.kt")
public void testDelegatedProperties_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
}
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
......
......@@ -7054,11 +7054,6 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
}
@TestMetadata("kt38925.kt")
public void testKt38925_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt", "kotlin.coroutines");
}
@TestMetadata("nullSpilling.kt")
public void testNullSpilling_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
......@@ -3388,11 +3388,6 @@ public class IrJsCodegenInlineES6TestGenerated extends AbstractIrJsCodegenInline
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
}
@TestMetadata("delegatedProperties.kt")
public void testDelegatedProperties_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
}
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
......
......@@ -7064,11 +7064,6 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
}
@TestMetadata("kt38925.kt")
public void testKt38925_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt", "kotlin.coroutines");
}
@TestMetadata("nullSpilling.kt")
public void testNullSpilling_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
......@@ -3388,11 +3388,6 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
}
@TestMetadata("delegatedProperties.kt")
public void testDelegatedProperties_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
}
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
......
......@@ -7064,11 +7064,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
}
@TestMetadata("kt38925.kt")
public void testKt38925_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt", "kotlin.coroutines");
}
@TestMetadata("nullSpilling.kt")
public void testNullSpilling_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
......@@ -3388,11 +3388,6 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
}
@TestMetadata("delegatedProperties.kt")
public void testDelegatedProperties_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
}
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册