1 /* 2 * Copyright (c) 2005, 2015, 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 /** 25 * @test 26 * @bug 5089849 27 * @summary Add support for backtracking reference graph. 28 * @author jjh 29 * 30 * @modules jdk.jdi 31 * @run build TestScaffold VMConnection TargetListener TargetAdapter 32 * @run compile -g ReferrersTest.java 33 * @run driver ReferrersTest 34 */ 35 36 /* 37 * To run this test do this: 38 * runregress -no ReferrersTest <cmd line options> 39 * 40 * where <cmd line options> are the options to be used to 41 * launch the debuggee, with the classname prefixed with @@. 42 * For example, this would run java2d demo as the debuggee: 43 * runregress -no ReferrersTest -classpath 44 * $jdkDir/demo/jfc/Java2D/Java2Demo.jar \ 45 * -client @@java2d.Java2Demo 46 * 47 * In this mode, the specified debuggee is launched in debug mode, 48 * and the debugger waits for a keystroke before connecting to the debuggee. 49 * 50 * If <cmd line options> is not specified, then the ReferrersTarg class below 51 * is run as the debuggee. 52 */ 53 import com.sun.jdi.*; 54 import com.sun.jdi.event.*; 55 import com.sun.jdi.request.*; 56 57 import java.util.*; 58 59 class ReferrersFiller { 60 // This many instances of this are created. 61 static int FILLER_COUNT = 20000; 62 static ReferrersFiller[] lotsAndLots = new ReferrersFiller[ 63 ReferrersFiller.FILLER_COUNT]; 64 int xx; 65 ReferrersFiller(int p1) { 66 xx = p1; 67 } 68 } 69 70 class ReferrersTarg { 71 // This many instances + 1 of this class are created. 72 static int TARG_COUNT = 10; 73 static ReferrersTarg theReferrersTarg; 74 static ReferrersTarg[] allReferrersTargs; 75 76 // Each instance will point to the theReferrersTarg 77 ReferrersTarg oneReferrersTarg; 78 79 public static void bkpt() { 80 } 81 82 public static void main(String[] args) { 83 System.out.println("Howdy!"); 84 for (int ii = 0; ii < ReferrersFiller.lotsAndLots.length; ii++) { 85 ReferrersFiller.lotsAndLots[ii] = new ReferrersFiller(ii); 86 } 87 88 theReferrersTarg = new ReferrersTarg(); 89 allReferrersTargs = new ReferrersTarg[ReferrersTarg.TARG_COUNT]; 90 for (int ii = 0; ii < ReferrersTarg.TARG_COUNT; ii++) { 91 allReferrersTargs[ii] = new ReferrersTarg(); 92 allReferrersTargs[ii].oneReferrersTarg = theReferrersTarg; 93 } 94 bkpt(); 95 96 System.out.println("Goodbye from ReferrersTarg!"); 97 } 98 } 99 100 /********** test program **********/ 101 102 public class ReferrersTest extends TestScaffold { 103 static String targetName = "ReferrersTarg"; 104 ReferenceType targetClass; 105 ThreadReference mainThread; 106 107 ReferrersTest(String args[]) { 108 super(args); 109 } 110 111 public static void main(String[] args) throws Exception { 112 /* 113 * If args contains @@xxxx, then that is the 114 * name of the class we are to run. 115 */ 116 for (int ii = 0; ii < args.length; ii ++) { 117 if (args[ii].startsWith("@@")) { 118 targetName = args[ii] = args[ii].substring(2); 119 break; 120 } 121 } 122 new ReferrersTest(args).startTests(); 123 } 124 125 /* 126 * Used to sort a list of ReferenceTypes by 127 * instance count. 128 */ 129 class ToSort implements Comparable<ToSort> { 130 long count; 131 ReferenceType rt; 132 133 public ToSort(long count, ReferenceType rt) { 134 this.count = count; 135 this.rt = rt; 136 } 137 138 public int compareTo(ToSort obj) { 139 if (count < obj.count) return -1; 140 if (count == obj.count) return 0; 141 return 1; 142 } 143 } 144 145 protected void runTests() throws Exception { 146 /* 147 * Get to the top of main() 148 * to determine targetClass and mainThread 149 */ 150 int CUT_OFF = 1000; 151 BreakpointEvent bpe; 152 bpe = startToMain(targetName); 153 targetClass = bpe.location().declaringType(); 154 mainThread = bpe.thread(); 155 156 if (targetName.equals("ReferrersTarg")) { 157 resumeTo("ReferrersTarg", "bkpt", "()V"); 158 } else { 159 // Let debuggee run for awhile to get classes loaded 160 vm().resume(); 161 try { 162 System.err.println("Press <enter> to continue"); 163 System.in.read(); 164 System.err.println("running..."); 165 166 } catch(Exception e) { 167 } 168 vm().suspend(); 169 } 170 171 // Get all classes. 172 long start = System.currentTimeMillis(); 173 List<ReferenceType> allClasses = vm().allClasses(); 174 long end = System.currentTimeMillis(); 175 System.out.println( allClasses.size() + 176 " classes from vm.allClasses() took " + 177 (end - start) + " ms"); 178 179 long[] counts; 180 181 // Test for NPE 182 { 183 boolean pass = false; 184 try { 185 counts = vm().instanceCounts(null); 186 } catch (NullPointerException ee) { 187 pass = true; 188 } 189 if (!pass) { 190 failure("failure: NullPointerException not thrown on instanceCounts(null)"); 191 } 192 } 193 194 // Test for 0 length array 195 { 196 List<ReferenceType>someClasses = new ArrayList(2); 197 counts = vm().instanceCounts(someClasses); 198 if (counts.length != 0) { 199 failure("failure: instanceCounts with a zero length array fails: " + 200 counts.length); 201 } 202 } 203 204 // Test various values of maxInstances 205 if (targetClass.name().equals("ReferrersTarg")) { 206 List<ObjectReference> noInstances = targetClass.instances(0); 207 if (noInstances.size() != ReferrersTarg.TARG_COUNT + 1) { 208 failure("failure: instances(0): " + noInstances.size() + ", for " + targetClass); 209 } 210 noInstances = targetClass.instances(1); 211 if (noInstances.size() != 1) { 212 failure("failure: instances(1): " + noInstances.size() + ", for " + targetClass); 213 } 214 boolean pass = false; 215 try { 216 noInstances = targetClass.instances(-1); 217 } catch (IllegalArgumentException ee) { 218 pass = true; 219 } 220 if (!pass) { 221 failure("failure: instances(-1) did not get an exception"); 222 } 223 } 224 225 // Instance counts for all classes 226 start = System.currentTimeMillis(); 227 counts = vm().instanceCounts(allClasses); 228 end = System.currentTimeMillis(); 229 230 if (counts.length == 0) { 231 System.out.println("failure: No instances found"); 232 throw new Exception("ReferrersTest: failed"); 233 } 234 235 // Create a list of ReferenceTypes sorted by instance count 236 int size = 0; 237 List<ToSort> sorted = new ArrayList(allClasses.size()); 238 for (int ii = 0; ii < allClasses.size(); ii++) { 239 size += counts[ii]; 240 ToSort tos = new ToSort(counts[ii], allClasses.get(ii)); 241 sorted.add(tos); 242 } 243 244 System.out.println("instance counts for " + counts.length + 245 " classes got " + size + " instances and took " + 246 (end - start) + " ms"); 247 248 249 boolean gotReferrersFiller = false; 250 boolean gotReferrersTarg = false; 251 252 Collections.sort(sorted); 253 for (int ii = sorted.size() - 1; ii >= 0 ; ii--) { 254 ToSort xxx = sorted.get(ii); 255 256 if (xxx.rt.name().equals("ReferrersFiller") && 257 xxx.count == ReferrersFiller.FILLER_COUNT) { 258 gotReferrersFiller = true; 259 } 260 if (xxx.rt.name().equals("ReferrersTarg") && 261 xxx.count == ReferrersTarg.TARG_COUNT + 1) { 262 gotReferrersTarg = true; 263 } 264 } 265 if (!gotReferrersFiller) { 266 failure("failure: Expected " + ReferrersFiller.FILLER_COUNT + 267 " instances of ReferrersFiller"); 268 } 269 if (!gotReferrersTarg) { 270 failure("failure: Expected " + (ReferrersTarg.TARG_COUNT + 1) + 271 " instances of ReferrersTarg"); 272 } 273 274 List<List<ObjectReference>> allInstances = new ArrayList(10); 275 276 // Instances, one class at a time, in sorted order, printing each line 277 if (true) { 278 System.out.println("\nGetting instances for one class " + 279 "at a time (limited) in sorted order"); 280 List<ReferenceType> rtList = new ArrayList(1); 281 rtList.add(null); 282 long start1 = System.currentTimeMillis(); 283 size = 0; 284 long count = 0; 285 for (int ii = sorted.size() - 1; ii >= 0 ; ii--) { 286 ToSort xxx = sorted.get(ii); 287 if (xxx.count <= CUT_OFF) { 288 break; 289 } 290 rtList.set(0, xxx.rt); 291 start = System.currentTimeMillis(); 292 List<ObjectReference> oneInstances = xxx.rt.instances(19999999); 293 end = System.currentTimeMillis(); 294 size += oneInstances.size(); 295 count++; 296 System.out.println("Expected " + xxx.count + " instances, got " + 297 oneInstances.size() + 298 " instances for " + sorted.get(ii).rt + 299 " in " + (end - start) + " ms"); 300 301 if (xxx.rt.name().equals("ReferrersFiller") && 302 oneInstances.size() != ReferrersFiller.FILLER_COUNT) { 303 failure("failure: Expected " + ReferrersFiller.FILLER_COUNT + 304 " instances of ReferrersFiller"); 305 } 306 if (xxx.rt.name().equals("ReferrersTarg") && 307 oneInstances.size() != ReferrersTarg.TARG_COUNT + 1) { 308 failure("failure: Expected " + (ReferrersTarg.TARG_COUNT + 1) + 309 " instances of ReferrersTarg"); 310 } 311 allInstances.add(oneInstances); 312 } 313 314 end = System.currentTimeMillis(); 315 316 System.out.println(size + " instances via making one vm.instances" + 317 " call for each of " + count + 318 " classes took " + (end - start1) + " ms"); 319 System.out.println("Per class = " + 320 (end - start) / allClasses.size() + " ms"); 321 } 322 323 324 // referrers 325 326 // Test various values of maxReferrers 327 if (targetClass.name().equals("ReferrersTarg")) { 328 Field field1 = targetClass.fieldByName("theReferrersTarg"); 329 ObjectReference anInstance = (ObjectReference)targetClass.getValue(field1); 330 List<ObjectReference> noReferrers = anInstance.referringObjects(0); 331 if (noReferrers.size() != ReferrersTarg.TARG_COUNT + 1 ) { 332 failure("failure: referringObjects(0) got " + noReferrers.size() + 333 ", for " + anInstance); 334 } 335 noReferrers = anInstance.referringObjects(1); 336 if (noReferrers.size() != 1 ) { 337 failure("failure: referringObjects(1) got " + noReferrers.size() + 338 ", for " + anInstance); 339 } 340 boolean pass = false; 341 try { 342 noReferrers = anInstance.referringObjects(-1); 343 } catch (IllegalArgumentException ee) { 344 pass = true; 345 } 346 if (!pass) { 347 failure("failure: referringObjects(-1) did not get an exception"); 348 } 349 } 350 351 List<ObjectReference> allReferrers = null; 352 List<ObjectReference> someInstances = new ArrayList(); 353 if (targetName.equals("ReferrersTarg")) { 354 Field field1 = targetClass.fieldByName("theReferrersTarg"); 355 ObjectReference val = (ObjectReference)targetClass.getValue(field1); 356 someInstances.add(val); 357 allReferrers = val.referringObjects(99999); //LIMIT 358 if (allReferrers.size() != ReferrersTarg.TARG_COUNT + 1) { 359 failure("failure: expected " + (ReferrersTarg.TARG_COUNT + 1) + 360 "referrers, but got " + allReferrers.size() + 361 " referrers for " + val); 362 } 363 } else { 364 // referrers 365 // Create someInstances to find the referrers of. 366 for (int ii = 0; ii < allClasses.size(); ii++) { 367 List<ObjectReference> objRefList = allInstances.get(ii); 368 if (objRefList != null) { 369 int asize = objRefList.size(); 370 if (false) { 371 System.out.println(asize + ", " + allClasses.get(ii)); 372 } 373 // Remember one instance per class to get referrers 374 if (asize > 0) { 375 someInstances.add(objRefList.get(0)); 376 } 377 } 378 } 379 } 380 381 for (ObjectReference objRef: someInstances) { 382 //System.out.println( "Getting referrers for " + objRef); 383 start = System.currentTimeMillis(); 384 if ( true) { 385 showReferrers(objRef, 0, 0, 0); 386 } else { 387 allReferrers = objRef.referringObjects(99999); //LIMIT 388 end = System.currentTimeMillis(); 389 if (true || allReferrers.size() > 1) { 390 System.out.println( allReferrers.size() + " referrers for " + objRef + " took " + (end - start) + " ms"); 391 } 392 } 393 } 394 395 /* 396 * deal with results of test 397 * if anything has called failure("foo") testFailed will be true 398 */ 399 if (!testFailed) { 400 println("ReferrersTest: passed"); 401 } else { 402 throw new Exception("ReferrersTest: failed"); 403 } 404 } 405 void indent(int level) { 406 for (int ii = 0; ii < level; ii++) { 407 System.out.print(" "); 408 } 409 } 410 411 412 Map<ObjectReference, Object> visited = new HashMap(100); 413 void showReferrers(ObjectReference objRef, int level, int total, int which) { 414 415 if (level == 0) { 416 visited.clear(); 417 } else { 418 if (visited.containsKey(objRef)) { 419 indent(level); 420 System.out.println("(" + which + ")" + ":<pruned> " + objRef); 421 return; 422 } 423 visited.put(objRef, null); 424 indent(level); 425 //System.out.println(which + "/" + total + ": " + objRef + " took " + time + " ms"); 426 } 427 428 List<ObjectReference> allReferrers = null; 429 430 //System.out.println( "Getting referrers for " + objRef); 431 long start, end; 432 start = System.currentTimeMillis(); 433 allReferrers = objRef.referringObjects(99999); //LIMIT 434 end = System.currentTimeMillis(); 435 436 if (which == 0) { 437 System.out.println(allReferrers.size() + " referrers for " + objRef + " took " + (end - start) + " ms"); 438 } else { 439 System.out.println("(" + which + ") " + objRef); 440 indent(level); 441 System.out.println(" " + allReferrers.size() + " referrers for " + objRef + " took " + (end - start) + " ms"); 442 } 443 444 // We have to stop going up a referrer chain in some cases 445 Type rt = objRef.type(); 446 if (rt instanceof ClassType) { 447 ClassType ct = (ClassType)rt; 448 String name = ct.name(); 449 if (name.equals("sun.awt.SoftCache$ValueCell")) { 450 return; 451 } 452 if (name.equals("java.lang.ref.Finalizer")) { 453 return; 454 } 455 if (name.equals("java.lang.ref.SoftReference")) { 456 return; 457 } 458 // oh oh, should really check for a subclass of ClassLoader :-) 459 if (name.indexOf("ClassLoader") >= 0) { 460 return; 461 } 462 // No doubt there are other reasons to stop ... 463 } 464 int itemNumber = 1; 465 int allSize = allReferrers.size(); 466 for (ObjectReference objx: allReferrers) { 467 showReferrers(objx, level + 1, allSize, itemNumber++); 468 } 469 } 470 }