123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- /* Copyright (C) 2004 Free Software Foundation
- This file is part of libgcj.
- This software is copyrighted work licensed under the terms of the
- Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
- details. */
- /* Utility methods that allow an object to be converted to a textual
- representation on an OutputStream. The intention here is that this
- class be used for debugging, so we provide information about all
- fields, public or otherwise. */
- package gnu.gcj.util;
- import java.lang.reflect.*;
- import java.io.*;
- import java.util.*;
- class Debug
- {
- private final PrintStream p;
- private final int maxdepth;
- private final int maxArrayLength;
- private final boolean printStaticFields;
- private int depth;
- Debug(PrintStream writer, int maxdepth, int maxArrayLength, boolean printStaticFields)
- {
- p = writer;
- this.maxdepth = maxdepth;
- this.maxArrayLength = maxArrayLength;
- this.printStaticFields = printStaticFields;
- }
- Debug(PrintStream writer)
- {
- this(writer, 0, 10, false);
- }
- Debug(int maxdepth, boolean printStaticFields)
- {
- this(new PrintStream
- (new FileOutputStream(FileDescriptor.err), true),
- maxdepth,
- maxdepth > 0 ? 1000 : 10, printStaticFields);
- }
- Debug(int maxdepth)
- {
- this(maxdepth, false);
- }
- Debug()
- {
- this(0, false);
- }
-
- private final void indent()
- {
- for (int i = 0; i < depth; i++)
- p.print(" ");
- }
- private final java.util.IdentityHashMap h =
- new java.util.IdentityHashMap();
- private static native Field[] getDeclaredFields(Class c);
- private static native Object getField(Object o, Field f);
- private static native long getAddr(Object o);
- // Return an array containing all the fields of a class and its
- // superclasses.
- private Field[] internalGetFields(Class c)
- {
- HashSet set = new HashSet();
- set.addAll(Arrays.asList(getDeclaredFields(c)));
- Class[] interfaces = c.getInterfaces();
- for (int i = 0; i < interfaces.length; i++)
- set.addAll(Arrays.asList(internalGetFields(interfaces[i])));
- Class superClass = c.getSuperclass();
- if (superClass != null)
- set.addAll(Arrays.asList(internalGetFields(superClass)));
- return (Field[])set.toArray(new Field[set.size()]);
- }
- // FIXME: We could just use getClass() here, but this is a
- // workaround for a C++ bug that is causing getClass() to be
- // miscompiled.
- static private Class getItsClass(Object O)
- {
- return O.getClass();
- }
- // Print a reasonably readable textual representation of an object
- // on our OutputStream. Objects are only printed once, no matter
- // how many references point to them.
- private void print(Object O)
- {
- int savedDepth = depth;
- h.put(O, O);
- try
- {
- Class C = getItsClass(O);
- p.print(C.getName() + "@");
- p.println(Long.toHexString(getAddr(O)));
- if (C.isArray())
- {
- indent(); p.println("{");
- depth++;
- indent();
- C = C.getComponentType();
- int len = Array.getLength(O);
- for (int i = 0; i < len; i++)
- {
- Object thing = Array.get(O, i);
- print0(thing, C);
- p.print(", ");
- if (i > maxArrayLength)
- {
- p.print("...");
- break;
- }
- }
- depth--;
- p.println();
- indent(); p.print("}");
- return;
- }
- indent(); p.println("{");
- depth++;
- if (C == java.lang.Class.class)
- {
- indent();
- p.println ("class = " + O.toString() + ",");
- }
- else if (C == java.lang.reflect.Field.class)
- {
- indent();
- p.println ("<field> = \"" + O.toString() + "\",");
- }
- else if (C == java.lang.String.class)
- {
- indent();
- p.println ("<string> = \"" + O.toString() + "\",");
- }
- Field[] f = internalGetFields(C);
- for (int i = 0; i < f.length; i++)
- {
- Class type = f[i].getType();
- boolean isStatic = (f[i].getModifiers() & Modifier.STATIC) != 0;
-
- if (isStatic && ! printStaticFields)
- continue;
- indent();
- if (isStatic)
- p.print("static ");
- p.print(type.getName() +" " +f[i].getName() + " = ");
- Object thing = getField(O, f[i]);
- print0(thing, type);
- p.println(",");
- }
- depth--;
- indent(); p.print("}");
- }
- catch (Throwable t)
- {
- p.print("error: 0x" + Long.toHexString(getAddr(O)) + ";");
- depth = savedDepth;
- }
- }
- private void print0(Object thing, Class C)
- {
- try
- {
- if (thing == null)
- {
- p.print("null");
- return;
- }
- else if (C == gnu.gcj.RawData.class ||
- C == gnu.gcj.RawDataManaged.class)
- {
- }
- else if (C.isPrimitive())
- {
- if (getItsClass(thing) == Character.class)
- p.print("'" + thing + "'");
- else
- p.print(thing);
- return;
- }
- else if (getItsClass(thing) == String.class)
- {
- p.print("\"" + thing + "\"");
- return;
- }
- else if (depth < maxdepth && h.get(thing) == null)
- {
- depth++;
- print(thing);
- depth--;
- return;
- }
- }
- catch (Throwable t)
- {
- }
-
- // The default action: just print the address.
- p.print("0x"+ Long.toHexString(getAddr(thing)));
- }
- // Print the textual representation of an object on System.err.
- public void write(Object O)
- {
- depth = 0;
- print(O);
- p.flush();
- }
- }
|