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 
init(String args[])73     protected void init(String args[]) {
74         super.init(args);
75         objectInstancesManager = new ObjectInstancesManager(log);
76     }
77 
initDebuggee(DebugeeArgumentHandler argHandler, Log log, IOPipe pipe, String args[], boolean callExit)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 
parseCommand(String command)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
useStrictCheck(String className, boolean otherThreadPresent)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("java.lang.Thread")) {
201             if (otherThreadPresent)
202                 return false;
203         }
204 
205         return true;
206     }
207 
208     // is reference with given type should be included in ObjectReference.referringObjects
isIncludedIntoReferrersCount(String referenceType)209     static public boolean isIncludedIntoReferrersCount(String referenceType) {
210         if (!ObjectInstancesManager.allReferenceTypes.contains(referenceType)) {
211             throw new TestBug("Invalid reference type: " + referenceType);
212         }
213 
214         return includedIntoReferrersCountTypes.contains(referenceType);
215     }
216 
217     // is reference with given type should be included in ReferenceType.instances
isIncludedIntoInstancesCount(String referenceType)218     static public boolean isIncludedIntoInstancesCount(String referenceType) {
219         if (!ObjectInstancesManager.allReferenceTypes.contains(referenceType)) {
220             throw new TestBug("Invalid reference type: " + referenceType);
221         }
222 
223         return includedIntoInstancesCountTypes.contains(referenceType);
224     }
225 
main(String args[])226     public static void main(String args[]) {
227         HeapwalkingDebuggee debuggee = new HeapwalkingDebuggee();
228         debuggee.init(args);
229         debuggee.doTest();
230     }
231 }
232