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 import java.lang.ref.PhantomReference; 77 import java.lang.ref.Reference; 78 import java.lang.ref.ReferenceQueue; 79 import java.lang.ref.WeakReference; 80 import jdk.test.whitebox.WhiteBox; 81 82 public class TestReferenceRefersToShenandoah { 83 private static final WhiteBox WB = WhiteBox.getWhiteBox(); 84 85 private static final class TestObject { 86 public final int value; 87 88 public TestObject(int value) { 89 this.value = value; 90 } 91 } 92 93 private static volatile TestObject testObjectNone = null; 94 private static volatile TestObject testObject1 = null; 95 private static volatile TestObject testObject2 = null; 96 private static volatile TestObject testObject3 = null; 97 private static volatile TestObject testObject4 = null; 98 99 private static ReferenceQueue<TestObject> queue = null; 100 101 private static PhantomReference<TestObject> testPhantom1 = null; 102 103 private static WeakReference<TestObject> testWeak2 = null; 104 private static WeakReference<TestObject> testWeak3 = null; 105 private static WeakReference<TestObject> testWeak4 = null; 106 107 private static void setup() { 108 testObjectNone = new TestObject(0); 109 testObject1 = new TestObject(1); 110 testObject2 = new TestObject(2); 111 testObject3 = new TestObject(3); 112 testObject4 = new TestObject(4); 113 114 queue = new ReferenceQueue<TestObject>(); 115 116 testPhantom1 = new PhantomReference<TestObject>(testObject1, queue); 117 118 testWeak2 = new WeakReference<TestObject>(testObject2, queue); 119 testWeak3 = new WeakReference<TestObject>(testObject3, queue); 120 testWeak4 = new WeakReference<TestObject>(testObject4, queue); 121 } 122 123 private static void gcUntilOld(Object o) throws Exception { 124 if (!WB.isObjectInOldGen(o)) { 125 WB.fullGC(); 126 if (!WB.isObjectInOldGen(o)) { 127 // This is just a warning, because failing would 128 // be overspecifying for generational shenandoah, 129 // which need not necessarily promote objects upon 130 // a full GC. 131 warn("object not promoted by full gc"); 132 } 133 } 134 } 135 136 private static void gcUntilOld() throws Exception { 137 gcUntilOld(testObjectNone); 138 gcUntilOld(testObject1); 139 gcUntilOld(testObject2); 140 gcUntilOld(testObject3); 141 gcUntilOld(testObject4); 142 143 gcUntilOld(testPhantom1); 144 145 gcUntilOld(testWeak2); 146 gcUntilOld(testWeak3); 147 gcUntilOld(testWeak4); 148 } 149 150 private static void progress(String msg) { 151 System.out.println(msg); 152 } 153 154 private static void fail(String msg) throws Exception { 155 throw new RuntimeException(msg); 156 } 157 158 private static void warn(String msg) { 159 System.out.println("Warning: " + msg); 160 } 161 162 private static void expectCleared(Reference<TestObject> ref, 163 String which) throws Exception { 164 expectNotValue(ref, testObjectNone, which); 165 if (!ref.refersTo(null)) { 166 fail("expected " + which + " to be cleared"); 167 } 168 } 169 170 private static void expectNotCleared(Reference<TestObject> ref, 171 String which) throws Exception { 172 expectNotValue(ref, testObjectNone, which); 173 if (ref.refersTo(null)) { 174 fail("expected " + which + " to not be cleared"); 175 } 176 } 177 178 private static void expectValue(Reference<TestObject> ref, 179 TestObject value, 180 String which) throws Exception { 181 expectNotValue(ref, testObjectNone, which); 182 expectNotCleared(ref, which); 183 if (!ref.refersTo(value)) { 184 fail(which + " doesn't refer to expected value"); 185 } 186 } 187 188 private static void expectNotValue(Reference<TestObject> ref, 189 TestObject value, 190 String which) throws Exception { 191 if (ref.refersTo(value)) { 192 fail(which + " refers to unexpected value"); 193 } 194 } 195 196 private static void checkInitialStates() throws Exception { 197 expectValue(testPhantom1, testObject1, "testPhantom1"); 198 expectValue(testWeak2, testObject2, "testWeak2"); 199 expectValue(testWeak3, testObject3, "testWeak3"); 200 expectValue(testWeak4, testObject4, "testWeak4"); 201 } 202 203 private static void discardStrongReferences() { 204 // testObjectNone not dropped 205 testObject1 = null; 206 testObject2 = null; 207 // testObject3 not dropped 208 testObject4 = null; 209 } 210 211 private static void testConcurrentCollection() throws Exception { 212 progress("setup concurrent collection test"); 213 setup(); 214 progress("gcUntilOld"); 215 gcUntilOld(); 216 217 progress("acquire control of concurrent cycles"); 218 WB.concurrentGCAcquireControl(); 219 try { 220 progress("check initial states"); 221 checkInitialStates(); 222 223 progress("discard strong references"); 224 discardStrongReferences(); 225 226 progress("run GC to before marking completed"); 227 WB.concurrentGCRunTo(WB.BEFORE_MARKING_COMPLETED); 228 229 progress("fetch test objects, possibly keeping some alive"); 230 expectNotCleared(testPhantom1, "testPhantom1"); 231 expectNotCleared(testWeak2, "testWeak2"); 232 expectValue(testWeak3, testObject3, "testWeak3"); 233 234 // For some collectors, calling get() will keep testObject4 alive. 235 if (testWeak4.get() == null) { 236 fail("testWeak4 unexpectedly == null"); 237 } 238 239 progress("finish collection"); 240 WB.concurrentGCRunToIdle(); 241 242 progress("verify expected clears"); 243 expectCleared(testPhantom1, "testPhantom1"); 244 expectCleared(testWeak2, "testWeak2"); 245 expectValue(testWeak3, testObject3, "testWeak3"); 246 expectNotCleared(testWeak4, "testWeak4"); 247 248 progress("verify get returns expected values"); 249 if (testWeak2.get() != null) { 250 fail("testWeak2.get() != null"); 251 } 252 253 TestObject obj3 = testWeak3.get(); 254 if (obj3 == null) { 255 fail("testWeak3.get() returned null"); 256 } else if (obj3.value != 3) { 257 fail("testWeak3.get().value is " + obj3.value); 258 } 259 260 TestObject obj4 = testWeak4.get(); 261 if (obj4 == null) { 262 fail("testWeak4.get() returned null"); 263 } else if (obj4.value != 4) { 264 fail("testWeak4.get().value is " + obj4.value); 265 } 266 267 progress("verify queue entries"); 268 long timeout = 60000; // 1 minute of milliseconds. 269 while (true) { 270 Reference<? extends TestObject> ref = queue.remove(timeout); 271 if (ref == null) { 272 break; 273 } else if (ref == testPhantom1) { 274 testPhantom1 = null; 275 } else if (ref == testWeak2) { 276 testWeak2 = null; 277 } else if (ref == testWeak3) { 278 testWeak3 = null; 279 } else if (ref == testWeak4) { 280 testWeak4 = null; 281 } else { 282 fail("unexpected reference in queue"); 283 } 284 } 285 if (testPhantom1 != null) { 286 fail("testPhantom1 not notified"); 287 } else if (testWeak2 != null) { 288 fail("testWeak2 not notified"); 289 } else if (testWeak3 == null) { 290 fail("testWeak3 notified"); 291 } else if (testWeak4 == null) { 292 if (obj4 != null) { 293 fail("testWeak4 notified"); 294 } 295 } 296 297 } finally { 298 progress("release control of concurrent cycles"); 299 WB.concurrentGCReleaseControl(); 300 } 301 progress("finished concurrent collection test"); 302 } 303 304 private static void testSimpleCollection() throws Exception { 305 progress("setup simple collection test"); 306 setup(); 307 progress("gcUntilOld"); 308 gcUntilOld(); 309 310 progress("check initial states"); 311 checkInitialStates(); 312 313 progress("discard strong references"); 314 TestObject tw4 = testWeak4.get(); // Keep testObject4 alive. 315 discardStrongReferences(); 316 317 progress("collect garbage"); 318 WB.fullGC(); 319 320 progress("verify expected clears"); 321 expectCleared(testPhantom1, "testPhantom1"); 322 expectCleared(testWeak2, "testWeak2"); 323 expectValue(testWeak3, testObject3, "testWeak3"); 324 expectNotCleared(testWeak4, "testWeak4"); 325 326 progress("verify get returns expected values"); 327 if (testWeak2.get() != null) { 328 fail("testWeak2.get() != null"); 329 } else if (testWeak3.get() != testObject3) { 330 fail("testWeak3.get() is not expected value"); 331 } else if (testWeak4.get() != tw4) { 332 fail("testWeak4.get() is not expected value"); 333 } 334 335 progress("finished simple collection test"); 336 } 337 338 public static void main(String[] args) throws Exception { 339 if (WB.supportsConcurrentGCBreakpoints()) { 340 testConcurrentCollection(); 341 } 342 testSimpleCollection(); 343 } 344 }