Refine stack frames markup calculation
It fixes VerifyError with coroutines on Dalvik happening because of variables spilling before/after suspension point BasicInterpreter 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 it's necessary to distinct int types for variables spilling #KT-13289 Fixed
This commit is contained in:
+4
-5
@@ -20,13 +20,12 @@ import com.intellij.util.containers.Stack
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.optimization.DeadCodeEliminationMethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.FixStackWithLabelNormalizationMethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.analyzeLiveness
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.insnListOf
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
@@ -191,7 +190,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
private fun spillVariables(suspensionPoints: List<SuspensionPoint>, methodNode: MethodNode) {
|
||||
val instructions = methodNode.instructions
|
||||
val frames = MethodTransformer.analyze(classBuilder.thisName, methodNode, OptimizationBasicInterpreter())
|
||||
val frames = performRefinedTypeAnalysis(methodNode, classBuilder.thisName)
|
||||
fun AbstractInsnNode.index() = instructions.indexOf(this)
|
||||
|
||||
// We postpone these actions because they change instruction indices that we use when obtaining frames
|
||||
@@ -202,11 +201,11 @@ class CoroutineTransformerMethodVisitor(
|
||||
for (suspension in suspensionPoints) {
|
||||
val suspensionCallBegin = suspension.suspensionCallBegin
|
||||
val suspensionCallEnd = suspension.suspensionCallEnd
|
||||
assert(frames[suspensionCallEnd.next.index()].stackSize == (if (suspension.returnType.sort == Type.VOID) 0 else 1)) {
|
||||
assert(frames[suspensionCallEnd.next.index()]?.stackSize == (if (suspension.returnType.sort == Type.VOID) 0 else 1)) {
|
||||
"Stack should be spilled before suspension call"
|
||||
}
|
||||
|
||||
val frame = frames[suspensionCallBegin.index()]
|
||||
val frame = frames[suspensionCallBegin.index()].sure { "Suspension points containing in dead code must be removed" }
|
||||
val localsCount = frame.locals
|
||||
val varsCountByType = mutableMapOf<Type, Int>()
|
||||
|
||||
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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
|
||||
|
||||
value.insns.forEach {
|
||||
val index = insnList.indexOf(it)
|
||||
|
||||
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 {
|
||||
insn ->
|
||||
if (insn.isIntLoad()) {
|
||||
frame.updateExpectedType((insn as VarInsnNode).`var`, expectedType)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
val refinedFrames = 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 == Type.INT_TYPE) {
|
||||
"int type expected, but ${current.getLocal(it.index)?.type} was found in basic frames"
|
||||
}
|
||||
|
||||
current.setLocal(it.index, BasicValue(it.value))
|
||||
}
|
||||
|
||||
current
|
||||
}
|
||||
|
||||
return refinedFrames
|
||||
}
|
||||
|
||||
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() {
|
||||
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 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?.javaClass != javaClass) return false
|
||||
|
||||
other as VarExpectedTypeFrame
|
||||
|
||||
if (!Arrays.equals(expectedTypeByVarIndex, other.expectedTypeByVarIndex)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return Arrays.hashCode(expectedTypeByVarIndex)
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
fun foo() = true
|
||||
|
||||
private var booleanResult = false
|
||||
fun setBooleanRes(x: Boolean) {
|
||||
booleanResult = x
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x = true
|
||||
val y = false
|
||||
suspendHere()
|
||||
setBooleanRes(if (foo()) x else y)
|
||||
}
|
||||
|
||||
if (!booleanResult) return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
private var byteResult: Byte = 0
|
||||
fun setByteRes(x: Byte) {
|
||||
byteResult = x
|
||||
}
|
||||
|
||||
fun foo(): Int = 1
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x: Byte = foo().toByte()
|
||||
suspendHere()
|
||||
setByteRes(x)
|
||||
}
|
||||
|
||||
if (byteResult != 1.toByte()) return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
private var booleanResult = false
|
||||
fun setBooleanRes(x: Boolean) {
|
||||
booleanResult = x
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val a = booleanArrayOf(true)
|
||||
val x = a[0]
|
||||
suspendHere()
|
||||
setBooleanRes(x)
|
||||
}
|
||||
|
||||
if (!booleanResult) return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
private var byteResult: Byte = 0
|
||||
fun setByteRes(x: Byte) {
|
||||
byteResult = x
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val a = byteArrayOf(1)
|
||||
val x = a[0]
|
||||
suspendHere()
|
||||
setByteRes(x)
|
||||
}
|
||||
|
||||
if (byteResult != 1.toByte()) return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
private var booleanResult = false
|
||||
fun setBooleanRes(x: Boolean, ignored: Unit) {
|
||||
booleanResult = x
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
// 'true' value is spilled into variable and saved to field before suspension point
|
||||
// It's important that there is no type info about this variable in local var table,
|
||||
// so we should infer that ICONST_1 is a boolean value from it's usage
|
||||
setBooleanRes(true, suspendHere())
|
||||
}
|
||||
|
||||
if (!booleanResult) return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
private var result: String = ""
|
||||
fun setRes(x: Byte, y: Int) {
|
||||
result = "$x#$y"
|
||||
}
|
||||
|
||||
fun foo(): Int = 1
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x: Byte = 1
|
||||
// No actual cast happens here
|
||||
val y: Int = x.toInt()
|
||||
suspendHere()
|
||||
setRes(x, y)
|
||||
}
|
||||
|
||||
if (result != "1#1") return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
// WITH_RUNTIME
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
@JvmField
|
||||
var booleanResult = booleanArrayOf()
|
||||
@JvmField
|
||||
var charResult = charArrayOf()
|
||||
@JvmField
|
||||
var byteResult = byteArrayOf()
|
||||
@JvmField
|
||||
var shortResult = shortArrayOf()
|
||||
@JvmField
|
||||
var intResult = intArrayOf()
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x = true
|
||||
suspendHere()
|
||||
val a = BooleanArray(1)
|
||||
a[0] = x
|
||||
booleanResult = a
|
||||
}
|
||||
|
||||
if (!booleanResult[0]) return "fail 1"
|
||||
|
||||
builder {
|
||||
val x = '1'
|
||||
suspendHere()
|
||||
val a = CharArray(1)
|
||||
a[0] = x
|
||||
charResult = a
|
||||
}
|
||||
|
||||
if (charResult[0] != '1') return "fail 2"
|
||||
|
||||
builder {
|
||||
val x: Byte = 1
|
||||
suspendHere()
|
||||
val a = ByteArray(1)
|
||||
a[0] = x
|
||||
byteResult = a
|
||||
}
|
||||
|
||||
if (byteResult[0] != 1.toByte()) return "fail 3"
|
||||
|
||||
builder {
|
||||
val x: Short = 1
|
||||
suspendHere()
|
||||
val a = ShortArray(1)
|
||||
a[0] = x
|
||||
shortResult = a
|
||||
}
|
||||
|
||||
if (shortResult[0] != 1.toShort()) return "fail 4"
|
||||
|
||||
builder {
|
||||
val x: Int = 1
|
||||
suspendHere()
|
||||
val a = IntArray(1)
|
||||
a[0] = x
|
||||
intResult = a
|
||||
}
|
||||
|
||||
if (intResult[0] != 1) return "fail 5"
|
||||
return "OK"
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
private var booleanResult = false
|
||||
fun setBooleanRes(x: Boolean) {
|
||||
booleanResult = x
|
||||
}
|
||||
|
||||
private var charResult: Char = '0'
|
||||
fun setCharRes(x: Char) {
|
||||
charResult = x
|
||||
}
|
||||
|
||||
private var byteResult: Byte = 0
|
||||
fun setByteRes(x: Byte) {
|
||||
byteResult = x
|
||||
}
|
||||
|
||||
private var shortResult: Short = 0
|
||||
fun setShortRes(x: Short) {
|
||||
shortResult = x
|
||||
}
|
||||
|
||||
private var intResult: Int = 0
|
||||
fun setIntRes(x: Int) {
|
||||
intResult = x
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x = true
|
||||
suspendHere()
|
||||
setBooleanRes(x)
|
||||
}
|
||||
|
||||
if (!booleanResult) return "fail 1"
|
||||
|
||||
builder {
|
||||
val x = '1'
|
||||
suspendHere()
|
||||
setCharRes(x)
|
||||
}
|
||||
|
||||
if (charResult != '1') return "fail 2"
|
||||
|
||||
builder {
|
||||
val x: Byte = 1
|
||||
suspendHere()
|
||||
setByteRes(x)
|
||||
}
|
||||
|
||||
if (byteResult != 1.toByte()) return "fail 3"
|
||||
|
||||
builder {
|
||||
val x: Short = 1
|
||||
suspendHere()
|
||||
setShortRes(x)
|
||||
}
|
||||
|
||||
if (shortResult != 1.toShort()) return "fail 4"
|
||||
|
||||
builder {
|
||||
val x: Int = 1
|
||||
suspendHere()
|
||||
setIntRes(x)
|
||||
}
|
||||
|
||||
if (intResult != 1) return "fail 5"
|
||||
return "OK"
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
// WITH_RUNTIME
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
@JvmField
|
||||
var booleanResult = false
|
||||
@JvmField
|
||||
var charResult: Char = '0'
|
||||
@JvmField
|
||||
var byteResult: Byte = 0
|
||||
@JvmField
|
||||
var shortResult: Short = 0
|
||||
@JvmField
|
||||
var intResult: Int = 0
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x = true
|
||||
suspendHere()
|
||||
booleanResult = x
|
||||
}
|
||||
|
||||
if (!booleanResult) return "fail 1"
|
||||
|
||||
builder {
|
||||
val x = '1'
|
||||
suspendHere()
|
||||
charResult = x
|
||||
}
|
||||
|
||||
if (charResult != '1') return "fail 2"
|
||||
|
||||
builder {
|
||||
val x: Byte = 1
|
||||
suspendHere()
|
||||
byteResult = x
|
||||
}
|
||||
|
||||
if (byteResult != 1.toByte()) return "fail 3"
|
||||
|
||||
builder {
|
||||
val x: Short = 1
|
||||
suspendHere()
|
||||
shortResult = x
|
||||
}
|
||||
|
||||
if (shortResult != 1.toShort()) return "fail 4"
|
||||
|
||||
builder {
|
||||
val x: Int = 1
|
||||
suspendHere()
|
||||
intResult = x
|
||||
}
|
||||
|
||||
if (intResult != 1) return "fail 5"
|
||||
return "OK"
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x = true
|
||||
suspendHere()
|
||||
val y: Boolean = x
|
||||
if (!y) throw IllegalStateException("fail 1")
|
||||
}
|
||||
|
||||
builder {
|
||||
val x = '1'
|
||||
suspendHere()
|
||||
|
||||
val y: Char = x
|
||||
if (y != '1') throw IllegalStateException("fail 2")
|
||||
}
|
||||
|
||||
builder {
|
||||
val x: Byte = 1
|
||||
suspendHere()
|
||||
|
||||
val y: Byte = x
|
||||
if (y != 1.toByte()) throw IllegalStateException("fail 3")
|
||||
}
|
||||
|
||||
builder {
|
||||
val x: Short = 1
|
||||
|
||||
suspendHere()
|
||||
|
||||
val y: Short = x
|
||||
if (y != 1.toShort()) throw IllegalStateException("fail 4")
|
||||
}
|
||||
|
||||
builder {
|
||||
val x: Int = 1
|
||||
suspendHere()
|
||||
|
||||
val y: Int = x
|
||||
if (y != 1) throw IllegalStateException("fail 5")
|
||||
}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
fun foo() = true
|
||||
|
||||
private var booleanResult = false
|
||||
fun setBooleanRes(x: Boolean) {
|
||||
booleanResult = x
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x = true
|
||||
val y = false
|
||||
suspendHere()
|
||||
setBooleanRes(if (foo()) x else y)
|
||||
}
|
||||
|
||||
if (!booleanResult) return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 1 PUTFIELD .*\.Z\$0 : Z
|
||||
// 1 PUTFIELD .*\.Z\$1 : Z
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
private var byteResult: Byte = 0
|
||||
fun setByteRes(x: Byte) {
|
||||
byteResult = x
|
||||
}
|
||||
|
||||
fun foo(): Int = 1
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x: Byte = foo().toByte()
|
||||
suspendHere()
|
||||
setByteRes(x)
|
||||
}
|
||||
|
||||
if (byteResult != 1.toByte()) return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 1 PUTFIELD .*\.B\$0 : B
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
private var booleanResult = false
|
||||
fun setBooleanRes(x: Boolean) {
|
||||
booleanResult = x
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val a = booleanArrayOf(true)
|
||||
val x = a[0]
|
||||
suspendHere()
|
||||
setBooleanRes(x)
|
||||
}
|
||||
|
||||
if (!booleanResult) return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 1 PUTFIELD .*\.Z\$0 : Z
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
private var byteResult: Byte = 0
|
||||
fun setByteRes(x: Byte) {
|
||||
byteResult = x
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val a = byteArrayOf(1)
|
||||
val x = a[0]
|
||||
suspendHere()
|
||||
setByteRes(x)
|
||||
}
|
||||
|
||||
if (byteResult != 1.toByte()) return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 1 PUTFIELD .*\.B\$0 : B
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
private var booleanResult = false
|
||||
fun setBooleanRes(x: Boolean, ignored: Unit) {
|
||||
booleanResult = x
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
// 'true' value is spilled into variable and saved to field before suspension point
|
||||
// It's important that there is no type info about this variable in local var table,
|
||||
// so we should infer that ICONST_1 is a boolean value from it's usage
|
||||
setBooleanRes(true, suspendHere())
|
||||
}
|
||||
|
||||
if (!booleanResult) return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 1 PUTFIELD .*\.Z\$0 : Z
|
||||
Vendored
+33
@@ -0,0 +1,33 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
private var result: String = ""
|
||||
fun setRes(x: Byte, y: Int) {
|
||||
result = "$x#$y"
|
||||
}
|
||||
|
||||
fun foo(): Int = 1
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x: Byte = 1
|
||||
// No actual cast happens here
|
||||
val y: Int = x.toInt()
|
||||
suspendHere()
|
||||
setRes(x, y)
|
||||
}
|
||||
|
||||
if (result != "1#1") return "fail 1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 1 PUTFIELD .*\.B\$0 : B
|
||||
// 1 PUTFIELD .*\.I\$0 : I
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
// WITH_RUNTIME
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
@JvmField
|
||||
var booleanResult = booleanArrayOf()
|
||||
@JvmField
|
||||
var charResult = charArrayOf()
|
||||
@JvmField
|
||||
var byteResult = byteArrayOf()
|
||||
@JvmField
|
||||
var shortResult = shortArrayOf()
|
||||
@JvmField
|
||||
var intResult = intArrayOf()
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x = true
|
||||
suspendHere()
|
||||
val a = BooleanArray(1)
|
||||
a[0] = x
|
||||
booleanResult = a
|
||||
}
|
||||
|
||||
if (!booleanResult[0]) return "fail 1"
|
||||
|
||||
builder {
|
||||
val x = '1'
|
||||
suspendHere()
|
||||
val a = CharArray(1)
|
||||
a[0] = x
|
||||
charResult = a
|
||||
}
|
||||
|
||||
if (charResult[0] != '1') return "fail 2"
|
||||
|
||||
builder {
|
||||
val x: Byte = 1
|
||||
suspendHere()
|
||||
val a = ByteArray(1)
|
||||
a[0] = x
|
||||
byteResult = a
|
||||
}
|
||||
|
||||
if (byteResult[0] != 1.toByte()) return "fail 3"
|
||||
|
||||
builder {
|
||||
val x: Short = 1
|
||||
suspendHere()
|
||||
val a = ShortArray(1)
|
||||
a[0] = x
|
||||
shortResult = a
|
||||
}
|
||||
|
||||
if (shortResult[0] != 1.toShort()) return "fail 4"
|
||||
|
||||
builder {
|
||||
val x: Int = 1
|
||||
suspendHere()
|
||||
val a = IntArray(1)
|
||||
a[0] = x
|
||||
intResult = a
|
||||
}
|
||||
|
||||
if (intResult[0] != 1) return "fail 5"
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 1 PUTFIELD .*\.B\$0 : B
|
||||
// 1 PUTFIELD .*\.C\$0 : C
|
||||
// 1 PUTFIELD .*\.S\$0 : S
|
||||
// 1 PUTFIELD .*\.Z\$0 : Z
|
||||
// 1 PUTFIELD .*\.I\$0 : I
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
private var booleanResult = false
|
||||
fun setBooleanRes(x: Boolean) {
|
||||
booleanResult = x
|
||||
}
|
||||
|
||||
private var charResult: Char = '0'
|
||||
fun setCharRes(x: Char) {
|
||||
charResult = x
|
||||
}
|
||||
|
||||
private var byteResult: Byte = 0
|
||||
fun setByteRes(x: Byte) {
|
||||
byteResult = x
|
||||
}
|
||||
|
||||
private var shortResult: Short = 0
|
||||
fun setShortRes(x: Short) {
|
||||
shortResult = x
|
||||
}
|
||||
|
||||
private var intResult: Int = 0
|
||||
fun setIntRes(x: Int) {
|
||||
intResult = x
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x = true
|
||||
suspendHere()
|
||||
setBooleanRes(x)
|
||||
}
|
||||
|
||||
if (!booleanResult) return "fail 1"
|
||||
|
||||
builder {
|
||||
val x = '1'
|
||||
suspendHere()
|
||||
setCharRes(x)
|
||||
}
|
||||
|
||||
if (charResult != '1') return "fail 2"
|
||||
|
||||
builder {
|
||||
val x: Byte = 1
|
||||
suspendHere()
|
||||
setByteRes(x)
|
||||
}
|
||||
|
||||
if (byteResult != 1.toByte()) return "fail 3"
|
||||
|
||||
builder {
|
||||
val x: Short = 1
|
||||
suspendHere()
|
||||
setShortRes(x)
|
||||
}
|
||||
|
||||
if (shortResult != 1.toShort()) return "fail 4"
|
||||
|
||||
builder {
|
||||
val x: Int = 1
|
||||
suspendHere()
|
||||
setIntRes(x)
|
||||
}
|
||||
|
||||
if (intResult != 1) return "fail 5"
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 1 PUTFIELD .*\.B\$0 : B
|
||||
// 1 PUTFIELD .*\.C\$0 : C
|
||||
// 1 PUTFIELD .*\.S\$0 : S
|
||||
// 1 PUTFIELD .*\.Z\$0 : Z
|
||||
// 1 PUTFIELD .*\.I\$0 : I
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
// WITH_RUNTIME
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
@JvmField
|
||||
var booleanResult = false
|
||||
@JvmField
|
||||
var charResult: Char = '0'
|
||||
@JvmField
|
||||
var byteResult: Byte = 0
|
||||
@JvmField
|
||||
var shortResult: Short = 0
|
||||
@JvmField
|
||||
var intResult: Int = 0
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x = true
|
||||
suspendHere()
|
||||
booleanResult = x
|
||||
}
|
||||
|
||||
if (!booleanResult) return "fail 1"
|
||||
|
||||
builder {
|
||||
val x = '1'
|
||||
suspendHere()
|
||||
charResult = x
|
||||
}
|
||||
|
||||
if (charResult != '1') return "fail 2"
|
||||
|
||||
builder {
|
||||
val x: Byte = 1
|
||||
suspendHere()
|
||||
byteResult = x
|
||||
}
|
||||
|
||||
if (byteResult != 1.toByte()) return "fail 3"
|
||||
|
||||
builder {
|
||||
val x: Short = 1
|
||||
suspendHere()
|
||||
shortResult = x
|
||||
}
|
||||
|
||||
if (shortResult != 1.toShort()) return "fail 4"
|
||||
|
||||
builder {
|
||||
val x: Int = 1
|
||||
suspendHere()
|
||||
intResult = x
|
||||
}
|
||||
|
||||
if (intResult != 1) return "fail 5"
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 1 PUTFIELD .*\.B\$0 : B
|
||||
// 1 PUTFIELD .*\.C\$0 : C
|
||||
// 1 PUTFIELD .*\.S\$0 : S
|
||||
// 1 PUTFIELD .*\.Z\$0 : Z
|
||||
// 1 PUTFIELD .*\.I\$0 : I
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
class Controller {
|
||||
suspend fun suspendHere(x: Continuation<Unit>) {
|
||||
x.resume(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
val x = true
|
||||
suspendHere()
|
||||
val y: Boolean = x
|
||||
if (!y) throw IllegalStateException("fail 1")
|
||||
}
|
||||
|
||||
builder {
|
||||
val x = '1'
|
||||
suspendHere()
|
||||
|
||||
val y: Char = x
|
||||
if (y != '1') throw IllegalStateException("fail 2")
|
||||
}
|
||||
|
||||
builder {
|
||||
val x: Byte = 1
|
||||
suspendHere()
|
||||
|
||||
val y: Byte = x
|
||||
if (y != 1.toByte()) throw IllegalStateException("fail 3")
|
||||
}
|
||||
|
||||
builder {
|
||||
val x: Short = 1
|
||||
|
||||
suspendHere()
|
||||
|
||||
val y: Short = x
|
||||
if (y != 1.toShort()) throw IllegalStateException("fail 4")
|
||||
}
|
||||
|
||||
builder {
|
||||
val x: Int = 1
|
||||
suspendHere()
|
||||
|
||||
val y: Int = x
|
||||
if (y != 1) throw IllegalStateException("fail 5")
|
||||
}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// 1 PUTFIELD .*\.B\$0 : B
|
||||
// 1 PUTFIELD .*\.C\$0 : C
|
||||
// 1 PUTFIELD .*\.S\$0 : S
|
||||
// 1 PUTFIELD .*\.Z\$0 : Z
|
||||
// 1 PUTFIELD .*\.I\$0 : I
|
||||
@@ -4557,6 +4557,75 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/varValueConflictsWithTableSameSort.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class IntLikeVarSpilling extends AbstractBlackBoxCodegenTest {
|
||||
public void testAllFilesPresentInIntLikeVarSpilling() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/intLikeVarSpilling"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("complicatedMerge.kt")
|
||||
public void testComplicatedMerge() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/complicatedMerge.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("i2bResult.kt")
|
||||
public void testI2bResult() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/i2bResult.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("loadFromBooleanArray.kt")
|
||||
public void testLoadFromBooleanArray() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/loadFromBooleanArray.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("loadFromByteArray.kt")
|
||||
public void testLoadFromByteArray() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/loadFromByteArray.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noVariableInTable.kt")
|
||||
public void testNoVariableInTable() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/noVariableInTable.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("sameIconst1ManyVars.kt")
|
||||
public void testSameIconst1ManyVars() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/sameIconst1ManyVars.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("usedInArrayStore.kt")
|
||||
public void testUsedInArrayStore() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInArrayStore.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("usedInMethodCall.kt")
|
||||
public void testUsedInMethodCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInMethodCall.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("usedInPutfield.kt")
|
||||
public void testUsedInPutfield() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInPutfield.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("usedInVarStore.kt")
|
||||
public void testUsedInVarStore() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInVarStore.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/dataClasses")
|
||||
|
||||
@@ -792,6 +792,75 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/coroutines/varValueConflictsWithTableSameSort.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class IntLikeVarSpilling extends AbstractBytecodeTextTest {
|
||||
public void testAllFilesPresentInIntLikeVarSpilling() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("complicatedMerge.kt")
|
||||
public void testComplicatedMerge() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling/complicatedMerge.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("i2bResult.kt")
|
||||
public void testI2bResult() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling/i2bResult.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("loadFromBooleanArray.kt")
|
||||
public void testLoadFromBooleanArray() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling/loadFromBooleanArray.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("loadFromByteArray.kt")
|
||||
public void testLoadFromByteArray() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling/loadFromByteArray.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noVariableInTable.kt")
|
||||
public void testNoVariableInTable() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling/noVariableInTable.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("sameIconst1ManyVars.kt")
|
||||
public void testSameIconst1ManyVars() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling/sameIconst1ManyVars.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("usedInArrayStore.kt")
|
||||
public void testUsedInArrayStore() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling/usedInArrayStore.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("usedInMethodCall.kt")
|
||||
public void testUsedInMethodCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling/usedInMethodCall.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("usedInPutfield.kt")
|
||||
public void testUsedInPutfield() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling/usedInPutfield.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("usedInVarStore.kt")
|
||||
public void testUsedInVarStore() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling/usedInVarStore.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/deadCodeElimination")
|
||||
|
||||
Reference in New Issue
Block a user