NameFinder.java (remove_interpreter): New field.
authorMark Wielaard <mark@klomp.org>
Mon, 2 Sep 2002 15:55:57 +0000 (15:55 +0000)
committerMark Wielaard <mark@gcc.gnu.org>
Mon, 2 Sep 2002 15:55:57 +0000 (15:55 +0000)
       * gnu/gcj/runtime/NameFinder.java (remove_interpreter): New field.
       (sanitizeStack): Correctly reset unknown and interpreter counters,
       detect interpreter runtime frames.
       (demangleInterpreterMethod): New method.
       * gnu/gcj/runtime/natNameFinder.cc (lookupInterp): Use new method.
       * java/lang/natVMThrowable.cc (fillInStackTrace): Change order of
       filling in addrs[].

From-SVN: r56741

libjava/ChangeLog
libjava/gnu/gcj/runtime/NameFinder.java
libjava/gnu/gcj/runtime/natNameFinder.cc
libjava/java/lang/natVMThrowable.cc

index 0fe3d270249bd60ee661c66bc7d39f1ed7f7c5e0..dabee5148f5048af6f605910954610cd3bd0228b 100644 (file)
@@ -1,3 +1,13 @@
+2002-09-01  Mark Wielaard  <mark@klomp.org>
+
+       * gnu/gcj/runtime/NameFinder.java (remove_interpreter): New field.
+       (sanitizeStack): Correctly reset unknown and interpreter counters,
+       detect interpreter runtime frames.
+       (demangleInterpreterMethod): New method.
+       * gnu/gcj/runtime/natNameFinder.cc (lookupInterp): Use new method.
+       * java/lang/natVMThrowable.cc (fillInStackTrace): Change order of
+       filling in addrs[].
+
 2002-09-02  Michael Koch  <konqueror@gmx.de>
 
        * java/net/DatagramPacket.java, java/net/MulticsstSocket.java:
index f32ebe0f530dd2a0e3516befc411b586ce1888b6..1d729d252accdca0ca1f96dfea00901e6746f89b 100644 (file)
@@ -34,11 +34,15 @@ import java.io.File;
  *     should be removed from the stack trace. Only done when names are
  *     demangled.</ul>
  * <ul><code>gnu.gcj.runtime.NameFinder.remove_unknown</code>
- *     Wheter calls to unknown functions (class and method names are unknown)
+ *     Whether calls to unknown functions (class and method names are unknown)
  *     should be removed from the stack trace. Only done when the stack is
  *     sanitized.</ul>
+ * <ul><code>gnu.gcj.runtime.NameFinder.remove_interpreter</code>
+ *     Whether runtime interpreter calls (methods in the _Jv_InterpMethod class
+ *     and functions starting with 'ffi_') should be removed from the stack
+ *     trace. Only done when the stack is sanitized.</ul>
  * <ul><code>gnu.gcj.runtime.NameFinder.use_addr2line</code>
- *     Wheter an external process (addr2line or addr2name.awk) should be used
+ *     Whether an external process (addr2line or addr2name.awk) should be used
  *     as fallback to convert the addresses to function names when the runtime
  *     is unable to do it through <code>dladdr</code>.</ul>
  * </li>
@@ -68,6 +72,10 @@ public class NameFinder
          = Boolean.valueOf(System.getProperty
                ("gnu.gcj.runtime.NameFinder.remove_unknown", "true")
            ).booleanValue();
+  private static final boolean remove_interpreter
+         = Boolean.valueOf(System.getProperty
+               ("gnu.gcj.runtime.NameFinder.remove_interpreter", "true")
+           ).booleanValue();
   private static final boolean use_addr2line
          = Boolean.valueOf(System.getProperty
                ("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
@@ -257,6 +265,7 @@ public class NameFinder
       consName = className.substring(lastDot + 1) + '(';
 
     int unknown = 0;
+    int interpreter = 0;
     int last_throw = -1;
     int length = elements.length;
     int end = length-1;
@@ -274,10 +283,20 @@ public class NameFinder
            && (MName.startsWith(consName)
                || MName.startsWith("Throwable(")
                || MName.startsWith("fillInStackTrace("))))
-         last_throw = i;
+         {
+           last_throw = i;
+           // Reset counting of unknown and interpreter frames.
+           unknown = 0;
+           interpreter = 0;
+         }
        else if (remove_unknown && CName == null 
                 && (MName == null || MName.startsWith("0x")))
          unknown++;
