1 /* 2 * Copyright (c) 2020, 2022, 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=iu 39 * @requires vm.gc.Shenandoah 40 * @library /test/lib 41 * @build jdk.test.whitebox.WhiteBox 42 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 43 * @run main/othervm 44 * -Xbootclasspath/a:. 45 * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 46 * -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu 47 * gc.shenandoah.TestReferenceRefersToShenandoah 48 */ 49 50 /* @test id=satb-100 51 * @requires vm.gc.Shenandoah 52 * @library /test/lib 53 * @build jdk.test.whitebox.WhiteBox 54 * @modules java.base 55 * @run main 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=satb -XX:ShenandoahGarbageThreshold=100 -Xmx100m 60 * gc.shenandoah.TestReferenceRefersToShenandoah 61 */ 62 63 /* @test id=iu-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=iu -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 fail("object not promoted by full gc"); 128 } 129 } 130 } 131 132 private static void gcUntilOld() throws Exception { 133 gcUntilOld(testObjectNone); 134 gcUntilOld(testObject1); 135 gcUntilOld(testObject2); 136 gcUntilOld(testObject3); 137 gcUntilOld(testObject4); 138 139 gcUntilOld(testPhantom1); 140 141 gcUntilOld(testWeak2); 142 gcUntilOld(testWeak3); 143 gcUntilOld(testWeak4); 144 } 145 146 private static void progress(String msg) { 147 System.out.println(msg); 148 } 149 150 private static void fail(String msg) throws Exception { 151 throw new RuntimeException(msg); 152 } 153 154 private static void expectCleared(Reference<TestObject> ref, 155 String which) throws Exception { 156 expectNotValue(ref, testObjectNone, which); 157 if (!ref.refersTo(null)) { 158 fail("expected " + which + " to be cleared"); 159 } 160 } 161 162 private static void expectNotCleared(Reference<TestObject> ref, 163 String which) throws Exception { 164 expectNotValue(ref, testObjectNone, which); 165 if (ref.refersTo(null)) { 166 fail("expected " + which + " to not be cleared"); 167 } 168 } 169 170 private static void expectValue(Reference<TestObject> ref, 171 TestObject value, 172 String which) throws Exception { 173 expectNotValue(ref, testObjectNone, which); 174 expectNotCleared(ref, which); 175 if (!ref.refersTo(value)) { 176 fail(which + " doesn't refer to expected value"); 177 } 178 } 179 180 private static void expectNotValue(Reference<TestObject> ref, 181 TestObject value, 182 String which) throws Exception { 183 if (ref.refersTo(value)) { 184 fail(which + " refers to unexpected value"); 185 } 186 } 187 188 private static void checkInitialStates() throws Exception { 189 expectValue(testPhantom1, testObject1, "testPhantom1"); 190 expectValue(testWeak2, testObject2, "testWeak2"); 191 expectValue(testWeak3, testObject3, "testWeak3"); 192 expectValue(testWeak4, testObject4, "testWeak4"); 193 } 194 195 private static void discardStrongReferences() { 196 // testObjectNone not dropped 197 testObject1 = null; 198 testObject2 = null; 199 // testObject3 not dropped 200 testObject4 = null; 201 } 202 203 private static boolean isShenandoahIUMode() { 204 return "iu".equals(WB.getStringVMFlag("ShenandoahGCMode")); 205 } 206 207 private static void testConcurrentCollection() throws Exception { 208 progress("setup concurrent collection test"); 209 setup(); 210 progress("gcUntilOld"); 211 gcUntilOld(); 212 213 progress("acquire control of concurrent cycles"); 214 WB.concurrentGCAcquireControl(); 215 try { 216 progress("check initial states"); 217 checkInitialStates(); 218 219 progress("discard strong references"); 220 discardStrongReferences(); 221 222 progress("run GC to before marking completed"); 223 WB.concurrentGCRunTo(WB.BEFORE_MARKING_COMPLETED); 224 225 progress("fetch test objects, possibly keeping some alive"); 226 expectNotCleared(testPhantom1, "testPhantom1"); 227 expectNotCleared(testWeak2, "testWeak2"); 228 expectValue(testWeak3, testObject3, "testWeak3"); 229 230 // For some collectors, calling get() will keep testObject4 alive. 231 if (testWeak4.get() == null) { 232 fail("testWeak4 unexpectedly == null"); 233 } 234 235 progress("finish collection"); 236 WB.concurrentGCRunToIdle(); 237 238 progress("verify expected clears"); 239 expectCleared(testPhantom1, "testPhantom1"); 240 expectCleared(testWeak2, "testWeak2"); 241 expectValue(testWeak3, testObject3, "testWeak3"); 242 // This is true for all currently supported concurrent collectors, 243 // except Shenandoah+IU, which allows clearing refs even when 244 // accessed during concurrent marking. 245 if (isShenandoahIUMode()) { 246 expectCleared(testWeak4, "testWeak4"); 247 } else { 248 expectNotCleared(testWeak4, "testWeak4"); 249 } 250 251 progress("verify get returns expected values"); 252 if (testWeak2.get() != null) { 253 fail("testWeak2.get() != null"); 254 } 255 256 TestObject obj3 = testWeak3.get(); 257 if (obj3 == null) { 258 fail("testWeak3.get() returned null"); 259 } else if (obj3.value != 3) { 260 fail("testWeak3.get().value is " + obj3.value); 261 } 262 263 TestObject obj4 = testWeak4.get(); 264 if (!isShenandoahIUMode()) { 265 if (obj4 == null) { 266 fail("testWeak4.get() returned null"); 267 } else if (obj4.value != 4) { 268 fail("testWeak4.get().value is " + obj4.value); 269 } 270 } 271 272 progress("verify queue entries"); 273 long timeout = 60000; // 1 minute of milliseconds. 274 while (true) { 275 Reference<? extends TestObject> ref = queue.remove(timeout); 276 if (ref == null) { 277 break; 278 } else if (ref == testPhantom1) { 279 testPhantom1 = null; 280 } else if (ref == testWeak2) { 281 testWeak2 = null; 282 } else if (ref == testWeak3) { 283 testWeak3 = null; 284 } else if (ref == testWeak4) { 285 testWeak4 = null; 286 } else { 287 fail("unexpected reference in queue"); 288 } 289 } 290 if (testPhantom1 != null) { 291 fail("testPhantom1 not notified"); 292 } else if (testWeak2 != null) { 293 fail("testWeak2 not notified"); 294 } else if (testWeak3 == null) { 295 fail("testWeak3 notified"); 296 } else if (testWeak4 == null) { 297 if (obj4 != null) { 298 fail("testWeak4 notified"); 299 } 300 } 301 302 } finally { 303 progress("release control of concurrent cycles"); 304 WB.concurrentGCReleaseControl(); 305 } 306 progress("finished concurrent collection test"); 307 } 308 309 private static void testSimpleCollection() throws Exception { 310 progress("setup simple collection test"); 311 setup(); 312 progress("gcUntilOld"); 313 gcUntilOld(); 314 315 progress("check initial states"); 316 checkInitialStates(); 317 318 progress("discard strong references"); 319 TestObject tw4 = testWeak4.get(); // Keep testObject4 alive. 320 discardStrongReferences(); 321 322 progress("collect garbage"); 323 WB.fullGC(); 324 325 progress("verify expected clears"); 326 expectCleared(testPhantom1, "testPhantom1"); 327 expectCleared(testWeak2, "testWeak2"); 328 expectValue(testWeak3, testObject3, "testWeak3"); 329 expectNotCleared(testWeak4, "testWeak4"); 330 331 progress("verify get returns expected values"); 332 if (testWeak2.get() != null) { 333 fail("testWeak2.get() != null"); 334 } else if (testWeak3.get() != testObject3) { 335 fail("testWeak3.get() is not expected value"); 336 } else if (testWeak4.get() != tw4) { 337 fail("testWeak4.get() is not expected value"); 338 } 339 340 progress("finished simple collection test"); 341 } 342 343 public static void main(String[] args) throws Exception { 344 if (WB.supportsConcurrentGCBreakpoints()) { 345 testConcurrentCollection(); 346 } 347 testSimpleCollection(); 348 } 349 }