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/bdi/MethodBreakpointSpec.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/example/debug/bdi/MethodBreakpointSpec.java+337−0
@@ -0,0 +1,337 @@
1+/*
2+ * Copyright (c) 1999, 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.bdi;
27+
28+import com.sun.jdi.*;
29+import java.util.ArrayList;
30+import java.util.List;
31+
32+public class MethodBreakpointSpec extends BreakpointSpec {
33+ String methodId;
34+ List<String> methodArgs;
35+
36+ MethodBreakpointSpec(EventRequestSpecList specs,
37+ ReferenceTypeSpec refSpec,
38+ String methodId, List<String> methodArgs) {
39+ super(specs, refSpec);
40+ this.methodId = methodId;
41+ this.methodArgs = methodArgs;
42+ }
43+
44+ /**
45+ * The 'refType' is known to match.
46+ */
47+ @Override
48+ void resolve(ReferenceType refType) throws MalformedMemberNameException,
49+ AmbiguousMethodException,
50+ InvalidTypeException,
51+ NoSuchMethodException,
52+ NoSessionException {
53+ if (!isValidMethodName(methodId)) {
54+ throw new MalformedMemberNameException(methodId);
55+ }
56+ if (!(refType instanceof ClassType)) {
57+ throw new InvalidTypeException();
58+ }
59+ Location location = location((ClassType)refType);
60+ setRequest(refType.virtualMachine().eventRequestManager()
61+ .createBreakpointRequest(location));
62+ }
63+
64+ private Location location(ClassType clazz) throws
65+ AmbiguousMethodException,
66+ NoSuchMethodException,
67+ NoSessionException {
68+ Method method = findMatchingMethod(clazz);
69+ Location location = method.location();
70+ return location;
71+ }
72+
73+ public String methodName() {
74+ return methodId;
75+ }
76+
77+ public List<String> methodArgs() {
78+ return methodArgs;
79+ }
80+
81+ @Override
82+ public int hashCode() {
83+ return refSpec.hashCode() +
84+ ((methodId != null) ? methodId.hashCode() : 0) +
85+ ((methodArgs != null) ? methodArgs.hashCode() : 0);
86+ }
87+
88+ @Override
89+ public boolean equals(Object obj) {
90+ if (obj instanceof MethodBreakpointSpec) {
91+ MethodBreakpointSpec breakpoint = (MethodBreakpointSpec)obj;
92+
93+ return methodId.equals(breakpoint.methodId) &&
94+ methodArgs.equals(breakpoint.methodArgs) &&
95+ refSpec.equals(breakpoint.refSpec);
96+ } else {
97+ return false;
98+ }
99+ }
100+
101+ @Override
102+ public String errorMessageFor(Exception e) {
103+ if (e instanceof AmbiguousMethodException) {
104+ return ("Method " + methodName() + " is overloaded; specify arguments");
105+ /*
106+ * TO DO: list the methods here
107+ */
108+ } else if (e instanceof NoSuchMethodException) {
109+ return ("No method " + methodName() + " in " + refSpec);
110+ } else if (e instanceof InvalidTypeException) {
111+ return ("Breakpoints can be located only in classes. " +
112+ refSpec + " is an interface or array");
113+ } else {
114+ return super.errorMessageFor( e);
115+ }
116+ }
117+
118+ @Override
119+ public String toString() {
120+ StringBuffer buffer = new StringBuffer("breakpoint ");
121+ buffer.append(refSpec.toString());
122+ buffer.append('.');
123+ buffer.append(methodId);
124+ if (methodArgs != null) {
125+ boolean first = true;
126+ buffer.append('(');
127+ for (String name : methodArgs) {
128+ if (!first) {
129+ buffer.append(',');
130+ }
131+ buffer.append(name);
132+ first = false;
133+ }
134+ buffer.append(")");
135+ }
136+ buffer.append(" (");
137+ buffer.append(getStatusString());
138+ buffer.append(')');
139+ return buffer.toString();
140+ }
141+
142+ private boolean isValidMethodName(String s) {
143+ return isJavaIdentifier(s) ||
144+ s.equals("<init>") ||
145+ s.equals("<clinit>");
146+ }
147+
148+ /*
149+ * Compare a method's argument types with a Vector of type names.
150+ * Return true if each argument type has a name identical to the
151+ * corresponding string in the vector (allowing for varargs)
152+ * and if the number of arguments in the method matches the
153+ * number of names passed
154+ */
155+ private boolean compareArgTypes(Method method, List<String> nameList) {
156+ List<String> argTypeNames = method.argumentTypeNames();
157+
158+ // If argument counts differ, we can stop here
159+ if (argTypeNames.size() != nameList.size()) {
160+ return false;
161+ }
162+
163+ // Compare each argument type's name
164+ int nTypes = argTypeNames.size();
165+ for (int i = 0; i < nTypes; ++i) {
166+ String comp1 = argTypeNames.get(i);
167+ String comp2 = nameList.get(i);
168+ if (! comp1.equals(comp2)) {
169+ /*
170+ * We have to handle varargs. EG, the
171+ * method's last arg type is xxx[]
172+ * while the nameList contains xxx...
173+ * Note that the nameList can also contain
174+ * xxx[] in which case we don't get here.
175+ */
176+ if (i != nTypes - 1 ||
177+ !method.isVarArgs() ||
178+ !comp2.endsWith("...")) {
179+ return false;
180+ }
181+ /*
182+ * The last types differ, it is a varargs
183+ * method and the nameList item is varargs.
184+ * We just have to compare the type names, eg,
185+ * make sure we don't have xxx[] for the method
186+ * arg type and yyy... for the nameList item.
187+ */
188+ int comp1Length = comp1.length();
189+ if (comp1Length + 1 != comp2.length()) {
190+ // The type names are different lengths
191+ return false;
192+ }
193+ // We know the two type names are the same length
194+ if (!comp1.regionMatches(0, comp2, 0, comp1Length - 2)) {
195+ return false;
196+ }
197+ // We do have xxx[] and xxx... as the last param type
198+ return true;
199+ }
200+ }
201+
202+ return true;
203+ }
204+
205+ private VirtualMachine vm() {
206+ return request.virtualMachine();
207+ }
208+
209+ /**
210+ * Remove unneeded spaces and expand class names to fully
211+ * qualified names, if necessary and possible.
212+ */
213+ private String normalizeArgTypeName(String name) throws NoSessionException {
214+ /*
215+ * Separate the type name from any array modifiers,
216+ * stripping whitespace after the name ends.
217+ */
218+ int i = 0;
219+ StringBuffer typePart = new StringBuffer();
220+ StringBuffer arrayPart = new StringBuffer();
221+ name = name.trim();
222+ int nameLength = name.length();
223+ /*
224+ * For varargs, there can be spaces before the ... but not
225+ * within the ... So, we will just ignore the ...
226+ * while stripping blanks.
227+ */
228+ boolean isVarArgs = name.endsWith("...");
229+ if (isVarArgs) {
230+ nameLength -= 3;
231+ }
232+
233+ while (i < nameLength) {
234+ char c = name.charAt(i);
235+ if (Character.isWhitespace(c) || c == '[') {
236+ break; // name is complete
237+ }
238+ typePart.append(c);
239+ i++;
240+ }
241+ while (i < nameLength) {
242+ char c = name.charAt(i);
243+ if ( (c == '[') || (c == ']')) {
244+ arrayPart.append(c);
245+ } else if (!Character.isWhitespace(c)) {
246+ throw new IllegalArgumentException(
247+ "Invalid argument type name");
248+
249+ }
250+ i++;
251+ }
252+
253+ name = typePart.toString();
254+
255+ /*
256+ * When there's no sign of a package name already,
257+ * try to expand the
258+ * the name to a fully qualified class name
259+ */
260+ if ((name.indexOf('.') == -1) || name.startsWith("*.")) {
261+ try {
262+ List<?> refs = specs.runtime.findClassesMatchingPattern(name);
263+ if (refs.size() > 0) { //### ambiguity???
264+ name = ((ReferenceType)(refs.get(0))).name();
265+ }
266+ } catch (IllegalArgumentException e) {
267+ // We'll try the name as is
268+ }
269+ }
270+ name += arrayPart.toString();
271+ if (isVarArgs) {
272+ name += "...";
273+ }
274+ return name;
275+ }
276+
277+ /*
278+ * Attempt an unambiguous match of the method name and
279+ * argument specification to a method. If no arguments
280+ * are specified, the method must not be overloaded.
281+ * Otherwise, the argument types much match exactly
282+ */
283+ private Method findMatchingMethod(ClassType clazz)
284+ throws AmbiguousMethodException,
285+ NoSuchMethodException,
286+ NoSessionException {
287+
288+ // Normalize the argument string once before looping below.
289+ List<String> argTypeNames = null;
290+ if (methodArgs() != null) {
291+ argTypeNames = new ArrayList<String>(methodArgs().size());
292+ for (String name : methodArgs()) {
293+ name = normalizeArgTypeName(name);
294+ argTypeNames.add(name);
295+ }
296+ }
297+
298+ // Check each method in the class for matches
299+ Method firstMatch = null; // first method with matching name
300+ Method exactMatch = null; // (only) method with same name & sig
301+ int matchCount = 0; // > 1 implies overload
302+ for (Method candidate : clazz.methods()) {
303+ if (candidate.name().equals(methodName())) {
304+ matchCount++;
305+
306+ // Remember the first match in case it is the only one
307+ if (matchCount == 1) {
308+ firstMatch = candidate;
309+ }
310+
311+ // If argument types were specified, check against candidate
312+ if ((argTypeNames != null)
313+ && compareArgTypes(candidate, argTypeNames) == true) {
314+ exactMatch = candidate;
315+ break;
316+ }
317+ }
318+ }
319+
320+ // Determine method for breakpoint
321+ Method method = null;
322+ if (exactMatch != null) {
323+ // Name and signature match
324+ method = exactMatch;
325+ } else if ((argTypeNames == null) && (matchCount > 0)) {
326+ // At least one name matched and no arg types were specified
327+ if (matchCount == 1) {
328+ method = firstMatch; // Only one match; safe to use it
329+ } else {
330+ throw new AmbiguousMethodException();
331+ }
332+ } else {
333+ throw new NoSuchMethodException(methodName());
334+ }
335+ return method;
336+ }
337+}