/* * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package nsk.share.jdi; import java.io.*; import java.util.*; import nsk.share.Log; import nsk.share.ObjectInstancesManager; import nsk.share.TestBug; import nsk.share.jpda.DebugeeArgumentHandler; import nsk.share.jpda.IOPipe; /* * Debuggee class used in tests for heapwalking(tests for VirtualMachine.instanceCounts, ReferenceType.instances, ObjectReference.referrers). * Handle commands related to creation of objects instances with given reference type * and given referrers number, use for this purposes nsk.share.ObjectInstancesManager. */ public class HeapwalkingDebuggee extends AbstractJDIDebuggee { protected ObjectInstancesManager objectInstancesManager; // reference of this type should be included in ObjectReference.referringObjects public static Set includedIntoReferrersCountTypes = new HashSet(); // reference of this type should be included in ReferenceType.instances public static Set includedIntoInstancesCountTypes = new HashSet(); static { includedIntoInstancesCountTypes.add(ObjectInstancesManager.STRONG_REFERENCE); includedIntoInstancesCountTypes.add(ObjectInstancesManager.WEAK_REFERENCE); includedIntoInstancesCountTypes.add(ObjectInstancesManager.SOFT_REFERENCE); includedIntoInstancesCountTypes.add(ObjectInstancesManager.PHANTOM_REFERENCE); includedIntoInstancesCountTypes.add(ObjectInstancesManager.JNI_GLOBAL_REFERENCE); includedIntoInstancesCountTypes.add(ObjectInstancesManager.JNI_LOCAL_REFERENCE); includedIntoReferrersCountTypes.add(ObjectInstancesManager.STRONG_REFERENCE); includedIntoReferrersCountTypes.add(ObjectInstancesManager.WEAK_REFERENCE); includedIntoReferrersCountTypes.add(ObjectInstancesManager.SOFT_REFERENCE); includedIntoReferrersCountTypes.add(ObjectInstancesManager.PHANTOM_REFERENCE); } //create number instance of class with given name, command format: createInstances:class_name:instance_count[:referrer_count:referrer_type] static public final String COMMAND_CREATE_INSTANCES = "createInstances"; //'delete'(make unreachable) number instance of class with given name, command format: deleteInstances:class_name:instance_count:referrer_count static public final String COMMAND_DELETE_INSTANCES = "deleteInstances"; //delete number referrers static public final String COMMAND_DELETE_REFERRERS = "deleteReferrers"; //create instance with all type referrers static public final String COMMAND_CREATE_ALL_TYPE_REFERENCES = "createAllTypeReferences"; protected void init(String args[]) { super.init(args); objectInstancesManager = new ObjectInstancesManager(log); } public void initDebuggee(DebugeeArgumentHandler argHandler, Log log, IOPipe pipe, String args[], boolean callExit) { super.initDebuggee(argHandler, log, pipe, args, callExit); objectInstancesManager = new ObjectInstancesManager(log); } public boolean parseCommand(String command) { if (super.parseCommand(command)) return true; try { StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(command)); tokenizer.whitespaceChars(':', ':'); tokenizer.wordChars('_', '_'); tokenizer.wordChars('$', '$'); tokenizer.wordChars('[', ']'); tokenizer.wordChars('|', '|'); if (command.startsWith(COMMAND_CREATE_INSTANCES)) { //createInstances:class_name:instance_count[:referrer_count:referrer_type] tokenizer.nextToken(); if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) throw new TestBug("Invalid command format: " + command); String className = tokenizer.sval; if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER) throw new TestBug("Invalid command format: " + command); int instanceCounts = (int) tokenizer.nval; int referrerCount = 1; Set referrerType = new HashSet(); if (tokenizer.nextToken() == StreamTokenizer.TT_NUMBER) { referrerCount = (int) tokenizer.nval; if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) referrerType.addAll(Arrays.asList(tokenizer.sval.split("\\|"))); } if (referrerType.isEmpty()) { referrerType.add(ObjectInstancesManager.STRONG_REFERENCE); } objectInstancesManager.createReferences(instanceCounts, className, referrerCount, referrerType); return true; } else if (command.startsWith(COMMAND_DELETE_INSTANCES)) { //deleteInstances:class_name:instance_count:referrer_count tokenizer.nextToken(); if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) throw new TestBug("Invalid command format: " + command); String className = tokenizer.sval; if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER) throw new TestBug("Invalid command format: " + command); int instanceCounts = (int) tokenizer.nval; objectInstancesManager.deleteAllReferrers(instanceCounts, className); return true; } else if (command.startsWith(COMMAND_DELETE_REFERRERS)) { tokenizer.nextToken(); if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) throw new TestBug("Invalid command format: " + command); String className = tokenizer.sval; if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER) throw new TestBug("Invalid command format: " + command); int referrersCount = (int) tokenizer.nval; Set referrerTypes = new HashSet(); if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) { referrerTypes.addAll(Arrays.asList(tokenizer.sval.split("\\|"))); } objectInstancesManager.deleteReferrers(className, referrersCount, referrerTypes); return true; } else if (command.startsWith(COMMAND_CREATE_ALL_TYPE_REFERENCES)) { tokenizer.nextToken(); if (tokenizer.nextToken() != StreamTokenizer.TT_WORD) throw new TestBug("Invalid command format: " + command); String className = tokenizer.sval; if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER) throw new TestBug("Invalid command format: " + command); int instanceCounts = (int) tokenizer.nval; objectInstancesManager.createAllTypeReferences(className, instanceCounts); return true; } } catch (IOException e) { throw new TestBug("Invalid command format: " + command); } return false; } // instances of some classes couldn't be strictly controlled during test execution, use non-strict checks for this classes public static boolean useStrictCheck(String className, boolean otherThreadPresent) { if (className.equals("java.lang.String")) return false; if (className.equals("char[]")) return false; if (className.equals("byte[]")) return false; if (className.equals("java.lang.Thread")) { if (otherThreadPresent) return false; } return true; } // is reference with given type should be included in ObjectReference.referringObjects static public boolean isIncludedIntoReferrersCount(String referenceType) { if (!ObjectInstancesManager.allReferenceTypes.contains(referenceType)) { throw new TestBug("Invalid reference type: " + referenceType); } return includedIntoReferrersCountTypes.contains(referenceType); } // is reference with given type should be included in ReferenceType.instances static public boolean isIncludedIntoInstancesCount(String referenceType) { if (!ObjectInstancesManager.allReferenceTypes.contains(referenceType)) { throw new TestBug("Invalid reference type: " + referenceType); } return includedIntoInstancesCountTypes.contains(referenceType); } public static void main(String args[]) { HeapwalkingDebuggee debuggee = new HeapwalkingDebuggee(); debuggee.init(args); debuggee.doTest(); } }