8203174: [Graal] JDI tests fail with Unexpected exception: com.sun.jdi.ObjectCollectedException
authordtitov
Thu, 15 Nov 2018 09:56:49 -0800
changeset 52574 8ba2479fe7fa
parent 52573 6e8c1206cca1
child 52575 1092ba73cb2d
8203174: [Graal] JDI tests fail with Unexpected exception: com.sun.jdi.ObjectCollectedException Reviewed-by: sspitsyn, cjplummer
test/hotspot/jtreg/ProblemList-graal.txt
test/hotspot/jtreg/vmTestbase/nsk/jdi/ArrayType/newInstance/newinstance001.java
test/hotspot/jtreg/vmTestbase/nsk/jdi/ArrayType/newInstance/newinstance002.java
test/hotspot/jtreg/vmTestbase/nsk/jdi/ArrayType/newInstance/newinstance003.java
test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/instances/instances002/instances002.java
test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/instances/instances003/instances003.java
test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebuggee.java
--- a/test/hotspot/jtreg/ProblemList-graal.txt	Thu Nov 15 09:45:18 2018 +0100
+++ b/test/hotspot/jtreg/ProblemList-graal.txt	Thu Nov 15 09:56:49 2018 -0800
@@ -107,16 +107,6 @@
 
 vmTestbase/nsk/jdi/ThreadReference/forceEarlyReturn/forceEarlyReturn007/TestDescription.java       8195600   generic-all
 
-vmTestbase/nsk/jdi/ArrayType/newInstance/newinstance001/TestDescription.java                              8203174   generic-all
-vmTestbase/nsk/jdi/ArrayType/newInstance/newinstance002/TestDescription.java                              8203174   generic-all
-vmTestbase/nsk/jdi/ArrayType/newInstance/newinstance003/TestDescription.java                              8203174   generic-all
-vmTestbase/nsk/jdi/ReferenceType/instances/instances002/instances002.java                                 8203174   generic-all
-vmTestbase/nsk/jdi/ReferenceType/instances/instances003/instances003.java                                 8203174   generic-all
-vmTestbase/nsk/jdi/stress/MonitorEvents/MonitorEvents002/TestDescription.java                             8203174   generic-all
-vmTestbase/nsk/jdi/stress/serial/heapwalking001/TestDescription.java                                      8203174   generic-all
-vmTestbase/nsk/jdi/stress/serial/heapwalking002/TestDescription.java                                      8203174   generic-all
-vmTestbase/nsk/jdi/stress/serial/mixed002/TestDescription.java                                            8203174   generic-all
-
 vmTestbase/nsk/jdi/VirtualMachine/redefineClasses/redefineclasses026/TestDescription.java   8195627   generic-all
 vmTestbase/nsk/jdi/VirtualMachine/redefineClasses/redefineclasses028/TestDescription.java   8195627   generic-all
 vmTestbase/nsk/jdi/VirtualMachine/redefineClasses/redefineclasses030/TestDescription.java   8195627   generic-all
--- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ArrayType/newInstance/newinstance001.java	Thu Nov 15 09:45:18 2018 +0100
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ArrayType/newInstance/newinstance001.java	Thu Nov 15 09:56:49 2018 -0800
@@ -148,9 +148,23 @@
         log1("      TESTING BEGINS");
 
         for (int i = 0; ; i++) {
-        pipe.println("newcheck");
+            pipe.println("newcheck");
+
+            // There are potentially other non-test Java threads allocating objects and triggering
+            // GC's so we need to suspend the target VM to avoid the objects created in the test
+            // from being accidentally GC'ed. However, we need the target VM temporary resumed
+            // while reading its response. Below we resume the target VM (if required) and suspend
+            // it only after pipe.readln() returns.
+
+            // On the first iteration the target VM is not suspended yet.
+            if (i > 0) {
+                debuggee.resume();
+            }
             line = pipe.readln();
 
+            // Suspending target VM to prevent other non-test Java threads from triggering GCs.
+            debuggee.suspend();
+
             if (line.equals("checkend")) {
                 log2("     : returned string is 'checkend'");
                 break ;
@@ -359,6 +373,7 @@
     //--------------------------------------------------   test summary section
     //-------------------------------------------------    standard end section
 
+        debuggee.resume();
         pipe.println("quit");
         log2("waiting for the debuggee to finish ...");
         debuggee.waitFor();
--- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ArrayType/newInstance/newinstance002.java	Thu Nov 15 09:45:18 2018 +0100
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ArrayType/newInstance/newinstance002.java	Thu Nov 15 09:56:49 2018 -0800
@@ -145,9 +145,23 @@
         log1("      TESTING BEGINS");
 
         for (int i = 0; ; i++) {
-        pipe.println("newcheck");
+            pipe.println("newcheck");
+
+            // There are potentially other non-test Java threads allocating objects and triggering
+            // GC's so we need to suspend the target VM to avoid the objects created in the test
+            // from being accidentally GC'ed. However, we need the target VM temporary resumed
+            // while reading its response. Below we resume the target VM (if required) and suspend
+            // it only after pipe.readln() returns.
+
+            // On the first iteration the target VM is not suspended yet.
+            if (i > 0) {
+                debuggee.resume();
+            }
             line = pipe.readln();
 
+            // Suspending target VM to prevent other non-test Java threads from triggering GCs.
+            debuggee.suspend();
+
             if (line.equals("checkend")) {
                 log2("     : returned string is 'checkend'");
                 break ;
@@ -232,6 +246,7 @@
     //--------------------------------------------------   test summary section
     //-------------------------------------------------    standard end section
 
+        debuggee.resume();
         pipe.println("quit");
         log2("waiting for the debuggee to finish ...");
         debuggee.waitFor();
--- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ArrayType/newInstance/newinstance003.java	Thu Nov 15 09:45:18 2018 +0100
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ArrayType/newInstance/newinstance003.java	Thu Nov 15 09:56:49 2018 -0800
@@ -144,9 +144,23 @@
         log1("      TESTING BEGINS");
 
         for (int i = 0; ; i++) {
-        pipe.println("newcheck");
+            pipe.println("newcheck");
+
+            // There are potentially other non-test Java threads allocating objects and triggering
+            // GC's so we need to suspend the target VM to avoid the objects created in the test
+            // from being accidentally GC'ed. However, we need the target VM temporary resumed
+            // while reading its response. Below we resume the target VM (if required) and suspend
+            // it only after pipe.readln() returns.
+
+            // On the first iteration the target VM is not suspended yet.
+            if (i > 0) {
+                debuggee.resume();
+            }
             line = pipe.readln();
 
+            // Suspending target VM to prevent other non-test Java threads from triggering GCs.
+            debuggee.suspend();
+
             if (line.equals("checkend")) {
                 log2("     : returned string is 'checkend'");
                 break ;
@@ -228,7 +242,7 @@
 
     //--------------------------------------------------   test summary section
     //-------------------------------------------------    standard end section
-
+        debuggee.resume();
         pipe.println("quit");
         log2("waiting for the debuggee to finish ...");
         debuggee.waitFor();
--- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/instances/instances002/instances002.java	Thu Nov 15 09:45:18 2018 +0100
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/instances/instances002/instances002.java	Thu Nov 15 09:56:49 2018 -0800
@@ -109,8 +109,22 @@
             log.complain("Unexpected reference type: " + referenceType.getClass().getName() + ", expected is ArrayType");
             return;
         }
+        // There are potentially other non-test Java threads allocating objects and triggering GC's.
+        debuggee.suspend();
 
-        baseInstances = referenceType.instances(0).size();
+        List<ObjectReference> baseReferences = new LinkedList<>();
+        // We need to call disableCollection() on each object returned by referenceType.instances()
+        // to deal with the case when GC was triggered before the suspend. Otherwise, these objects can
+        // be potentially collected.
+        for (ObjectReference objRef : referenceType.instances(0)) {
+            try {
+                objRef.disableCollection();
+                baseReferences.add(objRef);
+            } catch (ObjectCollectedException e) {
+                // skip this reference
+            }
+        }
+        baseInstances = baseReferences.size();
 
         int createInstanceCount = 100;
         int arraySize = 1;
@@ -129,8 +143,15 @@
 
         checkDebugeeAnswer_instances(className, createInstanceCount + baseInstances);
 
-        for (ArrayReference arrayReference : objectReferences)
+        for (ArrayReference arrayReference : objectReferences) {
             arrayReference.enableCollection();
+        }
+
+        for (ObjectReference baseRef : baseReferences) {
+            baseRef.enableCollection();
+        }
+
+        debuggee.resume();
     }
 
     // test method ClassType.newInstance
--- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/instances/instances003/instances003.java	Thu Nov 15 09:45:18 2018 +0100
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ReferenceType/instances/instances003/instances003.java	Thu Nov 15 09:56:49 2018 -0800
@@ -62,6 +62,7 @@
 import java.io.PrintStream;
 import java.util.*;
 
+import com.sun.jdi.ObjectCollectedException;
 import com.sun.jdi.ObjectReference;
 import com.sun.jdi.ReferenceType;
 
@@ -122,9 +123,10 @@
 
         // create temporary strong references to prevent the weakly referred instances being GCed
         // during the time between creating them and disabling collection on them
+        boolean useTempStrongReference = needTempStongReference(referrerType);
         pipe.println(HeapwalkingDebuggee.COMMAND_CREATE_INSTANCES + ":" + className + ":" + createInstanceCount +
-            ":" + referrerCount + ":" + referrerType +
-            (referrerType.equals(ObjectInstancesManager.WEAK_REFERENCE) ? "|" + ObjectInstancesManager.STRONG_REFERENCE : ""));
+                ":" + referrerCount + ":" + referrerType +
+                (useTempStrongReference ? "|" + ObjectInstancesManager.STRONG_REFERENCE : ""));
 
         // Note! This test is broken, in the sense that it incorrectly assumes
         // that no GC can happen before it walks the heap. In practice, it seems
@@ -135,14 +137,24 @@
         checkDebugeeAnswer_instanceCounts(className, createInstanceCount, objectsToFilter);
 
         ReferenceType referenceType = debuggee.classByName(className);
-        List<ObjectReference> instances = HeapwalkingDebugger.filterObjectReferrence(objectsToFilter, referenceType.instances(0));
+        List<ObjectReference> allInstances = HeapwalkingDebugger.filterObjectReferrence(objectsToFilter, referenceType.instances(0));
 
-        for (ObjectReference or : instances) {
-            or.disableCollection();
+        // There are potentially other non-test Java threads allocating objects and triggering GC's.
+        // We need to call disableCollection() on each object returned by referenceType.instances()
+        // to deal with the case when GC was triggered. Otherwise, these objects can
+        // be potentially collected.
+        List<ObjectReference> instances = new LinkedList<>();
+        for (ObjectReference objRef : allInstances) {
+            try {
+                objRef.disableCollection();
+                instances.add(objRef);
+            } catch (ObjectCollectedException ex) {
+                // skip this references
+            }
         }
 
         // remove the temporary strong references so the weak references can be properly tested
-        if (referrerType.equals(ObjectInstancesManager.WEAK_REFERENCE)) {
+        if (useTempStrongReference) {
             pipe.println(HeapwalkingDebuggee.COMMAND_DELETE_REFERRERS + ":" + className + ":" + referrerCount + ":" + ObjectInstancesManager.STRONG_REFERENCE);
             if (!isDebuggeeReady()) {
                 return;
@@ -157,6 +169,7 @@
             instances.get(i).enableCollection();
         }
 
+
         pipe.println(HeapwalkingDebuggee.COMMAND_DELETE_INSTANCES + ":" + className + ":" + createInstanceCount);
 
         if (!isDebuggeeReady())
@@ -183,4 +196,13 @@
                 testClass(className, referenceType);
         }
     }
+
+
+    private static boolean needTempStongReference(String referenceType) {
+        return ObjectInstancesManager.WEAK_REFERENCE.equals(referenceType) ||
+                ObjectInstancesManager.JNI_WEAK_REFERENCE.equals(referenceType) ||
+                ObjectInstancesManager.PHANTOM_REFERENCE.equals(referenceType) ||
+                ObjectInstancesManager.SOFT_REFERENCE.equals(referenceType);
+
+    }
 }
--- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebuggee.java	Thu Nov 15 09:45:18 2018 +0100
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/HeapwalkingDebuggee.java	Thu Nov 15 09:56:49 2018 -0800
@@ -197,6 +197,21 @@
         if (className.equals("byte[]"))
             return false;
 
+        if (className.equals("boolean[]"))
+            return false;
+
+        if (className.equals("float[]"))
+            return false;
+
+        if (className.equals("long[]"))
+            return false;
+
+        if (className.equals("int[]"))
+            return false;
+
+        if (className.equals("double[]"))
+            return false;
+
         if (className.equals("java.lang.Thread")) {
             if (otherThreadPresent)
                 return false;