1 /* 2 * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package gc.shenandoah; 25 26 /* @test id=satb 27 * @requires vm.gc.Shenandoah 28 * @library /test/lib 29 * @build jdk.test.whitebox.WhiteBox 30 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 31 * @run main/othervm 32 * -Xbootclasspath/a:. 33 * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 34 * -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=satb 35 * gc.shenandoah.TestReferenceRefersToShenandoah 36 */ 37 38 /* @test id=satb-100 39 * @requires vm.gc.Shenandoah 40 * @library /test/lib 41 * @build jdk.test.whitebox.WhiteBox 42 * @modules java.base 43 * @run main jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 44 * @run main/othervm 45 * -Xbootclasspath/a:. 46 * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 47 * -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=satb -XX:ShenandoahGarbageThreshold=100 -Xmx100m 48 * gc.shenandoah.TestReferenceRefersToShenandoah 49 */ 50 51 /* @test id=generational 52 * @requires vm.gc.Shenandoah 53 * @library /test/lib 54 * @build jdk.test.whitebox.WhiteBox 55 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 56 * @run main/othervm 57 * -Xbootclasspath/a:. 58 * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 59 * -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational 60 * gc.shenandoah.TestReferenceRefersToShenandoah 61 */ 62 63 /* @test id=generational-100 64 * @requires vm.gc.Shenandoah 65 * @library /test/lib 66 * @build jdk.test.whitebox.WhiteBox 67 * @modules java.base 68 * @run main jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 69 * @run main/othervm 70 * -Xbootclasspath/a:. 71 * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 72 * -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -XX:ShenandoahGarbageThreshold=100 -Xmx100m 73 * gc.shenandoah.TestReferenceRefersToShenandoah 74 */ 75 76 /* @test id=iu 77 * @requires vm.gc.Shenandoah 78 * @library /test/lib 79 * @build jdk.test.whitebox.WhiteBox 80 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 81 * @run main/othervm 82 * -Xbootclasspath/a:. 83 * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 84 * -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu 85 * gc.shenandoah.TestReferenceRefersToShenandoah 86 */ 87 88 /* @test id=iu-100 89 * @requires vm.gc.Shenandoah 90 * @library /test/lib 91 * @build jdk.test.whitebox.WhiteBox 92 * @modules java.base 93 * @run main jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 94 * @run main/othervm 95 * -Xbootclasspath/a:. 96 * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 97 * -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGarbageThreshold=100 -Xmx100m 98 * gc.shenandoah.TestReferenceRefersToShenandoah 99 */ 100 101 import java.lang.ref.PhantomReference; 102 import java.lang.ref.Reference; 103 import java.lang.ref.ReferenceQueue; 104 import java.lang.ref.WeakReference; 105 import jdk.test.whitebox.WhiteBox; 106 107 public class TestReferenceRefersToShenandoah { 108 private static final WhiteBox WB = WhiteBox.getWhiteBox(); 109 110 private static final class TestObject { 111 public final int value; 112 113 public TestObject(int value) { 114 this.value = value; 115 } 116 } 117 118 private static volatile TestObject testObjectNone = null; 119 private static volatile TestObject testObject1 = null; 120 private static volatile TestObject testObject2 = null; 121 private static volatile TestObject testObject3 = null; 122 private static volatile TestObject testObject4 = null; 123 124 private static ReferenceQueue<TestObject> queue = null; 125 126 private static PhantomReference<TestObject> testPhantom1 = null; 127 128 private static WeakReference<TestObject> testWeak2 = null; 129 private static WeakReference<TestObject> testWeak3 = null; 130 private static WeakReference<TestObject> testWeak4 = null; 131 132 private static void setup() { 133 testObjectNone = new TestObject(0); 134 testObject1 = new TestObject(1); 135 testObject2 = new TestObject(2); 136 testObject3 = new TestObject(3); 137 testObject4 = new TestObject(4); 138 139 queue = new ReferenceQueue<TestObject>(); 140 141 testPhantom1 = new PhantomReference<TestObject>(testObject1, queue); 142 143 testWeak2 = new WeakReference<TestObject>(testObject2, queue); 144 testWeak3 = new WeakReference<TestObject>(testObject3, queue); 145 testWeak4 = new WeakReference<TestObject>(testObject4, queue); 146 } 147 148 private static void gcUntilOld(Object o) throws Exception { 149 if (!WB.isObjectInOldGen(o)) { 150 WB.fullGC(); 151 if (!WB.isObjectInOldGen(o)) { 152 // This is just a warning, because failing would 153 // be overspecifying for generational shenandoah, 154 // which need not necessarily promote objects upon 155 // a full GC. 156 warn("object not promoted by full gc"); 157 } 158 } 159 } 160 161 private static void gcUntilOld() throws Exception { 162 gcUntilOld(testObjectNone); 163 gcUntilOld(testObject1); 164 gcUntilOld(testObject2); 165 gcUntilOld(testObject3); 166 gcUntilOld(testObject4); 167 168 gcUntilOld(testPhantom1); 169 170 gcUntilOld(testWeak2); 171 gcUntilOld(testWeak3); 172 gcUntilOld(testWeak4); 173 } 174 175 private static void progress(String msg) { 176 System.out.println(msg); 177 } 178 179 private static void fail(String msg) throws Exception { 180 throw new RuntimeException(msg); 181 } 182 183 private static void warn(String msg) { 184 System.out.println("Warning: " + msg); 185 } 186 187 private static void expectCleared(Reference<TestObject> ref, 188 String which) throws Exception { 189 expectNotValue(ref, testObjectNone, which); 190 if (!ref.refersTo(null)) { 191 fail("expected " + which + " to be cleared"); 192 } 193 } 194 195 private static void expectNotCleared(Reference<TestObject> ref, 196 String which) throws Exception { 197 expectNotValue(ref, testObjectNone, which); 198 if (ref.refersTo(null)) { 199 fail("expected " + which + " to not be cleared"); 200 } 201 } 202 203 private static void expectValue(Reference<TestObject> ref, 204 TestObject value, 205 String which) throws Exception { 206 expectNotValue(ref, testObjectNone, which); 207 expectNotCleared(ref, which); 208 if (!ref.refersTo(value)) { 209 fail(which + " doesn't refer to expected value"); 210 } 211 } 212 213 private static void expectNotValue(Reference<TestObject> ref, 214 TestObject value, 215 String which) throws Exception { 216 if (ref.refersTo(value)) { 217 fail(which + " refers to unexpected value"); 218 } 219 } 220 221 private static void checkInitialStates() throws Exception { 222 expectValue(testPhantom1, testObject1, "testPhantom1"); 223 expectValue(testWeak2, testObject2, "testWeak2"); 224 expectValue(testWeak3, testObject3, "testWeak3"); 225 expectValue(testWeak4, testObject4, "testWeak4"); 226 } 227 228 private static void discardStrongReferences() { 229 // testObjectNone not dropped 230 testObject1 = null; 231 testObject2 = null; 232 // testObject3 not dropped 233 testObject4 = null; 234 } 235 236 private static boolean isShenandoahIUMode() { 237 return "iu".equals(WB.getStringVMFlag("ShenandoahGCMode")); 238 } 239 240 private static void testConcurrentCollection() throws Exception { 241 progress("setup concurrent collection test"); 242 setup(); 243 progress("gcUntilOld"); 244 gcUntilOld(); 245 246 progress("acquire control of concurrent cycles"); 247 WB.concurrentGCAcquireControl(); 248 try { 249 progress("check initial states"); 250 checkInitialStates(); 251 252 progress("discard strong references"); 253 discardStrongReferences(); 254 255 progress("run GC to before marking completed"); 256 WB.concurrentGCRunTo(WB.BEFORE_MARKING_COMPLETED); 257 258 progress("fetch test objects, possibly keeping some alive"); 259 expectNotCleared(testPhantom1, "testPhantom1"); 260 expectNotCleared(testWeak2, "testWeak2"); 261 expectValue(testWeak3, testObject3, "testWeak3"); 262 263 // For some collectors, calling get() will keep testObject4 alive. 264 if (testWeak4.get() == null) { 265 fail("testWeak4 unexpectedly == null"); 266 } 267 268 progress("finish collection"); 269 WB.concurrentGCRunToIdle(); 270 271 progress("verify expected clears"); 272 expectCleared(testPhantom1, "testPhantom1"); 273 expectCleared(testWeak2, "testWeak2"); 274 expectValue(testWeak3, testObject3, "testWeak3"); 275 // This is true for all currently supported concurrent collectors, 276 // except Shenandoah+IU, which allows clearing refs even when 277 // accessed during concurrent marking. 278 if (isShenandoahIUMode()) { 279 expectCleared(testWeak4, "testWeak4"); 280 } else { 281 expectNotCleared(testWeak4, "testWeak4"); 282 } 283 284 progress("verify get returns expected values"); 285 if (testWeak2.get() != null) { 286 fail("testWeak2.get() != null"); 287 } 288 289 TestObject obj3 = testWeak3.get(); 290 if (obj3 == null) { 291 fail("testWeak3.get() returned null"); 292 } else if (obj3.value != 3) { 293 fail("testWeak3.get().value is " + obj3.value); 294 } 295 296 TestObject obj4 = testWeak4.get(); 297 if (!isShenandoahIUMode()) { 298 if (obj4 == null) { 299 fail("testWeak4.get() returned null"); 300 } else if (obj4.value != 4) { 301 fail("testWeak4.get().value is " + obj4.value); 302 } 303 } 304 305 progress("verify queue entries"); 306 long timeout = 60000; // 1 minute of milliseconds. 307 while (true) { 308 Reference<? extends TestObject> ref = queue.remove(timeout); 309 if (ref == null) { 310 break; 311 } else if (ref == testPhantom1) { 312 testPhantom1 = null; 313 } else if (ref == testWeak2) { 314 testWeak2 = null; 315 } else if (ref == testWeak3) { 316 testWeak3 = null; 317 } else if (ref == testWeak4) { 318 testWeak4 = null; 319 } else { 320 fail("unexpected reference in queue"); 321 } 322 } 323 if (testPhantom1 != null) { 324 fail("testPhantom1 not notified"); 325 } else if (testWeak2 != null) { 326 fail("testWeak2 not notified"); 327 } else if (testWeak3 == null) { 328 fail("testWeak3 notified"); 329 } else if (testWeak4 == null) { 330 if (obj4 != null) { 331 fail("testWeak4 notified"); 332 } 333 } 334 335 } finally { 336 progress("release control of concurrent cycles"); 337 WB.concurrentGCReleaseControl(); 338 } 339 progress("finished concurrent collection test"); 340 } 341 342 private static void testSimpleCollection() throws Exception { 343 progress("setup simple collection test"); 344 setup(); 345 progress("gcUntilOld"); 346 gcUntilOld(); 347 348 progress("check initial states"); 349 checkInitialStates(); 350 351 progress("discard strong references"); 352 TestObject tw4 = testWeak4.get(); // Keep testObject4 alive. 353 discardStrongReferences(); 354 355 progress("collect garbage"); 356 WB.fullGC(); 357 358 progress("verify expected clears"); 359 expectCleared(testPhantom1, "testPhantom1"); 360 expectCleared(testWeak2, "testWeak2"); 361 expectValue(testWeak3, testObject3, "testWeak3"); 362 expectNotCleared(testWeak4, "testWeak4"); 363 364 progress("verify get returns expected values"); 365 if (testWeak2.get() != null) { 366 fail("testWeak2.get() != null"); 367 } else if (testWeak3.get() != testObject3) { 368 fail("testWeak3.get() is not expected value"); 369 } else if (testWeak4.get() != tw4) { 370 fail("testWeak4.get() is not expected value"); 371 } 372 373 progress("finished simple collection test"); 374 } 375 376 public static void main(String[] args) throws Exception { 377 if (WB.supportsConcurrentGCBreakpoints()) { 378 testConcurrentCollection(); 379 } 380 testSimpleCollection(); 381 } 382 }