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 5024119
  27  *  @summary Add ReferenceType.getAllInstances () method to JDI.
  28  *  @author jjh
  29  *
  30  *  @modules jdk.jdi
  31  *  @run build TestScaffold VMConnection TargetListener TargetAdapter
  32  *  @run compile -g InstancesTest.java
  33  *  @run driver InstancesTest
  34  */
  35 
  36 /*
  37  *  To run this test do this:
  38  *     runregress -no InstancesTest <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 InstancesTest -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  * the debugger waits 20 secs, and then connects to the debuggee, suspends
  49  * it, and 'debugs' it.
  50  *
  51  * If <cmd line options> is not specified, then the InstancesTarg class below
  52  * is run as the debuggee.
  53  */
  54 import com.sun.jdi.*;
  55 import com.sun.jdi.event.*;
  56 import com.sun.jdi.request.*;
  57 
  58 import java.util.*;
  59 
  60 class InstancesFiller {
  61     // This many instances of this are created.
  62     static int FILLER_COUNT = 200000;
  63     static InstancesFiller[] lotsAndLots = new InstancesFiller[
  64                                                InstancesFiller.FILLER_COUNT];
  65     int xx;
  66     InstancesFiller(int p1) {
  67         xx = p1;
  68     }
  69 }
  70 
  71 class InstancesTarg {
  72     // This many instances + 1 of this class are created.
  73     static int TARG_COUNT = 1000;
  74     static InstancesTarg theInstancesTarg;
  75     static InstancesTarg[] allInstancesTargs;
  76 
  77     // Each instance will point to the theInstancesTarg
  78     InstancesTarg oneInstancesTarg;
  79 
  80     public static void bkpt() {
  81     }
  82 
  83     public static void main(String[] args) {
  84         System.out.println("Howdy!");
  85         for (int ii = 0; ii < InstancesFiller.lotsAndLots.length; ii++) {
  86             InstancesFiller.lotsAndLots[ii] = new InstancesFiller(ii);
  87         }
  88 
  89         theInstancesTarg = new InstancesTarg();
  90         allInstancesTargs = new InstancesTarg[InstancesTarg.TARG_COUNT];
  91         for (int ii = 0; ii < InstancesTarg.TARG_COUNT; ii++) {
  92             allInstancesTargs[ii] = new InstancesTarg();
  93             allInstancesTargs[ii].oneInstancesTarg = theInstancesTarg;
  94         }
  95         bkpt();
  96 
  97         System.out.println("Goodbye from InstancesTarg!");
  98     }
  99 }
 100 
 101 /********** test program **********/
 102 
 103 public class InstancesTest extends TestScaffold {
 104     static String targetName = "InstancesTarg";
 105     ReferenceType targetClass;
 106     ThreadReference mainThread;
 107 
 108     InstancesTest(String args[]) {
 109         super(args);
 110     }
 111 
 112     public static void main(String[] args) throws Exception {
 113         /*
 114          * If args contains @@xxxx, then that is the
 115          * name of the class we are to run.
 116          */
 117         for (int ii = 0; ii < args.length; ii ++) {
 118             if (args[ii].startsWith("@@")) {
 119                 targetName = args[ii] = args[ii].substring(2);
 120                 break;
 121             }
 122         }
 123         new InstancesTest(args).startTests();
 124     }
 125 
 126     /*
 127      * Used to sort a list of ReferenceTypes by
 128      * instance count.
 129      */
 130     class ToSort implements Comparable<ToSort> {
 131         long count;
 132         ReferenceType rt;
 133 
 134         public ToSort(long count, ReferenceType rt) {
 135             this.count = count;
 136             this.rt = rt;
 137         }
 138 
 139         public int compareTo(ToSort obj) {
 140             if (count < obj.count) return -1;
 141             if (count == obj.count) return 0;
 142             return 1;
 143         }
 144     }
 145 
 146     protected void runTests() throws Exception {
 147         /*
 148          * Get to the top of main()
 149          * to determine targetClass and mainThread
 150          */
 151         int CUT_OFF = 1000;
 152         BreakpointEvent bpe;
 153         bpe = startToMain(targetName);
 154         targetClass = bpe.location().declaringType();
 155         mainThread = bpe.thread();
 156 
 157         if (targetName.equals("InstancesTarg")) {
 158             resumeTo("InstancesTarg", "bkpt", "()V");
 159         } else {
 160             // Let debuggee run for awhile to get classes loaded
 161             vm().resume();
 162             try {
 163                 System.err.println("Press <enter> to continue");
 164                 System.in.read();
 165                 System.err.println("running...");
 166 
 167             } catch(Exception e) {
 168             }
 169             vm().suspend();
 170         }
 171 
 172         // Get all classes.
 173         long start = System.currentTimeMillis();
 174         List<ReferenceType> allClasses = vm().allClasses();
 175         long end = System.currentTimeMillis();
 176         System.out.println( allClasses.size() +
 177                             " classes from vm.allClasses() took " +
 178                             (end - start) + " ms");
 179 
 180         long[] counts;
 181 
 182         // Test for NPE
 183         {
 184             boolean pass = false;
 185             try {
 186                 counts = vm().instanceCounts(null);
 187             } catch (NullPointerException ee) {
 188                 pass = true;
 189             }
 190             if (!pass) {
 191                 failure("failure: NullPointerException not thrown on instanceCounts(null)");
 192             }
 193         }
 194 
 195         // Test for 0 length array
 196         {
 197             List<ReferenceType>someClasses = new ArrayList(2);
 198             counts = vm().instanceCounts(someClasses);
 199             if (counts.length != 0) {
 200                 failure("failure: instanceCounts with a zero length array fails: " +
 201                         counts.length);
 202             }
 203         }
 204 
 205         // Test various values of maxInstances
 206         if (targetClass.name().equals("InstancesTarg")) {
 207             List<ObjectReference> noInstances = targetClass.instances(0);
 208             if (noInstances.size() != InstancesTarg.TARG_COUNT + 1) {
 209                 failure("failure: instances(0): " + noInstances.size() + ", for " + targetClass);
 210             }
 211             noInstances = targetClass.instances(1);
 212             if (noInstances.size() != 1) {
 213                 failure("failure: instances(1): " + noInstances.size() + ", for " + targetClass);
 214             }
 215             boolean pass = false;
 216             try {
 217                 noInstances = targetClass.instances(-1);
 218             } catch (IllegalArgumentException ee) {
 219                 pass = true;
 220             }
 221             if (!pass) {
 222                 failure("failure: instances(-1) did not get an exception");
 223             }
 224         }
 225 
 226         // Instance counts for all classes
 227         start = System.currentTimeMillis();
 228         counts = vm().instanceCounts(allClasses);
 229         end = System.currentTimeMillis();
 230 
 231         if (counts.length == 0) {
 232             System.out.println("failure: No instances found");
 233             throw new Exception("InstancesTest: failed");
 234         }
 235 
 236         // Create a list of ReferenceTypes sorted by instance count
 237         int size = 0;
 238         List<ToSort> sorted = new ArrayList(allClasses.size());
 239         for (int ii = 0; ii < allClasses.size(); ii++) {
 240             System.out.println(counts[ii] + "   " + allClasses.get(ii));
 241             size += counts[ii];
 242             ToSort tos = new ToSort(counts[ii], allClasses.get(ii));
 243             sorted.add(tos);
 244         }
 245 
 246         System.out.println("instance counts for " + counts.length +
 247                            " classes got " + size + " instances and took " +
 248                             (end - start) + " ms");
 249 
 250 
 251         boolean gotInstancesFiller = false;
 252         boolean gotInstancesTarg = false;
 253 
 254         Collections.sort(sorted);
 255         for (int ii = sorted.size() - 1; ii >= 0 ; ii--) {
 256             ToSort xxx = sorted.get(ii);
 257             if (xxx.count <= CUT_OFF) {
 258                 break;
 259             }
 260             if (xxx.rt.name().equals("InstancesFiller") &&
 261                 xxx.count == InstancesFiller.FILLER_COUNT) {
 262                 gotInstancesFiller = true;
 263             }
 264             if (xxx.rt.name().equals("InstancesTarg") &&
 265                 xxx.count == InstancesTarg.TARG_COUNT + 1) {
 266                 gotInstancesTarg = true;
 267             }
 268         }
 269         if (!gotInstancesFiller) {
 270                 failure("failure: Expected " + InstancesFiller.FILLER_COUNT +
 271                         " instances of InstancesFiller");
 272         }
 273         if (!gotInstancesTarg) {
 274             failure("failure: Expected " + (InstancesTarg.TARG_COUNT + 1) +
 275                     " instances of InstancesTarg");
 276         }
 277 
 278         // Instances, one class at a time, in sorted order, printing each line
 279         if (true) {
 280             System.out.println("\nGetting instances for one class " +
 281                                "at a time (limited) in sorted order");
 282             List<ReferenceType> rtList = new ArrayList(1);
 283             rtList.add(null);
 284             long start1 = System.currentTimeMillis();
 285             size = 0;
 286             long count = 0;
 287             for (int ii = sorted.size() - 1; ii >= 0 ; ii--) {
 288                 ToSort xxx = sorted.get(ii);
 289                 if (xxx.count <= CUT_OFF) {
 290                     break;
 291                 }
 292                 rtList.set(0, xxx.rt);
 293                 start = System.currentTimeMillis();
 294                 List<ObjectReference> oneInstances = xxx.rt.instances(19999999);
 295                 end = System.currentTimeMillis();
 296                 size += oneInstances.size();
 297                 count++;
 298                 System.out.println("Expected " + xxx.count + " instances, got " +
 299                                    oneInstances.size() +
 300                                    " instances for " + sorted.get(ii).rt +
 301                                    " in " + (end - start) + " ms");
 302 
 303                 if (xxx.rt.name().equals("InstancesFiller") &&
 304                     oneInstances.size() != InstancesFiller.FILLER_COUNT) {
 305                     failure("failure: Expected " + InstancesFiller.FILLER_COUNT +
 306                             " instances of InstancesFiller");
 307                 }
 308                 if (xxx.rt.name().equals("InstancesTarg") &&
 309                     oneInstances.size() != InstancesTarg.TARG_COUNT + 1) {
 310                     failure("failure: Expected " + (InstancesTarg.TARG_COUNT + 1) +
 311                             " instances of InstancesTarg");
 312                 }
 313 
 314             }
 315 
 316             end = System.currentTimeMillis();
 317 
 318             System.out.println(size + " instances via making one vm.instances" +
 319                                " call for each of " + count +
 320                                " classes took " + (end - start1) + " ms");
 321             System.out.println("Per class = " +
 322                                (end - start) / allClasses.size() + " ms");
 323         }
 324 
 325         /*
 326          * deal with results of test
 327          * if anything has called failure("foo") testFailed will be true
 328          */
 329         if (!testFailed) {
 330             println("InstancesTest: passed");
 331         } else {
 332             throw new Exception("InstancesTest: failed");
 333         }
 334     }
 335 }