[JVM] Extend stepping tests with <clinit> stepping.
In addition, made the stepping information for constructor calls consistent across JVM_IR and JVM. For JVM_IR that stepping behavior is consistent for enum constructor calls in <clinit> for JVM it is not.
This commit is contained in:
+1
@@ -401,6 +401,7 @@ class ExpressionCodegen(
|
|||||||
|
|
||||||
// IR constructors have no receiver and return the new instance, but on JVM they are void-returning
|
// IR constructors have no receiver and return the new instance, but on JVM they are void-returning
|
||||||
// instance methods named <init>.
|
// instance methods named <init>.
|
||||||
|
markLineNumber(expression)
|
||||||
mv.anew(asmType)
|
mv.anew(asmType)
|
||||||
mv.dup()
|
mv.dup()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ fun box() {
|
|||||||
|
|
||||||
// LINENUMBERS
|
// LINENUMBERS
|
||||||
// test.kt:14 box
|
// test.kt:14 box
|
||||||
|
// test.kt:5 <clinit>
|
||||||
|
// test.kt:6 <clinit>
|
||||||
// test.kt:5 getProp0
|
// test.kt:5 getProp0
|
||||||
// LINENUMBERS JVM
|
// LINENUMBERS JVM
|
||||||
// test.kt:5 getProp0
|
// test.kt:5 getProp0
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// FILE: test.kt
|
||||||
|
|
||||||
|
class A(val x: Int)
|
||||||
|
|
||||||
|
fun box() {
|
||||||
|
A(1)
|
||||||
|
A(
|
||||||
|
2
|
||||||
|
)
|
||||||
|
A(3
|
||||||
|
)
|
||||||
|
A(
|
||||||
|
4)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LINENUMBERS
|
||||||
|
// test.kt:6 box
|
||||||
|
// test.kt:3 <init>
|
||||||
|
// test.kt:6 box
|
||||||
|
// test.kt:7 box
|
||||||
|
// test.kt:8 box
|
||||||
|
// test.kt:7 box
|
||||||
|
// test.kt:3 <init>
|
||||||
|
// test.kt:7 box
|
||||||
|
// test.kt:10 box
|
||||||
|
// test.kt:3 <init>
|
||||||
|
// test.kt:10 box
|
||||||
|
// test.kt:12 box
|
||||||
|
// test.kt:13 box
|
||||||
|
// test.kt:12 box
|
||||||
|
// test.kt:3 <init>
|
||||||
|
// test.kt:12 box
|
||||||
|
// test.kt:14 box
|
||||||
+40
-9
@@ -1,7 +1,8 @@
|
|||||||
// FILE: test.kt
|
// FILE: test.kt
|
||||||
|
|
||||||
enum class E {
|
enum class E() {
|
||||||
E1;
|
A,
|
||||||
|
B;
|
||||||
|
|
||||||
fun foo() = {
|
fun foo() = {
|
||||||
prop
|
prop
|
||||||
@@ -10,13 +11,43 @@ enum class E {
|
|||||||
val prop = 22
|
val prop = 22
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() {
|
enum class E2(val y : Int) {
|
||||||
E.E1.foo()
|
C(1),
|
||||||
|
D(
|
||||||
|
2
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun box() {
|
||||||
|
E.A.foo()
|
||||||
|
E2.C;
|
||||||
|
}
|
||||||
|
|
||||||
|
// JVM_IR maintains line number information in the class initializer for the
|
||||||
|
// initialization of the enum entries. There is line number information for
|
||||||
|
// the allocation of the object, for the evaluation of arguments to the
|
||||||
|
// constructor, and for the call to the constructor. This is consistent
|
||||||
|
// with the line number information generated for normal object allocation.
|
||||||
|
|
||||||
|
// JVM has no line number information in <clinit> if there are no arguments
|
||||||
|
// to the enum constructor. If there are arguments it has line number information
|
||||||
|
// for the evaluation of the arguments constructor and for the constructor call,
|
||||||
|
// but not for the allocation of the object.
|
||||||
|
|
||||||
// LINENUMBERS
|
// LINENUMBERS
|
||||||
// test.kt:14 box
|
// test.kt:22 box
|
||||||
// test.kt:6 foo
|
// LINENUMBERS JVM_IR
|
||||||
// test.kt:8 foo
|
// test.kt:4 <clinit>
|
||||||
// test.kt:14 box
|
// test.kt:5 <clinit>
|
||||||
// test.kt:15 box
|
// LINENUMBERS
|
||||||
|
// test.kt:7 foo
|
||||||
|
// test.kt:9 foo
|
||||||
|
// test.kt:22 box
|
||||||
|
// test.kt:23 box
|
||||||
|
// test.kt:15 <clinit>
|
||||||
|
// LINENUMBERS JVM_IR
|
||||||
|
// test.kt:16 <clinit>
|
||||||
|
// LINENUMBERS
|
||||||
|
// test.kt:17 <clinit>
|
||||||
|
// test.kt:16 <clinit>
|
||||||
|
// test.kt:24 box
|
||||||
+11
-4
@@ -32,12 +32,19 @@ fun box() {
|
|||||||
|
|
||||||
// JVM backend has extra steps for getX and getS.
|
// JVM backend has extra steps for getX and getS.
|
||||||
|
|
||||||
// TODO: since these tests operate as step-into, we do not get any steps
|
|
||||||
// in the <clinit> for the companion object. Maybe extend the test infrastructure
|
|
||||||
// with directives to set break points in order to test this.
|
|
||||||
|
|
||||||
// LINENUMBERS
|
// LINENUMBERS
|
||||||
// test.kt:29 box
|
// test.kt:29 box
|
||||||
|
// test.kt:7 <clinit>
|
||||||
|
// test.kt:8 <clinit>
|
||||||
|
// test.kt:9 <clinit>
|
||||||
|
// test.kt:11 <clinit>
|
||||||
|
// test.kt:13 <clinit>
|
||||||
|
// test.kt:15 <clinit>
|
||||||
|
// test.kt:16 <clinit>
|
||||||
|
// test.kt:17 <clinit>
|
||||||
|
// test.kt:19 <clinit>
|
||||||
|
// test.kt:21 <clinit>
|
||||||
|
// test.kt:22 <clinit>
|
||||||
// test.kt:11 getX
|
// test.kt:11 getX
|
||||||
// LINENUMBERS JVM
|
// LINENUMBERS JVM
|
||||||
// test.kt:11 getX
|
// test.kt:11 getX
|
||||||
|
|||||||
+31
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.codegen.debugInformation
|
|||||||
import com.intellij.openapi.util.SystemInfo
|
import com.intellij.openapi.util.SystemInfo
|
||||||
import com.intellij.util.PathUtil
|
import com.intellij.util.PathUtil
|
||||||
import com.intellij.util.SystemProperties
|
import com.intellij.util.SystemProperties
|
||||||
|
import com.sun.jdi.AbsentInformationException
|
||||||
import com.sun.jdi.VirtualMachine
|
import com.sun.jdi.VirtualMachine
|
||||||
import com.sun.jdi.event.*
|
import com.sun.jdi.event.*
|
||||||
import com.sun.jdi.request.EventRequest
|
import com.sun.jdi.request.EventRequest
|
||||||
@@ -194,13 +195,22 @@ abstract class AbstractDebugTest : CodegenTestCase() {
|
|||||||
is MethodEntryEvent -> {
|
is MethodEntryEvent -> {
|
||||||
if (!inBoxMethod && event.location().method().name() == BOX_METHOD) {
|
if (!inBoxMethod && event.location().method().name() == BOX_METHOD) {
|
||||||
if (manager.stepRequests().isEmpty()) {
|
if (manager.stepRequests().isEmpty()) {
|
||||||
|
// Create line stepping request to get all normal line steps starting now.
|
||||||
val stepReq = manager.createStepRequest(event.thread(), StepRequest.STEP_LINE, StepRequest.STEP_INTO)
|
val stepReq = manager.createStepRequest(event.thread(), StepRequest.STEP_LINE, StepRequest.STEP_INTO)
|
||||||
stepReq.setSuspendPolicy(SUSPEND_ALL)
|
stepReq.setSuspendPolicy(SUSPEND_ALL)
|
||||||
stepReq.addClassExclusionFilter("java.*")
|
stepReq.addClassExclusionFilter("java.*")
|
||||||
stepReq.addClassExclusionFilter("sun.*")
|
stepReq.addClassExclusionFilter("sun.*")
|
||||||
stepReq.addClassExclusionFilter("kotlin.*")
|
stepReq.addClassExclusionFilter("kotlin.*")
|
||||||
|
// Create class prepare request to be able to set breakpoints on class initializer lines.
|
||||||
|
// There are no line stepping events for class initializers, so we depend on breakpoints.
|
||||||
|
val prepareReq = manager.createClassPrepareRequest()
|
||||||
|
prepareReq.setSuspendPolicy(SUSPEND_ALL)
|
||||||
|
prepareReq.addClassExclusionFilter("java.*")
|
||||||
|
prepareReq.addClassExclusionFilter("sun.*")
|
||||||
|
prepareReq.addClassExclusionFilter("kotlin.*")
|
||||||
}
|
}
|
||||||
manager.stepRequests().map { it.enable() }
|
manager.stepRequests().map { it.enable() }
|
||||||
|
manager.classPrepareRequests().map { it.enable() }
|
||||||
inBoxMethod = true
|
inBoxMethod = true
|
||||||
storeStep(loggedItems, event)
|
storeStep(loggedItems, event)
|
||||||
}
|
}
|
||||||
@@ -209,6 +219,8 @@ abstract class AbstractDebugTest : CodegenTestCase() {
|
|||||||
// Handle the case where an Exception causing program to exit without MethodExitEvent.
|
// Handle the case where an Exception causing program to exit without MethodExitEvent.
|
||||||
if (inBoxMethod && event.location().method().name() == "run") {
|
if (inBoxMethod && event.location().method().name() == "run") {
|
||||||
manager.stepRequests().map { it.disable() }
|
manager.stepRequests().map { it.disable() }
|
||||||
|
manager.classPrepareRequests().map { it.disable() }
|
||||||
|
manager.breakpointRequests().map { it.disable() }
|
||||||
break@vmLoop
|
break@vmLoop
|
||||||
}
|
}
|
||||||
if (inBoxMethod) {
|
if (inBoxMethod) {
|
||||||
@@ -218,9 +230,28 @@ abstract class AbstractDebugTest : CodegenTestCase() {
|
|||||||
is MethodExitEvent -> {
|
is MethodExitEvent -> {
|
||||||
if (event.location().method().name() == BOX_METHOD) {
|
if (event.location().method().name() == BOX_METHOD) {
|
||||||
manager.stepRequests().map { it.disable() }
|
manager.stepRequests().map { it.disable() }
|
||||||
|
manager.classPrepareRequests().map { it.disable() }
|
||||||
|
manager.breakpointRequests().map { it.disable() }
|
||||||
break@vmLoop
|
break@vmLoop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is ClassPrepareEvent -> {
|
||||||
|
if (inBoxMethod) {
|
||||||
|
val initializer = event.referenceType().methods().find { it.isStaticInitializer }
|
||||||
|
try {
|
||||||
|
initializer?.allLineLocations()?.forEach {
|
||||||
|
manager.createBreakpointRequest(it).enable()
|
||||||
|
}
|
||||||
|
} catch (e: AbsentInformationException) {
|
||||||
|
// If there is no line information, do not set breakpoints.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is BreakpointEvent -> {
|
||||||
|
if (inBoxMethod) {
|
||||||
|
storeStep(loggedItems, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
throw IllegalStateException("event not handled: $event")
|
throw IllegalStateException("event not handled: $event")
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -97,6 +97,12 @@ public class IrSteppingTestGenerated extends AbstractIrSteppingTest {
|
|||||||
runTest("compiler/testData/debug/stepping/conjunction.kt");
|
runTest("compiler/testData/debug/stepping/conjunction.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("constructorCall.kt")
|
||||||
|
public void testConstructorCall() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/constructorCall.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("defaultParameter.kt")
|
@TestMetadata("defaultParameter.kt")
|
||||||
public void testDefaultParameter() throws Exception {
|
public void testDefaultParameter() throws Exception {
|
||||||
|
|||||||
+6
@@ -97,6 +97,12 @@ public class SteppingTestGenerated extends AbstractSteppingTest {
|
|||||||
runTest("compiler/testData/debug/stepping/conjunction.kt");
|
runTest("compiler/testData/debug/stepping/conjunction.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("constructorCall.kt")
|
||||||
|
public void testConstructorCall() throws Exception {
|
||||||
|
runTest("compiler/testData/debug/stepping/constructorCall.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("defaultParameter.kt")
|
@TestMetadata("defaultParameter.kt")
|
||||||
public void testDefaultParameter() throws Exception {
|
public void testDefaultParameter() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user