if (verbose >= 1) traceContext.push(values[i].getClass().getName(),
if (verbose >= 2) traceContext.push(values[i].getClass().getName(),
  private static int traverseObject(Object jdkObject)    throws IllegalAccessException    {      //      // don't traverse an object twice      //      final Object wrapper = jdkObject;      Object key = new Object() {        public int hashCode() { return System.identityHashCode(wrapper); }        public boolean equals(Object o) {          return getClass() == o.getClass() && hashCode() == o.hashCode();        }      };      Integer sz = (Integer) traversed.get(key);      if (sz != null) return sz.intValue(); // object already traversed      traversed.put(key, VISITED);      if (verbose >= 2) depth++;      //      // fetch object's type information      //      Class jdkType = jdkObject.getClass();      int size = OBJECT_HEADER_SIZE;      //      // recursively traverse object      //      if (jdkType.isArray()) {        size += 4; // length        int arrayCount       = Array.getLength(jdkObject);        //        // traverse array elements        // recurse on values that are references        //        Class jdkElementType = jdkType.getComponentType();        if (jdkElementType.isPrimitive()) {          // array element is logical or numeric type          if (jdkElementType == Boolean.TYPE) {            size += arrayCount*4;          } else if (jdkElementType == Byte.TYPE) {            size += arrayCount*1;          } else if (jdkElementType == Character.TYPE) {            size += arrayCount*2;          } else if (jdkElementType == Short.TYPE) {            size += arrayCount*2;          } else if (jdkElementType == Integer.TYPE) {            size += arrayCount*4;          } else if (jdkElementType == Long.TYPE) {            size += arrayCount*8;          } else if (jdkElementType == Float.TYPE) {            size += arrayCount*4;          } else if (jdkElementType == Double.TYPE) {            size += arrayCount*8;          } else            fail("unexpected array type: " + jdkType);        } else {          // array element is reference type          size += arrayCount*4;          Object values[] = (Object []) jdkObject;          for (int i = 0; i < arrayCount; ++i) {            if (values[i] != null) {              if (verbose >= 1) traceContext.push(values[i].getClass().getName(),                                                  jdkType.getName(), i);              traverseObject(values[i]);              if (verbose >= 1) traceContext.pop();            }          }        }        if (verbose >= 2) {          if (depth == depthCutoff)             say(SPACES.substring(0,depth+1), "TOO DEEP: cutting off");          else if (depth < depthCutoff) {            String tab = SPACES.substring(0,depth+1);            if (depth == 0 && jtocCount >= 0)              tab = tab + "jtoc #" + String.valueOf(jtocCount);            say(tab, "Traversed array  ", jdkType.getName(),                 "  length=", String.valueOf(arrayCount),                 "  total size=", String.valueOf(size),                (size >= LARGE_ARRAY_SIZE) ?"  large object!!!" : "");          }        }      } else {        //        // traverse object fields        // recurse on values that are references        //        for (Class type = jdkType; type != null; type = type.getSuperclass()) {          Field[] jdkFields = type.getDeclaredFields();          for (int i = 0, n = jdkFields.length; i < n; ++i) {            Field  jdkField       = jdkFields[i];            jdkField.setAccessible(true);            Class  jdkFieldType   = jdkField.getType();            if (jdkFieldType.isPrimitive()) {              // field is logical or numeric type              if (jdkFieldType == Boolean.TYPE)                size += 4;              else if (jdkFieldType == Byte.TYPE)                size += 4;              else if (jdkFieldType == Character.TYPE)                size += 4;              else if (jdkFieldType == Short.TYPE)                size += 4;              else if (jdkFieldType == Integer.TYPE)                size += 4;              else if (jdkFieldType == Long.TYPE)                size += 8;              else if (jdkFieldType == Float.TYPE)                size += 4;              else if (jdkFieldType == Double.TYPE)                size += 8;              else                fail("unexpected field type: " + jdkFieldType);            } else {              // field is reference type              size += 4;              Object value = jdkField.get(jdkObject);              if (value != null) {                if (verbose >= 1) traceContext.push(value.getClass().getName(),                                                    jdkType.getName(),                                                    jdkField.getName());                traverseObject(value);                if (verbose >= 1) traceContext.pop();              }            }          }        }        if (verbose >= 2) {          if (depth == depthCutoff)             say(SPACES.substring(0,depth+1), "TOO DEEP: cutting off");          else if (depth < depthCutoff) {            String tab = SPACES.substring(0,depth+1);            if (depth == 0 && jtocCount >= 0)              tab = tab + "#" + String.valueOf(jtocCount);            say(tab, "Traversed object ", jdkType.getName(),                 "   total size=", String.valueOf(size),                (size >= LARGE_SCALAR_SIZE) ? " large object!!!" : "");          }        }      }      traversed.put(key, new Integer(size));      if (verbose >= 2) depth--;      return size;    }