Revert "Revert "Completely rewrite reifiedIntTypeAnalysis, making it more streamline""
This reverts commit 822c14814b.
This commit is contained in:
+4
-4
@@ -593,7 +593,7 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
|
|
||||||
private fun spillVariables(suspensionPoints: List<SuspensionPoint>, methodNode: MethodNode): List<List<SpilledVariableDescriptor>> {
|
private fun spillVariables(suspensionPoints: List<SuspensionPoint>, methodNode: MethodNode): List<List<SpilledVariableDescriptor>> {
|
||||||
val instructions = methodNode.instructions
|
val instructions = methodNode.instructions
|
||||||
val frames = performRefinedTypeAnalysis(methodNode, containingClassInternalName)
|
val frames = performSpilledVariableFieldTypesAnalysis(methodNode, containingClassInternalName)
|
||||||
fun AbstractInsnNode.index() = instructions.indexOf(this)
|
fun AbstractInsnNode.index() = instructions.indexOf(this)
|
||||||
|
|
||||||
// We postpone these actions because they change instruction indices that we use when obtaining frames
|
// 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)) }
|
.map { Pair(it, frame.getLocal(it)) }
|
||||||
.filter { (index, value) ->
|
.filter { (index, value) ->
|
||||||
(index == 0 && needDispatchReceiver && isForNamedFunction) ||
|
(index == 0 && needDispatchReceiver && isForNamedFunction) ||
|
||||||
(value != StrictBasicValue.UNINITIALIZED_VALUE && livenessFrame.isAlive(index))
|
(value.type != null && livenessFrame.isAlive(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((index, basicValue) in variablesToSpill) {
|
for ((index, basicValue) in variablesToSpill) {
|
||||||
if (basicValue === StrictBasicValue.NULL_VALUE) {
|
if (basicValue.type == NULL_TYPE) {
|
||||||
postponedActions.add {
|
postponedActions.add {
|
||||||
with(instructions) {
|
with(instructions) {
|
||||||
insert(suspension.tryCatchBlockEndLabelAfterSuspensionCall, withInstructionAdapter {
|
insert(suspension.tryCatchBlockEndLabelAfterSuspensionCall, withInstructionAdapter {
|
||||||
@@ -657,7 +657,7 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val type = basicValue.type
|
val type = basicValue.type!!
|
||||||
val normalizedType = type.normalize()
|
val normalizedType = type.normalize()
|
||||||
|
|
||||||
val indexBySort = varsCountByType[normalizedType]?.plus(1) ?: 0
|
val indexBySort = varsCountByType[normalizedType]?.plus(1) ?: 0
|
||||||
|
|||||||
-1
@@ -18,7 +18,6 @@ import org.jetbrains.org.objectweb.asm.Type
|
|||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicInterpreter
|
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.BasicValue
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
|
||||||
|
|
||||||
private class PossibleSpilledValue(val source: AbstractInsnNode, type: Type?) : BasicValue(type) {
|
private class PossibleSpilledValue(val source: AbstractInsnNode, type: Type?) : BasicValue(type) {
|
||||||
val usages = mutableSetOf<AbstractInsnNode>()
|
val usages = mutableSetOf<AbstractInsnNode>()
|
||||||
|
|||||||
+306
@@ -0,0 +1,306 @@
|
|||||||
|
/*
|
||||||
|
* 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()
|
||||||
-221
@@ -1,221 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Generated
+5
@@ -8338,6 +8338,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("nullSpilling.kt")
|
||||||
public void testNullSpilling_1_3() throws Exception {
|
public void testNullSpilling_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// 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
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
// 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
|
||||||
|
}
|
||||||
+10
@@ -9553,6 +9553,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("nullSpilling.kt")
|
||||||
public void testNullSpilling_1_2() throws Exception {
|
public void testNullSpilling_1_2() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines.experimental");
|
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines.experimental");
|
||||||
|
|||||||
+10
@@ -3808,6 +3808,16 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
|
||||||
public void testDoubleRegenerationWithNonSuspendingLambda_1_2() throws Exception {
|
public void testDoubleRegenerationWithNonSuspendingLambda_1_2() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines.experimental");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines.experimental");
|
||||||
|
|||||||
Generated
+10
@@ -3808,6 +3808,16 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
|
||||||
public void testDoubleRegenerationWithNonSuspendingLambda_1_2() throws Exception {
|
public void testDoubleRegenerationWithNonSuspendingLambda_1_2() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines.experimental");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines.experimental");
|
||||||
|
|||||||
+10
@@ -9553,6 +9553,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("nullSpilling.kt")
|
||||||
public void testNullSpilling_1_2() throws Exception {
|
public void testNullSpilling_1_2() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines.experimental");
|
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines.experimental");
|
||||||
|
|||||||
+5
@@ -8338,6 +8338,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("nullSpilling.kt")
|
||||||
public void testNullSpilling_1_3() throws Exception {
|
public void testNullSpilling_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
|
||||||
|
|||||||
+5
@@ -3798,6 +3798,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
|
||||||
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
|
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
|
||||||
|
|||||||
Generated
+5
@@ -3798,6 +3798,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
|
||||||
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
|
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
|
||||||
|
|||||||
Generated
+5
@@ -7063,6 +7063,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("nullSpilling.kt")
|
||||||
public void testNullSpilling_1_3() throws Exception {
|
public void testNullSpilling_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
|
||||||
|
|||||||
Generated
+5
@@ -3388,6 +3388,11 @@ public class IrJsCodegenInlineES6TestGenerated extends AbstractIrJsCodegenInline
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
|
||||||
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
|
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
|
||||||
|
|||||||
Generated
+5
@@ -7073,6 +7073,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("nullSpilling.kt")
|
||||||
public void testNullSpilling_1_3() throws Exception {
|
public void testNullSpilling_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
|
||||||
|
|||||||
Generated
+5
@@ -3388,6 +3388,11 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
|
||||||
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
|
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
|
||||||
|
|||||||
+5
@@ -7073,6 +7073,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/kt19475.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("nullSpilling.kt")
|
||||||
public void testNullSpilling_1_3() throws Exception {
|
public void testNullSpilling_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/varSpilling/nullSpilling.kt", "kotlin.coroutines");
|
||||||
|
|||||||
+5
@@ -3388,6 +3388,11 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest {
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("doubleRegenerationWithNonSuspendingLambda.kt")
|
||||||
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
|
public void testDoubleRegenerationWithNonSuspendingLambda_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/doubleRegenerationWithNonSuspendingLambda.kt", "kotlin.coroutines");
|
||||||
|
|||||||
Reference in New Issue
Block a user