+       else if (remove_interpreter
+                && ((CName == null
+                     && MName != null && MName.startsWith("ffi_"))
+                    || (CName != null && CName.equals("_Jv_InterpMethod"))))
+         interpreter++;
        else if ("main(java.lang.String[])".equals(MName))
          {
            end = i;
@@ -287,20 +306,28 @@ public class NameFinder
     int begin = last_throw+1;
 
     // Now filter out everything at the start and the end that is not part
-    // of the "normal" user program including any elements that have no
-    // usefull information whatsoever unless that means we filter out all info.
-    int nr_elements = end-begin-unknown+1;
-    if ((begin > 0 || end < length-1 || unknown > 0) && nr_elements > 0)
+    // of the "normal" user program including any elements that are interpreter
+    // calls or have no usefull information whatsoever.
+    // Unless that means we filter out all info.
+    int nr_elements = end-begin-unknown-interpreter+1;
+    if ((begin > 0 || end < length-1 || unknown > 0 || interpreter > 0)
+       && nr_elements > 0)
       {
        stack = new StackTraceElement[nr_elements];
        int pos =0;
        for (int i=begin; i<=end; i++)
          {
-           String MName;
-           if (unknown == 0
-               || !(elements[i].getClassName() == null
-                    && ((MName = elements[i].getMethodName()) == null
-                        || MName.startsWith("0x"))))
+           String MName = elements[i].getMethodName();
+           String CName = elements[i].getClassName();
+           if (remove_unknown && CName == null 
+                && (MName == null || MName.startsWith("0x")))
+             ; // Skip unknown frame
+           else if (remove_interpreter
+                    && ((CName == null
+                        && MName != null && MName.startsWith("ffi_"))
+                       || (CName != null && CName.equals("_Jv_InterpMethod"))))
+             ; // Skip interpreter runtime frame
+           else
              {
                stack[pos] = elements[i];
                pos++;
@@ -394,6 +421,111 @@ public class NameFinder
     return s;
   }
 
+  /**
+   * Returns human readable method name and aguments given a method type
+   * signature as known to the interpreter and a classname.
+   */
+  public static String demangleInterpreterMethod(String m, String cn)
+  {
+    int index = 0;
+    int length = m.length();
+    StringBuffer sb = new StringBuffer(length);
+
+    // Figure out the real method name
+    if (m.startsWith("<init>"))
+      {
+       String className;
+       int i = cn.lastIndexOf('.');
+       if (i < 0)
+         className = cn;
+       else
+         className = cn.substring(i + 1);
+       sb.append(className);
+       index += 7;
+      }
+    else
+      {
+       int i = m.indexOf('(');
+       if (i > 0)
+         {
+           sb.append(m.substring(0,i));
+           index += i + 1;
+         }
+      }
+
+    sb.append('(');
+
+    // Demangle the type arguments
+    int arrayDepth = 0;
+    char c = (index < length) ? m.charAt(index) : ')';
+    while (c != ')')
+      {
+       String type;
+       switch(c)
+       {
+          case 'B':
+            type = "byte";
+           break;
+          case 'C':
+            type = "char";
+           break;
+          case 'D':
+            type = "double";
+           break;
+          case 'F':
+            type = "float";
+           break;
+          case 'I':
+            type = "int";
+           break;
+          case 'J':
+            type = "long";
+           break;
+          case 'S':
+            type = "short";
+           break;
+          case 'Z':
+            type = "boolean";
+           break;
+          case 'L':
+           int i = m.indexOf(';', index);
+           if (i > 0)
+             {
+               type = m.substring(index+1, i);
+               index = i;
+             }
+           else
+             type = "<unknown ref>";
+           break;
+          case '[':
+           type = "";
+           arrayDepth++;
+           break;
+          default:
+           type = "<unknown " + c + '>';
+       }
+       sb.append(type);
+
+       // Handle arrays
+       if (c != '[' && arrayDepth > 0)
+         while (arrayDepth > 0)
+           {
+             sb.append("[]");
+             arrayDepth--;
+           }
+
+       index++;
+       char nc = (index < length) ? m.charAt(index) : ')';
+       if (c != '[' && nc  != ')')
+         sb.append(", ");
+       c = nc;
+      }
+
+    // Stop. We are not interested in the return type.
+    sb.append(')');
+    return sb.toString();
+  }
+
   /**
    * Releases all resources used by this NameFinder.
    */
index 29488eddda72bdbf8874b5c16a4eff3d11689293..29687cb5bb9a377915dbc06eb23862384d1bb8ba 100644 (file)
@@ -95,7 +95,6 @@ gnu::gcj::runtime::NameFinder::lookupInterp(RawData* addrs, jint n)
 
   _Jv_InterpMethod *meth
     = reinterpret_cast<_Jv_InterpMethod *> (stack[n].interp);
-  // FIXME: demangle.
   java::lang::StringBuffer *sb = new java::lang::StringBuffer();
   sb->append(_Jv_NewStringUtf8Const(meth->self->name));
   sb->append(_Jv_NewStringUtf8Const(meth->self->signature));
@@ -103,9 +102,11 @@ gnu::gcj::runtime::NameFinder::lookupInterp(RawData* addrs, jint n)
   // bytecode debug information.  But currently we don't keep that
   // around.
   // FIXME: is using the defining class correct here?
+  java::lang::String *className = meth->defining_class->getName();
+  java::lang::String *methodName
+         = demangleInterpreterMethod(sb->toString(), className);
   return new java::lang::StackTraceElement(NULL, -1,
-                                          meth->defining_class->getName(),
-                                          sb->toString(), false);
+                                          className, methodName, false);
 #else // INTERPRETER
   return NULL;
 #endif // INTERPRETER
index f5c56c7a1d4639cd344ec8bd24d2a457e688436f..ce897c23e0b9bf75ebdd8f2d5862ecebecaca03a 100644 (file)
@@ -72,7 +72,7 @@ java::lang::VMThrowable::fillInStackTrace (java::lang::Throwable* t)
       state->length = n;
       int len = n;
       addrs = (_Jv_frame_info *) _Jv_Malloc (n * sizeof (_Jv_frame_info));
-      while (n--)
+      for (n = 0; n < len; n++)
        {
          addrs[n].addr = p[n];
 #ifdef INTERPRETER