1 /*
   2  * Copyright (c) 2006, 2018, 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 package nsk.share.jdi;
  24 
  25 import java.io.*;
  26 import java.util.*;
  27 import nsk.share.Log;
  28 import nsk.share.ObjectInstancesManager;
  29 import nsk.share.TestBug;
  30 import nsk.share.jpda.DebugeeArgumentHandler;
  31 import nsk.share.jpda.IOPipe;
  32 
  33 /*
  34  * Debuggee class used in tests for heapwalking(tests for VirtualMachine.instanceCounts, ReferenceType.instances, ObjectReference.referrers).
  35  * Handle commands related to creation of objects instances with given reference type
  36  * and given referrers number, use for this purposes nsk.share.ObjectInstancesManager.
  37  */
  38 public class HeapwalkingDebuggee extends AbstractJDIDebuggee {
  39     protected ObjectInstancesManager objectInstancesManager;
  40 
  41     // reference of this type should be included in ObjectReference.referringObjects
  42     public static Set<String> includedIntoReferrersCountTypes = new HashSet<String>();
  43 
  44     // reference of this type should be included in ReferenceType.instances
  45     public static Set<String> includedIntoInstancesCountTypes = new HashSet<String>();
  46 
  47     static {
  48         includedIntoInstancesCountTypes.add(ObjectInstancesManager.STRONG_REFERENCE);
  49         includedIntoInstancesCountTypes.add(ObjectInstancesManager.WEAK_REFERENCE);
  50         includedIntoInstancesCountTypes.add(ObjectInstancesManager.SOFT_REFERENCE);
  51         includedIntoInstancesCountTypes.add(ObjectInstancesManager.PHANTOM_REFERENCE);
  52         includedIntoInstancesCountTypes.add(ObjectInstancesManager.JNI_GLOBAL_REFERENCE);
  53         includedIntoInstancesCountTypes.add(ObjectInstancesManager.JNI_LOCAL_REFERENCE);
  54 
  55         includedIntoReferrersCountTypes.add(ObjectInstancesManager.STRONG_REFERENCE);
  56         includedIntoReferrersCountTypes.add(ObjectInstancesManager.WEAK_REFERENCE);
  57         includedIntoReferrersCountTypes.add(ObjectInstancesManager.SOFT_REFERENCE);
  58         includedIntoReferrersCountTypes.add(ObjectInstancesManager.PHANTOM_REFERENCE);
  59     }
  60 
  61     //create number instance of class with given name, command format: createInstances:class_name:instance_count[:referrer_count:referrer_type]
  62     static public final String COMMAND_CREATE_INSTANCES = "createInstances";
  63 
  64     //'delete'(make unreachable) number instance of class with given name, command format: deleteInstances:class_name:instance_count:referrer_count
  65     static public final String COMMAND_DELETE_INSTANCES = "deleteInstances";
  66 
  67     //delete number referrers
  68     static public final String COMMAND_DELETE_REFERRERS = "deleteReferrers";
  69 
  70     //create instance with all type referrers
  71     static public final String COMMAND_CREATE_ALL_TYPE_REFERENCES = "createAllTypeReferences";
  72 
  73     protected void init(String args[]) {
  74         super.init(args);
  75         objectInstancesManager = new ObjectInstancesManager(log);
  76     }
  77 
  78     public void initDebuggee(DebugeeArgumentHandler argHandler, Log log, IOPipe pipe, String args[], boolean callExit) {
  79         super.initDebuggee(argHandler, log, pipe, args, callExit);
  80         objectInstancesManager = new ObjectInstancesManager(log);
  81     }
  82 
  83     public boolean parseCommand(String command) {
  84         if (super.parseCommand(command))
  85             return true;
  86 
  87         try {
  88             StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(command));
  89             tokenizer.whitespaceChars(':', ':');
  90             tokenizer.wordChars('_', '_');
  91             tokenizer.wordChars('$', '$');
  92             tokenizer.wordChars('[', ']');
  93             tokenizer.wordChars('|', '|');
  94 
  95             if (command.startsWith(COMMAND_CREATE_INSTANCES)) {
  96                 //createInstances:class_name:instance_count[:referrer_count:referrer_type]
  97 
  98                 tokenizer.nextToken();
  99 
 100                 if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
 101                     throw new TestBug("Invalid command format: " + command);
 102 
 103                 String className = tokenizer.sval;
 104 
 105                 if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
 106                     throw new TestBug("Invalid command format: " + command);
 107 
 108                 int instanceCounts = (int) tokenizer.nval;
 109 
 110                 int referrerCount = 1;
 111                 Set<String> referrerType = new HashSet<String>();
 112 
 113                 if (tokenizer.nextToken() == StreamTokenizer.TT_NUMBER) {
 114                     referrerCount = (int) tokenizer.nval;
 115 
 116                     if (tokenizer.nextToken() == StreamTokenizer.TT_WORD)
 117                         referrerType.addAll(Arrays.asList(tokenizer.sval.split("\\|")));
 118                 }
 119                 if (referrerType.isEmpty()) {
 120                     referrerType.add(ObjectInstancesManager.STRONG_REFERENCE);
 121                 }
 122 
 123                 objectInstancesManager.createReferences(instanceCounts, className, referrerCount, referrerType);
 124 
 125                 return true;
 126             } else if (command.startsWith(COMMAND_DELETE_INSTANCES)) {
 127                 //deleteInstances:class_name:instance_count:referrer_count
 128 
 129                 tokenizer.nextToken();
 130 
 131                 if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
 132                     throw new TestBug("Invalid command format: " + command);
 133 
 134                 String className = tokenizer.sval;
 135 
 136                 if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
 137                     throw new TestBug("Invalid command format: " + command);
 138 
 139                 int instanceCounts = (int) tokenizer.nval;
 140 
 141                 objectInstancesManager.deleteAllReferrers(instanceCounts, className);
 142 
 143                 return true;
 144             } else if (command.startsWith(COMMAND_DELETE_REFERRERS)) {
 145                 tokenizer.nextToken();
 146 
 147                 if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
 148                     throw new TestBug("Invalid command format: " + command);
 149 
 150                 String className = tokenizer.sval;
 151 
 152                 if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
 153                     throw new TestBug("Invalid command format: " + command);
 154 
 155                 int referrersCount = (int) tokenizer.nval;
 156 
 157                 Set<String> referrerTypes = new HashSet<String>();
 158                 if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
 159                     referrerTypes.addAll(Arrays.asList(tokenizer.sval.split("\\|")));
 160                 }
 161 
 162                 objectInstancesManager.deleteReferrers(className, referrersCount, referrerTypes);
 163 
 164                 return true;
 165             } else if (command.startsWith(COMMAND_CREATE_ALL_TYPE_REFERENCES)) {
 166                 tokenizer.nextToken();
 167 
 168                 if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
 169                     throw new TestBug("Invalid command format: " + command);
 170 
 171                 String className = tokenizer.sval;
 172 
 173                 if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
 174                     throw new TestBug("Invalid command format: " + command);
 175 
 176                 int instanceCounts = (int) tokenizer.nval;
 177 
 178                 objectInstancesManager.createAllTypeReferences(className, instanceCounts);
 179 
 180                 return true;
 181             }
 182         } catch (IOException e) {
 183             throw new TestBug("Invalid command format: " + command);
 184         }
 185 
 186         return false;
 187     }
 188 
 189     // instances of some classes couldn't be strictly controlled during test execution, use non-strict checks for this classes
 190     public static boolean useStrictCheck(String className, boolean otherThreadPresent) {
 191         if (className.equals("java.lang.String"))
 192             return false;
 193 
 194         if (className.equals("char[]"))
 195             return false;
 196 
 197         if (className.equals("byte[]"))
 198             return false;
 199 
 200         if (className.equals("boolean[]"))
 201             return false;
 202 
 203         if (className.equals("float[]"))
 204             return false;
 205 
 206         if (className.equals("long[]"))
 207             return false;
 208 
 209         if (className.equals("int[]"))
 210             return false;
 211 
 212         if (className.equals("double[]"))
 213             return false;
 214 
 215         if (className.equals("java.lang.Thread")) {
 216             if (otherThreadPresent)
 217                 return false;
 218         }
 219 
 220         return true;
 221     }
 222 
 223     // is reference with given type should be included in ObjectReference.referringObjects
 224     static public boolean isIncludedIntoReferrersCount(String referenceType) {
 225         if (!ObjectInstancesManager.allReferenceTypes.contains(referenceType)) {
 226             throw new TestBug("Invalid reference type: " + referenceType);
 227         }
 228 
 229         return includedIntoReferrersCountTypes.contains(referenceType);
 230     }
 231 
 232     // is reference with given type should be included in ReferenceType.instances
 233     static public boolean isIncludedIntoInstancesCount(String referenceType) {
 234         if (!ObjectInstancesManager.allReferenceTypes.contains(referenceType)) {
 235             throw new TestBug("Invalid reference type: " + referenceType);
 236         }
 237 
 238         return includedIntoInstancesCountTypes.contains(referenceType);
 239     }
 240 
 241     public static void main(String args[]) {
 242         HeapwalkingDebuggee debuggee = new HeapwalkingDebuggee();
 243         debuggee.init(args);
 244         debuggee.doTest();
 245     }
 246 }