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+
26+package com.sun.tools.example.debug.tty;
27+
28+import com.sun.jdi.*;
29+import com.sun.jdi.request.*;
30+
31+import java.util.ArrayList;
32+import java.util.List;
33+
34+class 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+}