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