History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/tools/example/debug/tty/BreakpointSpec.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/example/debug/tty/BreakpointSpec.java+382−0
@@ -0,0 +1,382 @@
1/*
2 * Copyright (c) 1998, 2008, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.example.debug.tty;
27
28import com.sun.jdi.*;
29import com.sun.jdi.request.*;
30
31import java.util.ArrayList;
32import java.util.List;
33
34class BreakpointSpec extends EventRequestSpec {
35 String methodId;
36 List<String> methodArgs;
37 int lineNumber;
38
39 BreakpointSpec(ReferenceTypeSpec refSpec, int lineNumber) {
40 super(refSpec);
41 this.methodId = null;
42 this.methodArgs = null;
43 this.lineNumber = lineNumber;
44 }
45
46 BreakpointSpec(ReferenceTypeSpec refSpec, String methodId,
47 List<String> methodArgs) throws MalformedMemberNameException {
48 super(refSpec);
49 this.methodId = methodId;
50 this.methodArgs = methodArgs;
51 this.lineNumber = 0;
52 if (!isValidMethodName(methodId)) {
53 throw new MalformedMemberNameException(methodId);
54 }
55 }
56
57 /**
58 * The 'refType' is known to match, return the EventRequest.
59 */
60 @Override
61 EventRequest resolveEventRequest(ReferenceType refType)
62 throws AmbiguousMethodException,
63 AbsentInformationException,
64 InvalidTypeException,
65 NoSuchMethodException,
66 LineNotFoundException {
67 Location location = location(refType);
68 if (location == null) {
69 throw new InvalidTypeException();
70 }
71 EventRequestManager em = refType.virtualMachine().eventRequestManager();
72 EventRequest bp = em.createBreakpointRequest(location);
73 bp.setSuspendPolicy(suspendPolicy);
74 bp.enable();
75 return bp;
76 }
77
78 String methodName() {
79 return methodId;
80 }
81
82 int lineNumber() {
83 return lineNumber;
84 }
85
86 List<String> methodArgs() {
87 return methodArgs;
88 }
89
90 boolean isMethodBreakpoint() {
91 return (methodId != null);
92 }
93
94 @Override
95 public int hashCode() {
96 return refSpec.hashCode() + lineNumber +
97 ((methodId != null) ? methodId.hashCode() : 0) +
98 ((methodArgs != null) ? methodArgs.hashCode() : 0);
99 }
100
101 @Override
102 public boolean equals(Object obj) {
103 if (obj instanceof BreakpointSpec) {
104 BreakpointSpec breakpoint = (BreakpointSpec)obj;
105
106 return ((methodId != null) ?
107 methodId.equals(breakpoint.methodId)
108 : methodId == breakpoint.methodId) &&
109 ((methodArgs != null) ?
110 methodArgs.equals(breakpoint.methodArgs)
111 : methodArgs == breakpoint.methodArgs) &&
112 refSpec.equals(breakpoint.refSpec) &&
113 (lineNumber == breakpoint.lineNumber);
114 } else {
115 return false;
116 }
117 }
118
119 @Override
120 String errorMessageFor(Exception e) {
121 if (e instanceof AmbiguousMethodException) {
122 return (MessageOutput.format("Method is overloaded; specify arguments",
123 methodName()));
124 /*
125 * TO DO: list the methods here
126 */
127 } else if (e instanceof NoSuchMethodException) {
128 return (MessageOutput.format("No method in",
129 new Object [] {methodName(),
130 refSpec.toString()}));
131 } else if (e instanceof AbsentInformationException) {
132 return (MessageOutput.format("No linenumber information for",
133 refSpec.toString()));
134 } else if (e instanceof LineNotFoundException) {
135 return (MessageOutput.format("No code at line",
136 new Object [] {new Long (lineNumber()),
137 refSpec.toString()}));
138 } else if (e instanceof InvalidTypeException) {
139 return (MessageOutput.format("Breakpoints can be located only in classes.",
140 refSpec.toString()));
141 } else {
142 return super.errorMessageFor( e);
143 }
144 }
145
146 @Override
147 public String toString() {
148 StringBuffer buffer = new StringBuffer(refSpec.toString());
149 if (isMethodBreakpoint()) {
150 buffer.append('.');
151 buffer.append(methodId);
152 if (methodArgs != null) {
153 boolean first = true;
154 buffer.append('(');
155 for (String arg : methodArgs) {
156 if (!first) {
157 buffer.append(',');
158 }
159 buffer.append(arg);
160 first = false;
161 }
162 buffer.append(")");
163 }
164 } else {
165 buffer.append(':');
166 buffer.append(lineNumber);
167 }
168 return MessageOutput.format("breakpoint", buffer.toString());
169 }
170
171 private Location location(ReferenceType refType) throws
172 AmbiguousMethodException,
173 AbsentInformationException,
174 NoSuchMethodException,
175 LineNotFoundException {
176 Location location = null;
177 if (isMethodBreakpoint()) {
178 Method method = findMatchingMethod(refType);
179 location = method.location();
180 } else {
181 // let AbsentInformationException be thrown
182 List<Location> locs = refType.locationsOfLine(lineNumber());
183 if (locs.size() == 0) {
184 throw new LineNotFoundException();
185 }
186 // TO DO: handle multiple locations
187 location = locs.get(0);
188 if (location.method() == null) {
189 throw new LineNotFoundException();
190 }
191 }
192 return location;
193 }
194
195 private boolean isValidMethodName(String s) {
196 return isJavaIdentifier(s) ||
197 s.equals("<init>") ||
198 s.equals("<clinit>");
199 }
200
201 /*
202 * Compare a method's argument types with a Vector of type names.
203 * Return true if each argument type has a name identical to the
204 * corresponding string in the vector (allowing for varars)
205 * and if the number of arguments in the method matches the
206 * number of names passed
207 */
208 private boolean compareArgTypes(Method method, List<String> nameList) {
209 List<String> argTypeNames = method.argumentTypeNames();
210
211 // If argument counts differ, we can stop here
212 if (argTypeNames.size() != nameList.size()) {
213 return false;
214 }
215
216 // Compare each argument type's name
217 int nTypes = argTypeNames.size();
218 for (int i = 0; i < nTypes; ++i) {
219 String comp1 = argTypeNames.get(i);
220 String comp2 = nameList.get(i);
221 if (! comp1.equals(comp2)) {
222 /*
223 * We have to handle varargs. EG, the
224 * method's last arg type is xxx[]
225 * while the nameList contains xxx...
226 * Note that the nameList can also contain
227 * xxx[] in which case we don't get here.
228 */
229 if (i != nTypes - 1 ||
230 !method.isVarArgs() ||
231 !comp2.endsWith("...")) {
232 return false;
233 }
234 /*
235 * The last types differ, it is a varargs
236 * method and the nameList item is varargs.
237 * We just have to compare the type names, eg,
238 * make sure we don't have xxx[] for the method
239 * arg type and yyy... for the nameList item.
240 */
241 int comp1Length = comp1.length();
242 if (comp1Length + 1 != comp2.length()) {
243 // The type names are different lengths
244 return false;
245 }
246 // We know the two type names are the same length
247 if (!comp1.regionMatches(0, comp2, 0, comp1Length - 2)) {
248 return false;
249 }
250 // We do have xxx[] and xxx... as the last param type
251 return true;
252 }
253 }
254
255 return true;
256 }
257
258
259 /*
260 * Remove unneeded spaces and expand class names to fully
261 * qualified names, if necessary and possible.
262 */
263 private String normalizeArgTypeName(String name) {
264 /*
265 * Separate the type name from any array modifiers,
266 * stripping whitespace after the name ends
267 */
268 int i = 0;
269 StringBuffer typePart = new StringBuffer();
270 StringBuffer arrayPart = new StringBuffer();
271 name = name.trim();
272 int nameLength = name.length();
273 /*
274 * For varargs, there can be spaces before the ... but not
275 * within the ... So, we will just ignore the ...
276 * while stripping blanks.
277 */
278 boolean isVarArgs = name.endsWith("...");
279 if (isVarArgs) {
280 nameLength -= 3;
281 }
282 while (i < nameLength) {
283 char c = name.charAt(i);
284 if (Character.isWhitespace(c) || c == '[') {
285 break; // name is complete
286 }
287 typePart.append(c);
288 i++;
289 }
290 while (i < nameLength) {
291 char c = name.charAt(i);
292 if ( (c == '[') || (c == ']')) {
293 arrayPart.append(c);
294 } else if (!Character.isWhitespace(c)) {
295 throw new IllegalArgumentException
296 (MessageOutput.format("Invalid argument type name"));
297 }
298 i++;
299 }
300 name = typePart.toString();
301
302 /*
303 * When there's no sign of a package name already, try to expand the
304 * the name to a fully qualified class name
305 */
306 if ((name.indexOf('.') == -1) || name.startsWith("*.")) {
307 try {
308 ReferenceType argClass = Env.getReferenceTypeFromToken(name);
309 if (argClass != null) {
310 name = argClass.name();
311 }
312 } catch (IllegalArgumentException e) {
313 // We'll try the name as is
314 }
315 }
316 name += arrayPart.toString();
317 if (isVarArgs) {
318 name += "...";
319 }
320 return name;
321 }
322
323 /*
324 * Attempt an unambiguous match of the method name and
325 * argument specification to a method. If no arguments
326 * are specified, the method must not be overloaded.
327 * Otherwise, the argument types much match exactly
328 */
329 private Method findMatchingMethod(ReferenceType refType)
330 throws AmbiguousMethodException,
331 NoSuchMethodException {
332
333 // Normalize the argument string once before looping below.
334 List<String> argTypeNames = null;
335 if (methodArgs() != null) {
336 argTypeNames = new ArrayList<String>(methodArgs().size());
337 for (String name : methodArgs()) {
338 name = normalizeArgTypeName(name);
339 argTypeNames.add(name);
340 }
341 }
342
343 // Check each method in the class for matches
344 Method firstMatch = null; // first method with matching name
345 Method exactMatch = null; // (only) method with same name & sig
346 int matchCount = 0; // > 1 implies overload
347 for (Method candidate : refType.methods()) {
348 if (candidate.name().equals(methodName())) {
349 matchCount++;
350
351 // Remember the first match in case it is the only one
352 if (matchCount == 1) {
353 firstMatch = candidate;
354 }
355
356 // If argument types were specified, check against candidate
357 if ((argTypeNames != null)
358 && compareArgTypes(candidate, argTypeNames) == true) {
359 exactMatch = candidate;
360 break;
361 }
362 }
363 }
364
365 // Determine method for breakpoint
366 Method method = null;
367 if (exactMatch != null) {
368 // Name and signature match
369 method = exactMatch;
370 } else if ((argTypeNames == null) && (matchCount > 0)) {
371 // At least one name matched and no arg types were specified
372 if (matchCount == 1) {
373 method = firstMatch; // Only one match; safe to use it
374 } else {
375 throw new AmbiguousMethodException();
376 }
377 } else {
378 throw new NoSuchMethodException(methodName());
379 }
380 return method;
381 }
382}