KT-15112, KT-15631

Revert changes for "tolerant to uninitialized values" in OptimizationBasicInterpreter:
this approach doesn't converge for some specific cases where local variable is reused
(e.g., in several inlined functions - see https://youtrack.jetbrains.com/issue/KT-15112).

Instead, treat fake always-false conditional jump in the beginning of the post-condition loop as a "reference point" for stack on loop break / continue.
This requires an extra abstraction layer in FixStackAnalyzer, since we can't perform fine-grain manipulations on Frames
(such as "combine frame C from local variables of frame A and stack of frame B").

NB additional NOPs will be generated for post-condition loops.
Should make a separate bytecode postprocessing pass to get rid of unnecessary NOPs
(several YT issues for perceived quality of the generated bytecode are about such NOPs).
This commit is contained in:
Dmitry Petrov
2017-01-11 13:46:33 +03:00
parent c09a71b178
commit ba933fa887
15 changed files with 289 additions and 146 deletions
@@ -587,6 +587,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
blockStackElements.push(new LoopBlockStackElement(breakLabel, continueLabel, targetLabel(expression)));
PseudoInsnsKt.fakeAlwaysFalseIfeq(v, continueLabel);
PseudoInsnsKt.fakeAlwaysFalseIfeq(v, breakLabel);
KtExpression body = expression.getBody();
KtExpression condition = expression.getCondition();
@@ -32,15 +32,8 @@ import java.util.List;
import static org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue.*;
public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implements Opcodes {
private final boolean tolerantToUninitializedValues;
public OptimizationBasicInterpreter(boolean tolerantToUninitializedValues) {
super(ASM5);
this.tolerantToUninitializedValues = tolerantToUninitializedValues;
}
public OptimizationBasicInterpreter() {
this(false);
super(ASM5);
}
@Override
@@ -362,11 +355,7 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
) {
if (v.equals(w)) return v;
if (tolerantToUninitializedValues) {
if (v == StrictBasicValue.UNINITIALIZED_VALUE) return w;
if (w == StrictBasicValue.UNINITIALIZED_VALUE) return v;
}
else if (v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE) {
if (v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE) {
return StrictBasicValue.UNINITIALIZED_VALUE;
}
@@ -22,138 +22,191 @@ import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
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.Interpreter
internal class FixStackAnalyzer(
owner: String,
methodNode: MethodNode,
val method: MethodNode,
val context: FixStackContext
) : MethodAnalyzer<BasicValue>(owner, methodNode, OptimizationBasicInterpreter(/* tolerantToUninitializedValues = */true)) {
val savedStacks = hashMapOf<AbstractInsnNode, List<BasicValue>>()
var maxExtraStackSize = 0; private set
override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean {
val insnNode = instructions[insn]
return !(insnNode is JumpInsnNode && context.breakContinueGotoNodes.contains(insnNode))
) {
companion object {
// Stack size is always non-negative
const val DEAD_CODE_STACK_SIZE = -1
}
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> =
FixStackFrame(nLocals, nStack)
private val expectedStackNode = hashMapOf<LabelNode, AbstractInsnNode>()
private fun indexOf(node: AbstractInsnNode) = method.instructions.indexOf(node)
val maxExtraStackSize: Int get() = analyzer.maxExtraStackSize
inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<BasicValue>(nLocals, nStack) {
val extraStack = Stack<BasicValue>()
fun getStackToSpill(location: AbstractInsnNode) = analyzer.spilledStacks[location]
fun getActualStack(location: AbstractInsnNode) = getFrame(location)?.getStackContent()
fun getActualStackSize(location: AbstractInsnNode) = getFrame(location)?.stackSizeWithExtra ?: DEAD_CODE_STACK_SIZE
fun getExpectedStackSize(location: AbstractInsnNode) = getExpectedStackFrame(location)?.stackSizeWithExtra ?: DEAD_CODE_STACK_SIZE
override fun init(src: Frame<out BasicValue>): Frame<BasicValue> {
extraStack.clear()
extraStack.addAll((src as FixStackFrame).extraStack)
return super.init(src)
private fun getExpectedStackFrame(location: AbstractInsnNode) = getFrame(expectedStackNode[location] ?: location)
private fun getFrame(location: AbstractInsnNode) = analyzer.getFrame(location) as? InternalAnalyzer.FixStackFrame
fun analyze() {
preprocess()
analyzer.analyze()
}
private fun preprocess() {
var current: AbstractInsnNode? = method.instructions.first
while (current != null) {
val next = current.next
if (PseudoInsn.FAKE_ALWAYS_FALSE_IFEQ.isa(current) && next is JumpInsnNode) {
val nop = InsnNode(Opcodes.NOP)
expectedStackNode[next.label] = nop
method.instructions.insert(next, nop)
method.instructions.remove(current)
method.instructions.remove(next)
current = nop.next
}
else {
current = current.next
}
}
override fun clearStack() {
extraStack.clear()
super.clearStack()
context.fakeAlwaysFalseIfeqMarkers.clear()
}
private val analyzer = InternalAnalyzer(owner, method, context)
private class InternalAnalyzer(
owner: String,
method: MethodNode,
val context: FixStackContext
) : MethodAnalyzer<BasicValue>(owner, method, OptimizationBasicInterpreter()) {
val spilledStacks = hashMapOf<AbstractInsnNode, List<BasicValue>>()
var maxExtraStackSize = 0; private set
override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean {
val insnNode = instructions[insn]
return !(insnNode is JumpInsnNode && context.breakContinueGotoNodes.contains(insnNode))
}
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
when {
PseudoInsn.SAVE_STACK_BEFORE_TRY.isa(insn) ->
executeSaveStackBeforeTry(insn)
PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.isa(insn) ->
executeRestoreStackInTryCatch(insn)
InlineCodegenUtil.isBeforeInlineMarker(insn) ->
executeBeforeInlineCallMarker(insn)
InlineCodegenUtil.isAfterInlineMarker(insn) ->
executeAfterInlineCallMarker(insn)
InlineCodegenUtil.isMarkedReturn(insn) -> {
// KT-9644: might throw "Incompatible return type" on non-local return, in fact we don't care.
if (insn.opcode == Opcodes.RETURN) return
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> =
FixStackFrame(nLocals, nStack)
private fun indexOf(node: AbstractInsnNode) = method.instructions.indexOf(node)
inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<BasicValue>(nLocals, nStack) {
val extraStack = Stack<BasicValue>()
override fun init(src: Frame<out BasicValue>): Frame<BasicValue> {
extraStack.clear()
extraStack.addAll((src as FixStackFrame).extraStack)
return super.init(src)
}
override fun clearStack() {
extraStack.clear()
super.clearStack()
}
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
when {
PseudoInsn.SAVE_STACK_BEFORE_TRY.isa(insn) ->
executeSaveStackBeforeTry(insn)
PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.isa(insn) ->
executeRestoreStackInTryCatch(insn)
InlineCodegenUtil.isBeforeInlineMarker(insn) ->
executeBeforeInlineCallMarker(insn)
InlineCodegenUtil.isAfterInlineMarker(insn) ->
executeAfterInlineCallMarker(insn)
InlineCodegenUtil.isMarkedReturn(insn) -> {
// KT-9644: might throw "Incompatible return type" on non-local return, in fact we don't care.
if (insn.opcode == Opcodes.RETURN) return
}
}
super.execute(insn, interpreter)
}
val stackSizeWithExtra: Int get() = super.getStackSize() + extraStack.size
fun getStackContent(): List<BasicValue> {
val savedStack = arrayListOf<BasicValue>()
IntRange(0, super.getStackSize() - 1).mapTo(savedStack) { super.getStack(it) }
savedStack.addAll(extraStack)
return savedStack
}
override fun push(value: BasicValue) {
if (super.getStackSize() < maxStackSize) {
super.push(value)
}
else {
extraStack.add(value)
maxExtraStackSize = Math.max(maxExtraStackSize, extraStack.size)
}
}
super.execute(insn, interpreter)
}
fun getStackContent(): List<BasicValue> {
val savedStack = arrayListOf<BasicValue>()
IntRange(0, super.getStackSize() - 1).mapTo(savedStack) { super.getStack(it) }
savedStack.addAll(extraStack)
return savedStack
}
override fun push(value: BasicValue) {
if (super.getStackSize() < maxStackSize) {
super.push(value)
fun pushAll(values: Collection<BasicValue>) {
values.forEach { push(it) }
}
else {
extraStack.add(value)
maxExtraStackSize = Math.max(maxExtraStackSize, extraStack.size)
override fun pop(): BasicValue {
if (extraStack.isNotEmpty()) {
return extraStack.pop()
}
else {
return super.pop()
}
}
override fun getStack(i: Int): BasicValue {
if (i < super.getMaxStackSize()) {
return super.getStack(i)
}
else {
return extraStack[i - maxStackSize]
}
}
}
fun pushAll(values: Collection<BasicValue>) {
values.forEach { push(it) }
private fun FixStackFrame.executeBeforeInlineCallMarker(insn: AbstractInsnNode) {
saveStackAndClear(insn)
}
override fun pop(): BasicValue {
if (extraStack.isNotEmpty()) {
return extraStack.pop()
}
else {
return super.pop()
}
}
override fun getStack(i: Int): BasicValue {
if (i < super.getMaxStackSize()) {
return super.getStack(i)
}
else {
return extraStack[i - maxStackSize]
}
}
}
private fun FixStackFrame.executeBeforeInlineCallMarker(insn: AbstractInsnNode) {
saveStackAndClear(insn)
}
private fun FixStackFrame.saveStackAndClear(insn: AbstractInsnNode) {
val savedValues = getStackContent()
savedStacks[insn] = savedValues
clearStack()
}
private fun FixStackFrame.executeAfterInlineCallMarker(insn: AbstractInsnNode) {
val beforeInlineMarker = context.openingInlineMethodMarker[insn]
if (stackSize > 0) {
val returnValue = pop()
private fun FixStackFrame.saveStackAndClear(insn: AbstractInsnNode) {
val savedValues = getStackContent()
spilledStacks[insn] = savedValues
clearStack()
val savedValues = savedStacks[beforeInlineMarker]
pushAll(savedValues!!)
push(returnValue)
}
else {
val savedValues = savedStacks[beforeInlineMarker]
pushAll(savedValues!!)
private fun FixStackFrame.executeAfterInlineCallMarker(insn: AbstractInsnNode) {
val beforeInlineMarker = context.openingInlineMethodMarker[insn]
if (stackSize > 0) {
val returnValue = pop()
clearStack()
val savedValues = spilledStacks[beforeInlineMarker]
pushAll(savedValues!!)
push(returnValue)
}
else {
val savedValues = spilledStacks[beforeInlineMarker]
pushAll(savedValues!!)
}
}
private fun FixStackFrame.executeRestoreStackInTryCatch(insn: AbstractInsnNode) {
val saveNode = context.saveStackMarkerForRestoreMarker[insn]
val savedValues = spilledStacks.getOrElse(saveNode!!) {
throw AssertionError("${indexOf(insn)}: Restore stack is unavailable for ${indexOf(saveNode)}")
}
pushAll(savedValues)
}
private fun FixStackFrame.executeSaveStackBeforeTry(insn: AbstractInsnNode) {
saveStackAndClear(insn)
}
}
private fun FixStackFrame.executeRestoreStackInTryCatch(insn: AbstractInsnNode) {
val saveNode = context.saveStackMarkerForRestoreMarker[insn]
val savedValues = savedStacks.getOrElse(saveNode!!) {
throw AssertionError("${indexOf(insn)}: Restore stack is unavailable for ${indexOf(saveNode)}")
}
pushAll(savedValues)
}
private fun FixStackFrame.executeSaveStackBeforeTry(insn: AbstractInsnNode) {
saveStackAndClear(insn)
}
}
@@ -72,16 +72,18 @@ class FixStackMethodTransformer : MethodTransformer() {
val gotoIndex = methodNode.instructions.indexOf(gotoNode)
val labelIndex = methodNode.instructions.indexOf(gotoNode.label)
val DEAD_CODE = -1 // Stack size is always non-negative
val actualStackSize = analyzer.frames[gotoIndex]?.stackSize ?: DEAD_CODE
val expectedStackSize = analyzer.frames[labelIndex]?.stackSize ?: DEAD_CODE
val actualStackSize = analyzer.getActualStackSize(gotoNode)
val expectedStackSize = analyzer.getExpectedStackSize(gotoNode.label)
if (actualStackSize != DEAD_CODE && expectedStackSize != DEAD_CODE) {
assert(expectedStackSize <= actualStackSize) { "Label at $labelIndex, jump at $gotoIndex: stack underflow: $expectedStackSize > $actualStackSize" }
val frame = analyzer.frames[gotoIndex]!!
actions.add({ replaceMarkerWithPops(methodNode, gotoNode.previous, expectedStackSize, frame) })
if (actualStackSize >= 0 && expectedStackSize >= 0) {
assert(expectedStackSize <= actualStackSize) {
"Label at $labelIndex, jump at $gotoIndex: stack underflow: $expectedStackSize > $actualStackSize"
}
val actualStackContent = analyzer.getActualStack(gotoNode)
?: throw AssertionError("Jump at $gotoIndex should be alive")
actions.add({ replaceMarkerWithPops(methodNode, gotoNode.previous, expectedStackSize, actualStackContent) })
}
else if (actualStackSize != DEAD_CODE && expectedStackSize == DEAD_CODE) {
else if (actualStackSize >= 0 && expectedStackSize < 0) {
throw AssertionError("Live jump $gotoIndex to dead label $labelIndex")
}
else {
@@ -120,7 +122,7 @@ class FixStackMethodTransformer : MethodTransformer() {
marker: AbstractInsnNode,
localVariablesManager: LocalVariablesManager
) {
val savedStackValues = analyzer.savedStacks[marker]
val savedStackValues = analyzer.getStackToSpill(marker)
if (savedStackValues != null) {
val savedStackDescriptor = localVariablesManager.allocateVariablesForSaveStackMarker(marker, savedStackValues)
actions.add({ saveStack(methodNode, marker, savedStackDescriptor, false) })
@@ -151,20 +153,21 @@ class FixStackMethodTransformer : MethodTransformer() {
localVariablesManager: LocalVariablesManager
) {
val savedStackDescriptor = localVariablesManager.getBeforeInlineDescriptor(inlineMarker)
val afterInlineFrame = analyzer.getFrame(inlineMarker) as FixStackAnalyzer.FixStackFrame?
if (afterInlineFrame != null && savedStackDescriptor.isNotEmpty()) {
assert(afterInlineFrame.stackSize <= 1) { "Inline method should not leave more than 1 value on stack" }
if (afterInlineFrame.stackSize == 1) {
val afterInlineStackValues = afterInlineFrame.getStackContent()
val returnValue = afterInlineStackValues.last()
val returnValueLocalVarIndex = localVariablesManager.createReturnValueVariable(returnValue)
actions.add({
restoreStackWithReturnValue(methodNode, inlineMarker, savedStackDescriptor,
returnValue, returnValueLocalVarIndex)
})
}
else {
actions.add({ restoreStack(methodNode, inlineMarker, savedStackDescriptor) })
val stackContentAfterInline = analyzer.getActualStack(inlineMarker)
if (stackContentAfterInline != null && savedStackDescriptor.isNotEmpty()) {
when (stackContentAfterInline.size) {
1 -> {
val returnValue = stackContentAfterInline.last()
val returnValueLocalVarIndex = localVariablesManager.createReturnValueVariable(returnValue)
actions.add({
restoreStackWithReturnValue(methodNode, inlineMarker, savedStackDescriptor,
returnValue, returnValueLocalVarIndex)
})
}
0 ->
actions.add({ restoreStack(methodNode, inlineMarker, savedStackDescriptor) })
else ->
throw AssertionError("Inline method should not leave more than 1 value on stack")
}
}
else {
@@ -181,7 +184,7 @@ class FixStackMethodTransformer : MethodTransformer() {
inlineMarker: AbstractInsnNode,
localVariablesManager: LocalVariablesManager
) {
val savedStackValues = analyzer.savedStacks[inlineMarker]
val savedStackValues = analyzer.getStackToSpill(inlineMarker)
if (savedStackValues != null) {
val savedStackDescriptor = localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, savedStackValues)
actions.add({ saveStack(methodNode, inlineMarker, savedStackDescriptor, false) })
@@ -115,11 +115,10 @@ fun replaceAlwaysTrueIfeqWithGoto(methodNode: MethodNode, node: AbstractInsnNode
}
}
fun replaceMarkerWithPops(methodNode: MethodNode, node: AbstractInsnNode, expectedStackSize: Int, frame: Frame<BasicValue>) {
fun replaceMarkerWithPops(methodNode: MethodNode, node: AbstractInsnNode, expectedStackSize: Int, stackContent: List<BasicValue>) {
with (methodNode.instructions) {
while (frame.stackSize > expectedStackSize) {
val top = frame.pop()
insertBefore(node, getPopInstruction(top))
for (stackValue in stackContent.subList(expectedStackSize, stackContent.size)) {
insert(node, getPopInstruction(stackValue))
}
remove(node)
}
@@ -0,0 +1,8 @@
fun box(): String {
var flag = false
do {
if (flag) break
continue
} while (false)
return "OK"
}
@@ -0,0 +1,29 @@
// FULL_JDK
// WITH_RUNTIME
// IGNORE_BACKEND: JS
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write
private val evalStateLock = ReentrantReadWriteLock()
private val classLoaderLock = ReentrantReadWriteLock()
val compiledClasses = arrayListOf("")
fun box(): String = evalStateLock.write {
classLoaderLock.read {
classLoaderLock.write {
"write"
}
compiledClasses.forEach {
it
}
}
classLoaderLock.read {
compiledClasses.map { it }
}
"OK"
}
@@ -0,0 +1,4 @@
@kotlin.Metadata
public final class PathologicalDoWhileKt {
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
}
@@ -0,0 +1,8 @@
@kotlin.Metadata
public final class Kt15112Kt {
private final static field classLoaderLock: java.util.concurrent.locks.ReentrantReadWriteLock
private final static @org.jetbrains.annotations.NotNull field compiledClasses: java.util.ArrayList
private final static field evalStateLock: java.util.concurrent.locks.ReentrantReadWriteLock
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static @org.jetbrains.annotations.NotNull method getCompiledClasses(): java.util.ArrayList
}
@@ -10,4 +10,4 @@ fun testSome(): Boolean {
return false
}
// 2 +3 4 2 7 10
// 2 3 4 2 7 10
@@ -4345,6 +4345,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("pathologicalDoWhile.kt")
public void testPathologicalDoWhile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/pathologicalDoWhile.kt");
doTest(fileName);
}
@TestMetadata("popSizes.kt")
public void testPopSizes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/popSizes.kt");
@@ -7465,6 +7471,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/fullJdk/regressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("kt15112.kt")
public void testKt15112() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/fullJdk/regressions/kt15112.kt");
doTest(fileName);
}
@TestMetadata("kt1770.kt")
public void testKt1770() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/fullJdk/regressions/kt1770.kt");
@@ -4345,6 +4345,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("pathologicalDoWhile.kt")
public void testPathologicalDoWhile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/pathologicalDoWhile.kt");
doTest(fileName);
}
@TestMetadata("popSizes.kt")
public void testPopSizes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/popSizes.kt");
@@ -7465,6 +7471,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/fullJdk/regressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("kt15112.kt")
public void testKt15112() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/fullJdk/regressions/kt15112.kt");
doTest(fileName);
}
@TestMetadata("kt1770.kt")
public void testKt1770() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/fullJdk/regressions/kt1770.kt");
@@ -4345,6 +4345,12 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis
doTest(fileName);
}
@TestMetadata("pathologicalDoWhile.kt")
public void testPathologicalDoWhile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/pathologicalDoWhile.kt");
doTest(fileName);
}
@TestMetadata("popSizes.kt")
public void testPopSizes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/popSizes.kt");
@@ -7465,6 +7471,12 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/fullJdk/regressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("kt15112.kt")
public void testKt15112() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/fullJdk/regressions/kt15112.kt");
doTest(fileName);
}
@TestMetadata("kt1770.kt")
public void testKt1770() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/fullJdk/regressions/kt1770.kt");
@@ -10,13 +10,14 @@ stepOverWhileWithInline.kt:13
stepOverWhileWithInline.kt:14
stepOverWhileWithInline.kt:15
stepOverWhileWithInline.kt:13
stepOverWhileWithInline.kt:18
stepOverWhileWithInline.kt:19
stepOverWhileWithInline.kt:20
stepOverWhileWithInline.kt:21
stepOverWhileWithInline.kt:23
stepOverWhileWithInline.kt:24
stepOverWhileWithInline.kt:25
stepOverWhileWithInline.kt:26
stepOverWhileWithInline.kt:27
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -5084,6 +5084,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("pathologicalDoWhile.kt")
public void testPathologicalDoWhile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/pathologicalDoWhile.kt");
doTest(fileName);
}
@TestMetadata("popSizes.kt")
public void testPopSizes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/popSizes.kt");
@@ -8432,6 +8438,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/fullJdk/regressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("kt15112.kt")
public void testKt15112() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/fullJdk/regressions/kt15112.kt");
doTest(fileName);
}
@TestMetadata("kt1770.kt")
public void testKt1770() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/fullJdk/regressions/kt1770.kt");