Makefile.am (libgcj_la_SOURCES): Remove name-finder.cc.
* Makefile.am (libgcj_la_SOURCES): Remove name-finder.cc. (core_java_source_files): Add VMThrowable.java and NameFinder.java (nat_source_files): Remove natThrowable.cc, add natVMThrowable.cc and natNameFinder.cc. * Makefile.in: Regenerate. * prims.cc: Use trace_enabled from VMThrowable. * name-finder.cc: Removed. * gcj/javaprims.h: Add class VMThrowable. * gnu/gcj/runtime/NameFinder.java: New file. * gnu/gcj/runtime/natNameFinder.cc: Likewise. * include/name-finder.h: Removed. * java/lang/Throwable.java (printStackTrace (PrintStream)): Use new method stackTraceString(). (printStackTrace (PrintWriter)): Likewise. (stackTraceString): Complete rewrite of old printStackTrace using StringBuffer. (stackTraceStringBuffer): New helper method for stackTraceString(). (fillInStackTrace): Delegate to VMTrowable. (getStackTrace): Likewise. (getStackTrace0): Removed. (trace_enabled, stackTraceBytes): Moved to new VMThrowable.java. (setStackTrace): Copy given array. * java/lang/natThrowable.cc: Removed (replaced by natVMThrowable). * java/lang/VMThrowable.java: New class. * java/lang/natVMThrowable.cc: New file. From-SVN: r56556
This commit is contained in:
parent
4906d5d83e
commit
6e0532cdf6
13 changed files with 821 additions and 645 deletions
|
@ -46,11 +46,6 @@ import java.io.ObjectInputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* @author Tom Tromey <tromey@cygnus.com>
|
||||
* @date October 30, 1998
|
||||
*/
|
||||
|
||||
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
|
||||
* "The Java Language Specification", ISBN 0-201-63451-1
|
||||
* Status: Sufficient for compiled code, but methods applicable to
|
||||
|
@ -116,7 +111,7 @@ import java.io.OutputStream;
|
|||
* @author Tom Tromey
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @since 1.0
|
||||
* @status still missing 1.4 functionality
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public class Throwable implements Serializable
|
||||
{
|
||||
|
@ -130,7 +125,7 @@ public class Throwable implements Serializable
|
|||
*
|
||||
* @serial specific details about the exception, may be null
|
||||
*/
|
||||
private String detailMessage;
|
||||
private final String detailMessage;
|
||||
|
||||
/**
|
||||
* The cause of the throwable, including null for an unknown or non-chained
|
||||
|
@ -374,7 +369,7 @@ public class Throwable implements Serializable
|
|||
*/
|
||||
public void printStackTrace(PrintStream s)
|
||||
{
|
||||
printStackTrace(new PrintWriter(s));
|
||||
s.print(stackTraceString());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -409,72 +404,88 @@ public class Throwable implements Serializable
|
|||
*/
|
||||
public void printStackTrace (PrintWriter pw)
|
||||
{
|
||||
// First line
|
||||
pw.println(toString());
|
||||
pw.print(stackTraceString());
|
||||
}
|
||||
|
||||
// The stacktrace
|
||||
private static final String nl = System.getProperty("line.separator");
|
||||
// Create whole stack trace in a stringbuffer so we don't have to print
|
||||
// it line by line. This prevents printing multiple stack traces from
|
||||
// different threads to get mixed up when written to the same PrintWriter.
|
||||
private String stackTraceString()
|
||||
{
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
// Main stacktrace
|
||||
StackTraceElement[] stack = getStackTrace();
|
||||
if (stack == null || stack.length == 0)
|
||||
{
|
||||
pw.println(" <<No stacktrace available>>");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < stack.length; i++)
|
||||
pw.println(" at " + stack[i]);
|
||||
}
|
||||
stackTraceStringBuffer(sb, this.toString(), stack, 0);
|
||||
|
||||
// The cause(s)
|
||||
Throwable cause = getCause();
|
||||
while (cause != null)
|
||||
{
|
||||
// Cause first line
|
||||
pw.println("Caused by: " + cause);
|
||||
// Cause start first line
|
||||
sb.append("Caused by: ");
|
||||
|
||||
// Cause stacktrace
|
||||
StackTraceElement[] parentStack = stack;
|
||||
stack = cause.getStackTrace();
|
||||
if (stack == null || stack.length == 0)
|
||||
{
|
||||
pw.println(" <<No stacktrace available>>");
|
||||
}
|
||||
else if (parentStack == null || parentStack.length == 0)
|
||||
{
|
||||
for (int i = 0; i < stack.length; i++)
|
||||
pw.println(" at " + stack[i]);
|
||||
}
|
||||
if (parentStack == null || parentStack.length == 0)
|
||||
stackTraceStringBuffer(sb, cause.toString(), stack, 0);
|
||||
else
|
||||
{
|
||||
boolean equal = false; // Is rest of stack equal to parent frame?
|
||||
for (int i = 0; i < stack.length && ! equal; i++)
|
||||
int equal = 0; // Count how many of the last stack frames are equal
|
||||
int frame = stack.length-1;
|
||||
int parentFrame = parentStack.length-1;
|
||||
while (frame > 0 && parentFrame > 0)
|
||||
{
|
||||
// Check if we already printed the rest of the stack
|
||||
// since it was the tail of the parent stack
|
||||
int remaining = stack.length - i;
|
||||
int element = i;
|
||||
int parentElement = parentStack.length - remaining;
|
||||
equal = parentElement >= 0
|
||||
&& parentElement < parentStack.length; // be optimistic
|
||||
while (equal && element < stack.length)
|
||||
if (stack[frame].equals(parentStack[parentFrame]))
|
||||
{
|
||||
if (stack[element].equals(parentStack[parentElement]))
|
||||
{
|
||||
element++;
|
||||
parentElement++;
|
||||
}
|
||||
else
|
||||
equal = false;
|
||||
equal++;
|
||||
frame--;
|
||||
parentFrame--;
|
||||
}
|
||||
// Print stacktrace element or indicate the rest is equal
|
||||
if (! equal)
|
||||
pw.println(" at " + stack[i]);
|
||||
else
|
||||
pw.println(" ..." + remaining + " more");
|
||||
break;
|
||||
}
|
||||
stackTraceStringBuffer(sb, cause.toString(), stack, equal);
|
||||
}
|
||||
cause = cause.getCause();
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// Adds to the given StringBuffer a line containing the name and
|
||||
// all stacktrace elements minus the last equal ones.
|
||||
private static void stackTraceStringBuffer(StringBuffer sb, String name,
|
||||
StackTraceElement[] stack, int equal)
|
||||
{
|
||||
// (finish) first line
|
||||
sb.append(name);
|
||||
sb.append(nl);
|
||||
|
||||
// The stacktrace
|
||||
if (stack == null || stack.length == 0)
|
||||
{
|
||||
sb.append(" <<No stacktrace available>>");
|
||||
sb.append(nl);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < stack.length-equal; i++)
|
||||
{
|
||||
sb.append(" at ");
|
||||
sb.append(stack[i] == null ? "<<Unknown>>" : stack[i].toString());
|
||||
sb.append(nl);
|
||||
}
|
||||
if (equal > 0)
|
||||
{
|
||||
sb.append(" ...");
|
||||
sb.append(equal);
|
||||
sb.append(" more");
|
||||
sb.append(nl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -483,7 +494,13 @@ public class Throwable implements Serializable
|
|||
* @return this same throwable
|
||||
* @see #printStackTrace()
|
||||
*/
|
||||
public native Throwable fillInStackTrace();
|
||||
public Throwable fillInStackTrace()
|
||||
{
|
||||
vmState = VMThrowable.fillInStackTrace(this);
|
||||
stackTrace = null; // Should be regenerated when used.
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to the information printed in {@link #printStackTrace()}.
|
||||
|
@ -499,7 +516,13 @@ public class Throwable implements Serializable
|
|||
public StackTraceElement[] getStackTrace()
|
||||
{
|
||||
if (stackTrace == null)
|
||||
stackTrace = getStackTrace0();
|
||||
if (vmState == null)
|
||||
stackTrace = new StackTraceElement[0];
|
||||
else
|
||||
{
|
||||
stackTrace = vmState.getStackTrace(this);
|
||||
vmState = null; // No longer needed
|
||||
}
|
||||
|
||||
return stackTrace;
|
||||
}
|
||||
|
@ -508,6 +531,10 @@ public class Throwable implements Serializable
|
|||
* Change the stack trace manually. This method is designed for remote
|
||||
* procedure calls, which intend to alter the stack trace before or after
|
||||
* serialization according to the context of the remote call.
|
||||
* <p>
|
||||
* The contents of the given stacktrace is copied so changes to the
|
||||
* original * array do not change the stack trace elements of this
|
||||
* throwable.
|
||||
*
|
||||
* @param stackTrace the new trace to use
|
||||
* @throws NullPointerException if stackTrace is null or has null elements
|
||||
|
@ -515,15 +542,22 @@ public class Throwable implements Serializable
|
|||
*/
|
||||
public void setStackTrace(StackTraceElement[] stackTrace)
|
||||
{
|
||||
for (int i = stackTrace.length; --i >= 0; )
|
||||
int i = stackTrace.length;
|
||||
StackTraceElement[] st = new StackTraceElement[i];
|
||||
|
||||
while (--i >= 0)
|
||||
if (stackTrace[i] == null)
|
||||
throw new NullPointerException();
|
||||
this.stackTrace = stackTrace;
|
||||
throw new NullPointerException();
|
||||
else
|
||||
st[i] = stackTrace[i];
|
||||
|
||||
this.stackTrace = st;
|
||||
}
|
||||
|
||||
private native final StackTraceElement[] getStackTrace0 ();
|
||||
|
||||
// Setting this flag to false prevents fillInStackTrace() from running.
|
||||
static boolean trace_enabled = true;
|
||||
private transient byte stackTraceBytes[];
|
||||
/**
|
||||
* VM state when fillInStackTrace was called.
|
||||
* Used by getStackTrace() to get an array of StackTraceElements.
|
||||
* Cleared when no longer needed.
|
||||
*/
|
||||
private transient VMThrowable vmState;
|
||||
}
|
||||
|
|
97
libjava/java/lang/VMThrowable.java
Normal file
97
libjava/java/lang/VMThrowable.java
Normal file
|
@ -0,0 +1,97 @@
|
|||
/* java.lang.VMThrowable -- VM support methods for Throwable.
|
||||
Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
package java.lang;
|
||||
|
||||
import gnu.gcj.runtime.NameFinder;
|
||||
|
||||
/**
|
||||
* VM dependant state and support methods Throwabele.
|
||||
* It is deliberately package local and final and should only be accessed
|
||||
* by the Throwable class.
|
||||
* <p>
|
||||
* This is the version used by libgcj (http://gcc.gnu.org/java/).
|
||||
*
|
||||
* @author Mark Wielaard (mark@klomp.org)
|
||||
*/
|
||||
final class VMThrowable
|
||||
{
|
||||
private gnu.gcj.RawData stackTraceAddrs;
|
||||
private int length;
|
||||
|
||||
/**
|
||||
* Private contructor, create VMThrowables with fillInStackTrace();
|
||||
*/
|
||||
private VMThrowable() { }
|
||||
|
||||
/**
|
||||
* Fill in the stack trace with the current execution stack.
|
||||
* Called by <code>Throwable.fillInStackTrace()</code> to get the state of
|
||||
* the VM. Can return null when the VM does not support caputing the VM
|
||||
* execution state.
|
||||
*
|
||||
* @return a new VMThrowable containing the current execution stack trace.
|
||||
* @see Throwable#fillInStackTrace()
|
||||
*/
|
||||
static native VMThrowable fillInStackTrace(Throwable t);
|
||||
|
||||
/**
|
||||
* Returns an <code>StackTraceElement</code> array based on the execution
|
||||
* state of the VM as captured by <code>fillInStackTrace</code>.
|
||||
* Called by <code>Throwable.getStackTrace()</code>.
|
||||
*
|
||||
* @return a non-null but possible zero length array of StackTraceElement.
|
||||
* @see Throwable#getStackTrace()
|
||||
*/
|
||||
StackTraceElement[] getStackTrace(Throwable t)
|
||||
{
|
||||
StackTraceElement[] result;
|
||||
if (stackTraceAddrs != null)
|
||||
{
|
||||
NameFinder nameFinder = new NameFinder();
|
||||
result = nameFinder.lookup(t, stackTraceAddrs, length);
|
||||
nameFinder.close();
|
||||
}
|
||||
else
|
||||
result = new StackTraceElement[0];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Setting this flag to false prevents fillInStackTrace() from running.
|
||||
static boolean trace_enabled = true;
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
// natThrowable.cc - Superclass for all exceptions.
|
||||
|
||||
/* Copyright (C) 2000 Free Software Foundation, Inc
|
||||
|
||||
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. */
|
||||
|
||||
/**
|
||||
* @author Andrew Haley <aph@cygnus.com>
|
||||
* @date Jan 6 2000
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gcj/cni.h>
|
||||
#include <jvm.h>
|
||||
#include <java/lang/Object.h>
|
||||
#include <java-threads.h>
|
||||
#include <java/lang/Throwable.h>
|
||||
#include <java/lang/StackTraceElement.h>
|
||||
#include <java/io/PrintStream.h>
|
||||
#include <java/io/PrintWriter.h>
|
||||
#include <java/io/IOException.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
#include <name-finder.h>
|
||||
|
||||
/* FIXME: size of the stack trace is limited to 128 elements. It's
|
||||
undoubtedly sensible to limit the stack trace, but 128 is rather
|
||||
arbitrary. It may be better to configure this. */
|
||||
|
||||
java::lang::Throwable *
|
||||
java::lang::Throwable::fillInStackTrace (void)
|
||||
{
|
||||
if (! trace_enabled)
|
||||
return this;
|
||||
#if defined (HAVE_BACKTRACE)
|
||||
void *p[128];
|
||||
|
||||
// We subtract 1 from the number of elements because we don't want
|
||||
// to include the call to fillInStackTrace in the trace.
|
||||
int n = backtrace (p, 128) - 1;
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
// We copy the array below to deal with alignment issues.
|
||||
stackTraceBytes = JvNewByteArray (n * sizeof p[0]);
|
||||
memcpy (elements (stackTraceBytes), p+1, (n * sizeof p[0]));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
JArray<java::lang::StackTraceElement*> *
|
||||
java::lang::Throwable::getStackTrace0 ()
|
||||
{
|
||||
#ifdef HAVE_BACKTRACE
|
||||
if (!stackTraceBytes)
|
||||
return NULL;
|
||||
|
||||
int depth = stackTraceBytes->length / sizeof (void *);
|
||||
void *p[depth];
|
||||
// This memcpy is esential; it ensures that the array of void* is
|
||||
// correctly aligned.
|
||||
memcpy (p, elements (stackTraceBytes), sizeof p);
|
||||
|
||||
JArray<java::lang::StackTraceElement*> *result;
|
||||
java::lang::StackTraceElement** el;
|
||||
result = reinterpret_cast <JArray<java::lang::StackTraceElement *>*>
|
||||
(JvNewObjectArray (depth, &java::lang::StackTraceElement::class$, NULL));
|
||||
el = elements (result);
|
||||
|
||||
_Jv_name_finder finder (_Jv_ThisExecutable ());
|
||||
|
||||
for (int i = 0; i < depth; i++)
|
||||
el[i] = finder.lookup (p[i]);
|
||||
|
||||
return result;
|
||||
#else
|
||||
return NULL;
|
||||
#endif /* HAVE_BACKTRACE */
|
||||
}
|
73
libjava/java/lang/natVMThrowable.cc
Normal file
73
libjava/java/lang/natVMThrowable.cc
Normal file
|
@ -0,0 +1,73 @@
|
|||
// natVMThrowable.cc - native helper methods for Throwable
|
||||
|
||||
/* Copyright (C) 2000, 2002 Free Software Foundation, Inc
|
||||
|
||||
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. */
|
||||
|
||||
/**
|
||||
* @author Andrew Haley <aph@cygnus.com>
|
||||
* @author Mark Wielaard <mark@klomp.org>
|
||||
*
|
||||
* Native helper methods for VM specific Throwable support.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <jvm.h>
|
||||
#include <gcj/cni.h>
|
||||
#include <gnu/gcj/RawData.h>
|
||||
#include <java/lang/Object.h>
|
||||
#include <java-threads.h>
|
||||
#include <java/lang/Throwable.h>
|
||||
#include <java/lang/VMThrowable.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
/* FIXME: size of the stack trace is limited to 128 elements. It's
|
||||
undoubtedly sensible to limit the stack trace, but 128 is rather
|
||||
arbitrary. It may be better to configure this. */
|
||||
|
||||
java::lang::VMThrowable *
|
||||
java::lang::VMThrowable::fillInStackTrace (java::lang::Throwable* t)
|
||||
{
|
||||
if (! trace_enabled)
|
||||
return NULL;
|
||||
#if defined (HAVE_BACKTRACE)
|
||||
VMThrowable* state = new VMThrowable;
|
||||
void *p[128];
|
||||
|
||||
// We subtract 1 from the number of elements because we don't want
|
||||
// to include the calls to fillInStackTrace in the trace.
|
||||
int n = backtrace (p, 128) - 1;
|
||||
|
||||
void **addrs;
|
||||
if (n > 0)
|
||||
{
|
||||
state->length = n;
|
||||
addrs = (void **) _Jv_Malloc (n * sizeof p[0]);
|
||||
while (n--)
|
||||
addrs[n] = p[n];
|
||||
}
|
||||
else
|
||||
addrs = NULL;
|
||||
|
||||
state->stackTraceAddrs = reinterpret_cast<gnu::gcj::RawData *> (addrs);
|
||||
|
||||
return state;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue