From 5567033b3343fa67e51565b79df3e23de5d1be68 Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Mon, 8 Jun 2020 16:01:33 +0200 Subject: [PATCH] Revert "Revert "Completely rewrite reifiedIntTypeAnalysis, making it more streamline"" This reverts commit 822c14814bbb0042e956bbc76bda2179b34fa2ff. --- .../CoroutineTransformerMethodVisitor.kt | 8 +- ...ndantLocalsEliminationMethodTransformer.kt | 1 - .../SpilledVariableFieldTypesAnalysis.kt | 306 ++++++++++++++++++ .../coroutines/refinedIntTypesAnalysis.kt | 221 ------------- .../ir/FirBlackBoxCodegenTestGenerated.java | 5 + .../box/coroutines/varSpilling/kt38925.kt | 29 ++ .../boxInline/suspend/delegatedProperties.kt | 49 +++ .../codegen/BlackBoxCodegenTestGenerated.java | 10 + .../BlackBoxInlineCodegenTestGenerated.java | 10 + ...otlinAgainstInlineKotlinTestGenerated.java | 10 + .../LightAnalysisModeTestGenerated.java | 10 + .../ir/IrBlackBoxCodegenTestGenerated.java | 5 + .../IrBlackBoxInlineCodegenTestGenerated.java | 5 + ...otlinAgainstInlineKotlinTestGenerated.java | 5 + .../IrJsCodegenBoxES6TestGenerated.java | 5 + .../IrJsCodegenInlineES6TestGenerated.java | 5 + .../IrJsCodegenBoxTestGenerated.java | 5 + .../IrJsCodegenInlineTestGenerated.java | 5 + .../semantics/JsCodegenBoxTestGenerated.java | 5 + .../JsCodegenInlineTestGenerated.java | 5 + 20 files changed, 478 insertions(+), 226 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SpilledVariableFieldTypesAnalysis.kt delete mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/refinedIntTypesAnalysis.kt create mode 100644 compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt create mode 100644 compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt index 43e0cd30cfe..ff9d05e8428 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt @@ -593,7 +593,7 @@ class CoroutineTransformerMethodVisitor( private fun spillVariables(suspensionPoints: List, methodNode: MethodNode): List> { val instructions = methodNode.instructions - val frames = performRefinedTypeAnalysis(methodNode, containingClassInternalName) + val frames = performSpilledVariableFieldTypesAnalysis(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 != StrictBasicValue.UNINITIALIZED_VALUE && livenessFrame.isAlive(index)) + (value.type != null && livenessFrame.isAlive(index)) } for ((index, basicValue) in variablesToSpill) { - if (basicValue === StrictBasicValue.NULL_VALUE) { + if (basicValue.type == NULL_TYPE) { 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 diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/RedundantLocalsEliminationMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/RedundantLocalsEliminationMethodTransformer.kt index 3e6aa85002b..dbac2f9132e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/RedundantLocalsEliminationMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/RedundantLocalsEliminationMethodTransformer.kt @@ -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.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() diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SpilledVariableFieldTypesAnalysis.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SpilledVariableFieldTypesAnalysis.kt new file mode 100644 index 00000000000..94ab962bd94 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SpilledVariableFieldTypesAnalysis.kt @@ -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(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(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 + ): SpilledVariableFieldTypeValue? { + fun updateTypes(argTypes: Array, 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?> = + MethodAnalyzer(thisName, methodNode, SpilledVariableFieldTypesInterpreter(methodNode)).analyze() \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/refinedIntTypesAnalysis.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/refinedIntTypesAnalysis.kt deleted file mode 100644 index 4c21f80a686..00000000000 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/refinedIntTypesAnalysis.kt +++ /dev/null @@ -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?> { - val insnList = methodNode.instructions - val basicFrames = MethodTransformer.analyze(thisName, methodNode, OptimizationBasicInterpreter()) - val sourceValueFrames = MethodTransformer.analyze(thisName, methodNode, MySourceInterpreter()) - - val expectedTypeAndSourcesByInsnIndex: Array>?> = 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) { - 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) { - 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) { - 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 { - 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 { - val expectedTypeByVarIndex = arrayOfNulls(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) - } -} diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 1c7fb8e817a..0060f905555 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -8338,6 +8338,11 @@ 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"); diff --git a/compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt b/compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt new file mode 100644 index 00000000000..6c5eb45c557 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/varSpilling/kt38925.kt @@ -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 +} diff --git a/compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt b/compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt new file mode 100644 index 00000000000..2de5ca1129c --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt @@ -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 +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index fc83a43b3a3..b07a343194d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -9553,6 +9553,16 @@ 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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index fe5371bb07c..ea48790479f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -3808,6 +3808,16 @@ 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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index ca5bec0ce09..f87c480e6d6 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3808,6 +3808,16 @@ 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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 85feffb2300..82a319b014a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -9553,6 +9553,16 @@ 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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 9bb0893599a..5254e2cfa76 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -8338,6 +8338,11 @@ 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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index 40a0ece26f1..38fec729dc8 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -3798,6 +3798,11 @@ 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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java index 541c9f87e43..536225deb89 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3798,6 +3798,11 @@ 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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 586191fbd50..5bda23c5f2f 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -7063,6 +7063,11 @@ 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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java index bc6e566f9d9..9549f29d35f 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java @@ -3388,6 +3388,11 @@ 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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 2d565099ccc..ed5930d735d 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -7073,6 +7073,11 @@ 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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java index c9d33c1debb..d998c39fd6d 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java @@ -3388,6 +3388,11 @@ 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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index d9487b4fa4f..5ff55dfcbb2 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -7073,6 +7073,11 @@ 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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java index b864ea4d1c5..539a2c51380 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java @@ -3388,6 +3388,11 @@ 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");