10 * Responsible for providing static methods used in spewing out string
13 * <li> A useful hierarchy:
17 * <li> ObjectReference
19 * <li> StringReference
21 * <li> ThreadReference
22 * <li> ThreadGroupReference
33 * In our design, whenever we encounter an objectReference, we pass a
34 * sort of summary to jde, as well as an 'id' to identify it with.
35 * Whenever jde needs info about the objectReference, it uses the id to
36 * uniquely identify the object.
38 * Now, the representation that is sent across for the threads (ie to the
39 * jde) depends on the context. When it is sent with reference to thread
40 * commands, eg. get_threads, get_thread, get_object_monitors; it has
41 * a lot of thread specific information, eg. its state and all.
43 * When it's sent treating the thread as an object, eg. get_object, it's
44 * represented differently, and a different set of information is sent.
46 * Similary, when an array command is used, a different set of information
47 * is sent across, as against when it's treated as an object.
49 * Created: Tue Aug 3 16:36:54 1999
52 * Copyright (c) 2000, 2001, 2003 Paul Kinnucan
57 * @author Paul Kinnucan
59 * @version $Revision: 1.18 $
62 public class Rep implements Protocol {
65 * Returns a representation of a Location
70 * (list "type-name" "sourcefile" lineNumber)
71 * (list "type-name" nil lineNumber)
76 * <li> lineNumber is -1 if that information is not available
79 public static String getLocationRep(Location loc) {
80 StringBuffer locationString = new StringBuffer();
81 locationString.append("(list \"");
82 locationString.append(loc.declaringType().name());
83 locationString.append("\"");
85 locationString.append(" \"");
86 locationString.append(loc.sourceName());
87 locationString.append("\"");
88 } catch (AbsentInformationException ex) {
89 locationString.append(" nil"); // XXX - check if this is OK, or if we need to remove the \".
91 locationString.append(" ");
92 locationString.append(loc.lineNumber());
93 locationString.append(")");
94 return locationString.toString();
99 * Returns a representation of a method
104 * (list "name of method" return-type-name
105 * (list [argument-type-name]*)
106 * ["final"] ["static"] ["native"] ["constructor"] ["abstract"]
107 * ["synchronized"] ["static_initializer"])
110 static String getMethodRep(Method m) {
111 List l = m.argumentTypeNames();
112 StringBuffer argList = new StringBuffer("(list");
113 Iterator it = l.iterator();
114 while (it.hasNext()) {
115 argList.append(" \"");
116 argList.append(it.next().toString());
117 argList.append("\"");
121 // The below code results in an extra StringBuffer being created, but I think
122 // that's OK from a performance perspective.
123 return "(list \""+m.declaringType().name()+"\""
125 +" \""+m.returnTypeName()+"\""
126 + BR + argList.toString()
127 +(m.isFinal()?" \"final\"":"")
128 +(m.isStatic()?" \"static\"":"")
129 +(m.isNative()?" \"native\"":"")
130 +(m.isConstructor()?" \"constructor\"":"")
131 +(m.isAbstract()?" \"abstract\"":"")
132 +(m.isSynchronized()?" \"synchronized\"":"")
133 +(m.isStaticInitializer()
134 ?" \"static_initializer\"":"")
141 * Returns a representation of a local variable on a stack frame
145 * (list "name of variable" "type of variable")
148 static public String getLocalVariableRep(LocalVariable lv) {
149 return "(list" + " \""+lv.name()+"\" \""+lv.typeName()+"\")";
153 * Returns a representation of a (local variable, value) pair.
157 * ({@link #getLocalVariableRep local-variable} . {@link #getValueRep value})
160 static public String getLocalVariableValueRep(LocalVariable lv, Value v) {
161 return "(cons "+getLocalVariableRep(lv)
162 +" "+getValueRep(v)+")";
166 * Returns a list of (local variable, value) pairs.
170 * (list [{@link #getLocalVariableValueRep (local variable, value) pair}]*)
173 static public String getLocalVariableValueMapRep(Map map) {
174 StringBuffer localVariablesValuesString = new StringBuffer("(list ");
175 Set keys = map.keySet();
176 Iterator iter = keys.iterator();
177 while (iter.hasNext()) {
178 LocalVariable localVariable = (LocalVariable)iter.next();
179 Value val = (Value)map.get(localVariable);
180 localVariablesValuesString.append(BR);
181 localVariablesValuesString.append(getLocalVariableValueRep(localVariable, val));
183 localVariablesValuesString.append(")");
184 return localVariablesValuesString.toString();
189 * Returns a representation of a field.
193 * (list "name of field" "type of field" ["transient"] ["volatile"]
194 * ["final"] ["static"])
197 static String getFieldRep(Field f) {
199 + " \""+f.name()+"\""
200 + " \""+f.typeName()+"\""
201 + (f.isTransient() ? " \"transient\"" : "")
202 + (f.isVolatile() ? " \"volatile\"" : "")
203 + (f.isFinal() ? " \"final\"" : "")
204 + (f.isStatic() ? " \"static\"" : "")
209 * Returns a representation of a (field, value) pair.
213 * ({@link #getFieldRep field} . {@link #getValueRep value})
216 static String getFieldValueRep(Field f, Value v) {
217 return "(cons "+getFieldRep(f)+" "+getValueRep(v)+")";
221 * Returns a list of (field, value) pairs.
225 * (list [{@link #getFieldValueRep (field, value) pair}]*)
228 static String getFieldValueMapRep(Map map) {
229 StringBuffer fieldsValuesString = new StringBuffer("(list ");
230 Set keys = map.keySet();
231 Iterator iter = keys.iterator();
232 while (iter.hasNext()) {
233 Field field = (Field)iter.next();
234 Value val = (Value)map.get(field);
235 fieldsValuesString.append(BR);
236 fieldsValuesString.append(getFieldValueRep(field, val));
238 fieldsValuesString.append(")");
239 return fieldsValuesString.toString();
242 private static String filterFPValue(String fpValue) {
243 if (fpValue.equals("NaN"))
245 else if (fpValue.equals("-Infinity"))
246 return "\"-Infinity\"";
247 else if (fpValue.equals("Infinity"))
248 return "\"Infinity\"";
256 * Returns a representation of a 'value', that can be primitive
257 * or an object reference, or void.
264 * {@link #getObjectRep(ObjectReference) object-rep}
266 * (list "boolean" "true") (list "boolean" "false")
267 * (list "byte" 'byte-value')
268 * (list "char" 'char-value')
269 * (list "double" double-value)
270 * (list "float" float-value)
271 * (list "int" int-value)
272 * (list "long" long-value)
273 * (list "short" short-value)
276 static public String getValueRep(Value value) {
278 return "(list \"null\")";
279 } else if (value instanceof VoidValue) {
280 return "(list \"void\")";
281 } else if (value instanceof ObjectReference) {
282 return getObjectRep((ObjectReference)value);
284 PrimitiveValue v = (PrimitiveValue)value;
285 if (v instanceof BooleanValue) {
286 return "(list \"boolean\" \""+v.booleanValue()+"\")";
287 } else if (v instanceof ByteValue) {
288 return "(list \"byte\" \""+v.byteValue()+"\")";
289 } else if (v instanceof CharValue) {
290 return "(list \"char\" \""+
291 escapeString(String.valueOf(v.charValue()))+"\")";
292 } else if (v instanceof DoubleValue) {
293 return "(list \"double\" " + filterFPValue(String.valueOf(v.doubleValue()))+")";
294 } else if (v instanceof FloatValue) {
295 return "(list \"float\" "+filterFPValue(String.valueOf(v.floatValue()))+")";
296 } else if (v instanceof IntegerValue) {
297 return "(list \"int\" \""+v.intValue()+"\")";
298 } else if (v instanceof LongValue) {
299 return "(list \"long\" \""+v.longValue()+"\")";
300 } else if (v instanceof ShortValue) {
301 return "(list \"short\" "+v.shortValue()+")";
308 * Returns information about an array
314 * (list "type name" uniqueID ['t|nil] length [element]*)
319 * <li> The third argument (['t|nil]) indicates if the object has
320 * been garbage collected in the debugee vm: it's nil if it hasn't.
321 * <li> elements are only present if the index/length make sense. See
326 * @param String a description of the array elements
328 static public String getArrayRep(ArrayReference a, String elements) {
330 return "\"Error! null array reference in Rep.getArrayRep!\"";
334 + "\""+a.referenceType().name()+"\""
336 + (a.isCollected() ? " 't":" nil")
344 * Prefix \ escapes to all \ and " characters in a string so that
345 * the string can be read byte the Lisp interpreter. For efficiency,
346 * if no such characters are found, the argument String itself
349 * @param str String to be prefixed.
353 * @author Mark Gibson
354 * @author Steve Haflich
355 * @author Charles Hart
356 * @author David Dagon
358 public static String escapeString (String str) {
360 if ( str.indexOf('\\') == -1 &&
361 str.indexOf('"') == -1 )
367 StringBuffer buf = new StringBuffer(str.length() + 16);
368 for ( int i = 0; i < str.length(); i++ ) {
369 char ch = str.charAt( i );
371 case '"': buf.append("\\\"" ); break;
372 case '\\': buf.append("\\\\" ); break;
373 default: buf.append( ch ); break;
376 return buf.toString();
383 * Returns the value of a string
389 * (list "java.lang.String" uniqueID ['t|nil] "string-value")
393 * <li> The third argument (['t|nil]) indicates if the object has
394 * been garbage collected in the debugee vm: it's nil if it hasn't.
398 static public String getStringRep(StringReference s) {
404 + "\""+s.referenceType().name()+"\""
406 + (s.isCollected() ? " 't":" nil")
407 + " \"" + escapeString(s.value()) + "\")";
413 * Returns a non-detailed representation of an object.
415 * @see #getObjectRep(ObjectReference,boolean)
417 static public String getObjectRep(ObjectReference o) {
418 return getObjectRep(o, false);
422 * Returns a canonical representation of an object.
429 * <i>Non-detailed</i>
430 * (list "type of object" uniqueID ['t|nil])
432 * (list "type of object" uniqueID ['t|nil] {@link #getFieldValueMapRep fields-values})
437 * <li> The third argument (['t|nil]) indicates if the object has
438 * been garbage collected in the debugee vm: it's nil if it hasn't.
441 static public String getObjectRep(ObjectReference o, boolean detailed) {
443 return "(list \"null\")";
447 String fieldsValuesString;
449 // XXX a more complete list is available using
450 // allFields().... fyi
451 fieldsValuesString = getFieldValueMapRep(o.getValues(o.referenceType().visibleFields()));
452 } catch (ClassNotPreparedException ex) {
453 fieldsValuesString = "\"The class isn't prepared\"";
454 } catch (ObjectCollectedException ex) {
455 fieldsValuesString = "\"The object has already been collected\"";
456 } catch (Exception ex) {
457 fieldsValuesString = "\"Unable to access fields and values. Optimized class?\"";
461 + "\""+o.referenceType().name()+"\""
463 + (o.isCollected() ? " 't":" nil")+BR
464 + fieldsValuesString+")";
467 + "\""+o.referenceType().name()+"\""
469 + (o.isCollected() ? " 't":" nil")
477 * THREAD REPRESENTATIONS
481 * Returns information about monitors of an object.
486 * (list uniqueID "type of object" ['t|nil] {@link #getThreadRep owning-thread} (list [{@link #getThreadRep waiting-thread}]*))
491 * <li> The third argument (['t|nil]) indicates if the object has
492 * been garbage collected in the debugee vm: it's nil if it hasn't.
495 static public String getObjectMonitorsRep(ObjectReference o) {
503 ThreadReference t = o.owningThread();
505 owningThread = "nil";
507 owningThread = getThreadRep(t);
509 } catch (IncompatibleThreadStateException ex) {
510 owningThread = "\"Information Not Available\"";
511 } catch (UnsupportedOperationException ex) {
512 owningThread = "\"VM has no information\"";
516 StringBuffer waitingThreadsStringBuffer = new StringBuffer("(list");
517 String waitingThreadsString;
519 List waitingThreads = o.waitingThreads();
520 Iterator it = waitingThreads.iterator();
521 while (it.hasNext()) {
522 waitingThreadsStringBuffer.append(BR);
523 waitingThreadsStringBuffer.append(getThreadRep((ThreadReference)it.next()));
525 waitingThreadsStringBuffer.append(")");
526 waitingThreadsString = waitingThreadsStringBuffer.toString();
527 } catch (IncompatibleThreadStateException ex) {
528 waitingThreadsString = "\"Information Not Available\"";
529 } catch (UnsupportedOperationException ex) {
530 waitingThreadsString = "\"VM has no information\"";
534 return "(list "+o.uniqueID()+" "
535 +"\""+o.referenceType().name()+"\""
536 + (o.isCollected() ? " 't":" nil")+BR
538 +waitingThreadsString+")";
542 /* thread information retrieval routines */
547 * Returns a canonical representation of a given ThreadGroupReference.
551 * (list "ThreadGroup" uniqueID "name of threadgroup"
552 * (list [{@link #getThreadRep(ThreadReference) child thread}]*)
553 * (list [{@link #getThreadGroupRep child threadgroup}]*))
556 public static String getThreadGroupRep(ThreadGroupReference t) {
557 StringBuffer rep = new StringBuffer("(list \"ThreadGroup\" ");
558 rep.append(t.uniqueID());
560 rep.append(t.name());
563 List list = t.threads();
564 Iterator it = list.iterator();
569 while (it.hasNext()) {
571 rep.append(getThreadRep((ThreadReference)it.next()));
575 list = t.threadGroups();
576 it = list.iterator();
579 while (it.hasNext()) {
581 rep.append(getThreadGroupRep((ThreadGroupReference)it.next()));
585 return rep.toString();
589 * Returns a detailed thread representation.
590 * @see #getThreadRep(ThreadReference, boolean)
592 static public String getThreadRep(ThreadReference t) {
593 return getThreadRep(t, true);
597 * Returns a canonical representation of a given ThreadReference.
602 * <i>Non-detailed</i>
603 * (list "Thread" uniqueID "name of thread" <u>status</u> <u>currentState</u>)
605 * (list "Thread" uniqueID "name of thread" status currentState
606 * (list [{@link #getStackFrameRep stack-frame}]*)
607 * <u>owned-monitors-string</u>
608 * <u>current-contended-monitor-string</u>)
613 * <li> <u>status</u> is one of: "unknown", "waiting on monitor",
614 * "not started", "runnable", "sleeping", "waiting", and "zombie"
616 * <li> <u>currentState</u> is one of "normal", "suspended by debugger",
617 * and "suspended at breakpoint"
619 * <li> <u>owned-monitors-string</u>:
622 * (list [{@link #getObjectRep(ObjectReference) owned monitor}]*)
624 * <li> <u>current-contended-monitor-string</u>:
628 * {@link #getObjectRep(ObjectReference) current contended monitor}
633 * (list "Thread" 53 "Thread 1, continuous"
634 * "suspended by debugger" "waiting on monitor"
636 * (list 0 "test.Test" "Test.java" 45))
638 * (list "java.lang.String" 55))
640 * (list "Thread" 54 "Thread 2"
641 * "suspended by debugger" "waiting on monitor"
643 * (list 0 "java.lang.Thread" "Thread.java" -1)
644 * (list 1 "test.Test" "Test.java" 47))
646 * (list "java.lang.String" 55)
647 * (list "java.lang.Integer" 61))
653 * @param detailed True if a more detailed representation is desired:
654 * includes the stackframe as well as information about the monitors.
656 static public String getThreadRep(ThreadReference t,
658 int status = t.status();
659 String statusString = "unknown";
661 case ThreadReference.THREAD_STATUS_MONITOR:
662 statusString = "waiting on monitor";
664 case ThreadReference.THREAD_STATUS_NOT_STARTED:
665 statusString = "not started";
667 case ThreadReference.THREAD_STATUS_RUNNING:
668 statusString = "runnable";
670 case ThreadReference.THREAD_STATUS_SLEEPING:
671 statusString = "sleeping";
673 case ThreadReference.THREAD_STATUS_WAIT:
674 statusString = "waiting";
676 case ThreadReference.THREAD_STATUS_ZOMBIE:
677 statusString = "zombie";
679 case ThreadReference.THREAD_STATUS_UNKNOWN:
680 statusString = "unknown";
686 // note that the above status string refers to the state of the
687 // thread *before* a suspension, if there was a suspension.
689 /* Due to a bug in ThreadReference.isSuspended(), we need to
690 use suspendCount() */
691 String stateString = "normal";
692 if (t.isAtBreakpoint()) {
693 stateString = "suspended at breakpoint";
694 } else if (t.suspendCount() > 0) {
695 stateString = "suspended by debugger";
702 StringBuffer stackStringBuffer = new StringBuffer("(list");
705 // a list of the stackframes is also sent...
706 List stackFrames = t.frames();
707 Iterator it = stackFrames.iterator();
709 while (it.hasNext()) {
710 stackStringBuffer.append(BR);
711 stackStringBuffer.append(getStackFrameRep((StackFrame)it.next(), index++));
713 stackStringBuffer.append(")");
714 stackString = stackStringBuffer.toString();
715 } catch (IncompatibleThreadStateException ex) {
716 stackString = "\"Information Not Available\"";
719 // info on the monitors
723 StringBuffer ownedMonitorsStringBuffer = new StringBuffer("(list");
724 String ownedMonitorsString;
726 List ownedMonitors = t.ownedMonitors();
727 Iterator it = ownedMonitors.iterator();
728 while (it.hasNext()) {
729 ownedMonitorsStringBuffer.append(BR);
730 ownedMonitorsStringBuffer.append(getObjectRep((ObjectReference)it.next()));
732 ownedMonitorsStringBuffer.append(")");
733 ownedMonitorsString = ownedMonitorsStringBuffer.toString();
734 } catch (IncompatibleThreadStateException ex) {
735 ownedMonitorsString = "\"Information Not Available\"";
736 } catch (UnsupportedOperationException ex) {
737 ownedMonitorsString = "\"VM has no information\"";
738 } catch (ObjectCollectedException ex) {
739 ownedMonitorsString = "\"The object has been collected\"";
742 // current contended monitor
743 // note, however, from the jdi api:
744 // The thread can be waiting for a monitor through entry into a
745 // synchronized method, the synchronized statement, or
746 // Object.wait(). The status() method can be used to
747 // differentiate between the first two cases and the third.
749 String currentContendedMonitorString;
751 ObjectReference o = t.currentContendedMonitor();
753 currentContendedMonitorString = "nil";
755 currentContendedMonitorString =
758 } catch (IncompatibleThreadStateException ex) {
759 currentContendedMonitorString =
760 "\"Information Not Available\"";
761 } catch (UnsupportedOperationException ex) {
762 currentContendedMonitorString =
763 "\"VM has no information\"";
764 } catch (ObjectCollectedException ex) {
765 currentContendedMonitorString =
766 "\"The object has been collected\"";
769 return "(list \"Thread\""
772 +" \""+statusString+"\""
773 +" \""+stateString+"\""
775 + BR +ownedMonitorsString
776 + BR +currentContendedMonitorString
779 return "(list \"Thread\""
782 +" \""+statusString+"\""
783 +" \""+stateString+"\")";
788 * Returns a canonical representation of a given StackFrame.
793 * (list "StackFrame" index "Information not available")
794 * (list "StackFrame" index "type name" "source name" lineNumber "method name")
799 * <li> lineNumber is -1 for native methods
802 * @param index Gives the index of this particular stack frame for
803 * the thread. This basically goes into the string returned as a
806 static String getStackFrameRep(StackFrame s, int index) {
808 Location loc = s.location();
809 Method method = loc.method();
810 return "(list "+index+" "
811 +"\""+loc.declaringType().name()+"\" "
812 // Source file name can be a path with a backslash.
813 // Need to escape the backslash.
814 + "\"" + escapeString(loc.sourceName()) + "\" "
815 +loc.lineNumber()+" "
816 +"\""+method.name()+"\")";
817 } catch (AbsentInformationException ex) {
818 return "(list \"StackFrame\" "+index
819 +" \"Information not available\")";
827 * Revision 1.18 2003/01/08 06:53:37 paulk
828 * Integrate Petter Mahlen's updates.
830 * Revision 1.17 2002/10/23 05:54:05 paulk
831 * Updated the getStackFrameRep method to escape backslashes in the name of the source file
832 * corresponding to a stack frame. The name of the source file can be a relative path in
833 * some obscure cases and the relative path can include backslashes.
835 * Revision 1.16 2001/08/14 05:15:01 paulk
836 * Miscellaneous updates.
838 * Revision 1.15 2001/04/19 04:43:55 paulk
839 * Now escapes char values.
841 * Revision 1.14 2001/03/24 05:36:49 paulk
842 * Updated to reflect reorganization of debuggee code.
844 * Revision 1.13 2000/07/28 06:26:31 paulk
845 * Committing all modified files.
847 * Revision 1.12 2000/04/10 05:57:30 paulk
848 * Publicized some methods.
850 * Revision 1.11 2000/04/01 06:02:37 paulk
851 * Wrap NaN, Infinity, and -Infinity values in quotes to prevent Lisp evaluation errors.
853 * Revision 1.10 2000/03/17 03:35:23 paulk
854 * Enhanced getStackFrameRep to return method. Thanks to Paul Michael Reilly <pmr@pajato.com>.
856 * Revision 1.9 2000/03/10 06:53:25 paulk
857 * Escape quotes in strings.
859 * Revision 1.8 2000/03/04 08:58:11 paulk
860 * Put quotes around byte, int, and long values to avoid Lisp
861 * representation problems. Thanks to Charles Hart <cfhart@Z-TEL.com> for this fix.