jvmti-int.h (_Jv_ReportJVMTIExceptionThrow): Declare.

* include/jvmti-int.h (_Jv_ReportJVMTIExceptionThrow):
        Declare.
        * interpret.cc (_Jv_ReportJVMTIExceptionThrow): New function.
        (find_catch_location): New function.
        (REPORT_EXCEPTION): New macro.
        (throw_internal_error): Use REPORT_EXCEPTION.
        (throw_incompatible_class_change_error): Likewise.
        (throw_null_pointer_exception): Likewise.
        (throw_class_format_error): Likewise.
        * interpret-run.cc (INTERP_REPORT_EXCEPTION)[DEBUG]: Set
        to REPORT_EXCEPTION.
        (INTERP_REPORT_EXCEPTION)[!DEBUG]: Make nop.
        (insn_new): Use INTERP_REPORT_EXCEPTION.
        (insn_athrow): Likewise.
        Remove previous JVMTI exception notifications.
        Add JVMTI ExceptionCatch notificatin.
        * jni.cc (_Jv_PopSystemFrame): Notify JVMTI clients of
        exception throw.
        * gnu/gcj/jvmti/ExceptionEvent.java: Removed.
        * gnu/gcj/jvmti/ExceptionEvent.h: Removed.
        * classpath/lib/gnu/gcj/jvmti/ExceptionEvent.class: Removed.
        * gnu/classpath/jdwp/natVMVirtualMachine.cc
        (jdwpExceptionCB): New function.
        (jdwpVMInitCB): Set Exception event handler and enable.
        * sources.am: Regenerated.
        * Makefile.in: Regenerated.

From-SVN: r124406
This commit is contained in:
Keith Seitz 2007-05-04 01:04:11 +00:00 committed by Keith Seitz
parent 820b51ae16
commit befd756626
11 changed files with 198 additions and 169 deletions

View File

@ -1,3 +1,32 @@
2007-05-03 Keith Seitz <keiths@redhat.com>
* include/jvmti-int.h (_Jv_ReportJVMTIExceptionThrow):
Declare.
* interpret.cc (_Jv_ReportJVMTIExceptionThrow): New function.
(find_catch_location): New function.
(REPORT_EXCEPTION): New macro.
(throw_internal_error): Use REPORT_EXCEPTION.
(throw_incompatible_class_change_error): Likewise.
(throw_null_pointer_exception): Likewise.
(throw_class_format_error): Likewise.
* interpret-run.cc (INTERP_REPORT_EXCEPTION)[DEBUG]: Set
to REPORT_EXCEPTION.
(INTERP_REPORT_EXCEPTION)[!DEBUG]: Make nop.
(insn_new): Use INTERP_REPORT_EXCEPTION.
(insn_athrow): Likewise.
Remove previous JVMTI exception notifications.
Add JVMTI ExceptionCatch notificatin.
* jni.cc (_Jv_PopSystemFrame): Notify JVMTI clients of
exception throw.
* gnu/gcj/jvmti/ExceptionEvent.java: Removed.
* gnu/gcj/jvmti/ExceptionEvent.h: Removed.
* classpath/lib/gnu/gcj/jvmti/ExceptionEvent.class: Removed.
* gnu/classpath/jdwp/natVMVirtualMachine.cc
(jdwpExceptionCB): New function.
(jdwpVMInitCB): Set Exception event handler and enable.
* sources.am: Regenerated.
* Makefile.in: Regenerated.
2007-05-03 Thomas Fitzsimmons <fitzsim@redhat.com>
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=237304

View File

@ -1349,7 +1349,6 @@ gnu_gcj_io_header_files = $(patsubst %.java,%.h,$(gnu_gcj_io_source_files))
gnu_gcj_jvmti_source_files = \
gnu/gcj/jvmti/Breakpoint.java \
gnu/gcj/jvmti/BreakpointManager.java \
gnu/gcj/jvmti/ExceptionEvent.java \
gnu/gcj/jvmti/Location.java
gnu_gcj_jvmti_header_files = $(patsubst %.java,%.h,$(gnu_gcj_jvmti_source_files))

View File

@ -21,6 +21,7 @@ details. */
#include <java/lang/String.h>
#include <java/lang/StringBuilder.h>
#include <java/lang/Thread.h>
#include <java/lang/Throwable.h>
#include <java/nio/ByteBuffer.h>
#include <java/nio/ByteBufferImpl.h>
#include <java/util/ArrayList.h>
@ -37,6 +38,7 @@ details. */
#include <gnu/classpath/jdwp/VMVirtualMachine.h>
#include <gnu/classpath/jdwp/event/BreakpointEvent.h>
#include <gnu/classpath/jdwp/event/ClassPrepareEvent.h>
#include <gnu/classpath/jdwp/event/ExceptionEvent.h>
#include <gnu/classpath/jdwp/event/EventManager.h>
#include <gnu/classpath/jdwp/event/EventRequest.h>
#include <gnu/classpath/jdwp/event/SingleStepEvent.h>
@ -82,6 +84,9 @@ static void handle_single_step (jvmtiEnv *, struct step_info *, jthread,
static void JNICALL jdwpBreakpointCB (jvmtiEnv *, JNIEnv *, jthread,
jmethodID, jlocation);
static void JNICALL jdwpClassPrepareCB (jvmtiEnv *, JNIEnv *, jthread, jclass);
static void JNICALL jdwpExceptionCB (jvmtiEnv *, JNIEnv *jni_env, jthread,
jmethodID, jlocation, jobject,
jmethodID, jlocation);
static void JNICALL jdwpSingleStepCB (jvmtiEnv *, JNIEnv *, jthread,
jmethodID, jlocation);
static void JNICALL jdwpThreadEndCB (jvmtiEnv *, JNIEnv *, jthread);
@ -932,6 +937,56 @@ jdwpClassPrepareCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
Jdwp::notify (event);
}
static void JNICALL
jdwpExceptionCB (jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env, jthread thread,
jmethodID method, jlocation location, jobject exception,
jmethodID catch_method, jlocation catch_location)
{
using namespace gnu::classpath::jdwp;
jclass throw_klass;
jvmtiError err = env->GetMethodDeclaringClass (method, &throw_klass);
if (err != JVMTI_ERROR_NONE)
{
fprintf (stderr, "libgcj: internal error: could not find class for ");
fprintf (stderr, "method throwing exception -- continuing\n");
return;
}
VMMethod *vmmethod = new VMMethod (throw_klass,
reinterpret_cast<jlong> (method));
Location *throw_loc = new Location (vmmethod, location);
Location *catch_loc = NULL;
if (catch_method == 0)
catch_loc = Location::getEmptyLocation ();
else
{
jclass catch_klass;
err = env->GetMethodDeclaringClass (catch_method, &catch_klass);
if (err != JVMTI_ERROR_NONE)
{
fprintf (stderr,
"libgcj: internal error: could not find class for ");
fprintf (stderr,
"method catching exception -- ignoring\n");
}
else
{
vmmethod = new VMMethod (catch_klass,
reinterpret_cast<jlong> (catch_method));
catch_loc = new Location (vmmethod, catch_location);
}
}
_Jv_InterpFrame *iframe
= reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
jobject instance = (iframe == NULL) ? NULL : iframe->get_this_ptr ();
Throwable *throwable = reinterpret_cast<Throwable *> (exception);
event::ExceptionEvent *e = new ExceptionEvent (throwable, thread,
throw_loc, catch_loc,
throw_klass, instance);
Jdwp::notify (e);
}
static void JNICALL
jdwpSingleStepCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread,
jmethodID method, jlocation location)
@ -1034,6 +1089,7 @@ jdwpVMInitCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
jvmtiEventCallbacks callbacks;
DEFINE_CALLBACK (callbacks, Breakpoint);
DEFINE_CALLBACK (callbacks, ClassPrepare);
DEFINE_CALLBACK (callbacks, Exception);
DEFINE_CALLBACK (callbacks, SingleStep);
DEFINE_CALLBACK (callbacks, ThreadEnd);
DEFINE_CALLBACK (callbacks, ThreadStart);
@ -1043,6 +1099,7 @@ jdwpVMInitCB (MAYBE_UNUSED jvmtiEnv *env, MAYBE_UNUSED JNIEnv *jni_env,
// Enable callbacks
ENABLE_EVENT (BREAKPOINT, NULL);
ENABLE_EVENT (CLASS_PREPARE, NULL);
ENABLE_EVENT (EXCEPTION, NULL);
// SingleStep is enabled only when needed
ENABLE_EVENT (THREAD_END, NULL);
ENABLE_EVENT (THREAD_START, NULL);

View File

@ -1,44 +0,0 @@
// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-
#ifndef __gnu_gcj_jvmti_ExceptionEvent__
#define __gnu_gcj_jvmti_ExceptionEvent__
#pragma interface
#include <java/lang/Object.h>
extern "Java"
{
namespace gnu
{
namespace gcj
{
namespace jvmti
{
class ExceptionEvent;
}
}
}
}
class gnu::gcj::jvmti::ExceptionEvent : public ::java::lang::Object
{
ExceptionEvent(::java::lang::Thread *, jlong, jlong, ::java::lang::Throwable *, jlong, jlong);
public:
static void postExceptionEvent(::java::lang::Thread *, jlong, jlong, ::java::lang::Throwable *, jlong, jlong);
virtual void sendEvent();
virtual void checkCatch();
private:
jlong __attribute__((aligned(__alignof__( ::java::lang::Object)))) _throwMeth;
jlong _throwLoc;
jlong _catchMeth;
jlong _catchLoc;
::java::lang::Thread * _thread;
::java::lang::Throwable * _ex;
static ::java::util::WeakHashMap * _exMap;
public:
static ::java::lang::Class class$;
};
#endif // __gnu_gcj_jvmti_ExceptionEvent__

View File

@ -1,96 +0,0 @@
// ExceptionEvent - an exception event for JVMTI
/* Copyright (C) 2007 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. */
package gnu.gcj.jvmti;
import java.util.WeakHashMap;
/**
* Class to create and send JVMTI Exception events
*
* @author Kyle Galloway (kgallowa@redhat.com)
*/
public class ExceptionEvent
{
// Information about where the exception was thrown
private long _throwMeth, _throwLoc;
// Information about where the exception was or can be caught
private long _catchMeth, _catchLoc;
// Thread where the exception occurred
private Thread _thread;
// The exception
private Throwable _ex;
// A hash map of the exceptions we've already seen in a thread's call stack
private static WeakHashMap<Thread, Throwable> _exMap = new WeakHashMap<Thread, Throwable>();
/**
* Constructs a new ExceptionEvent and sends it. If it is not caught
* within the frame where it was thrown (catchMeth and catchLoc are null),
* check_catch will check for a possible catch further up the call stack
* before marking it uncaught.
*
* @param thr the thread where the exception occurred
* @param throwMeth the method of the throw (a jmethodID)
* @param throwLoc the location of the throw (a jlocation)
* @param ex the exception
* @param catchMeth the method of the catch (a jmethodID), null indicates
* that the exception was not caught in the frame where it was thrown
* @param catchLoc the location of the catch (a jlocation), null indicates
* that the exception was not caught in the frame where it was thrown
*/
private ExceptionEvent(Thread thr, long throwMeth, long throwLoc,
Throwable ex, long catchMeth, long catchLoc)
{
this._thread = thr;
this._ex = ex;
this._throwMeth = throwMeth;
this._throwLoc = throwLoc;
this._catchMeth = catchMeth;
this._catchLoc = catchLoc;
}
public static void postExceptionEvent(Thread thr, long throwMeth,
long throwLoc, Throwable ex,
long catchMeth, long catchLoc)
{
// Check to see if there is an entry for this Thread thr in the has map.
// If not, add the thread to the hash map and send an ExceptionEvent.
if (_exMap.containsKey(thr))
{
// Check to see if we are receiving events for the same exception, or a
// new one. If it is not the same exception beign rethrown, send a new
// event.
if (!(_exMap.get(thr) == ex))
{
_exMap.put(thr, ex);
ExceptionEvent event = new ExceptionEvent(thr, throwMeth,
throwLoc, ex, catchMeth,
catchLoc);
event.sendEvent ();
}
}
else
{
_exMap.put(thr, ex);
ExceptionEvent event = new ExceptionEvent(thr, throwMeth,
throwLoc, ex, catchMeth,
catchLoc);
event.sendEvent();
}
}
public native void sendEvent();
public native void checkCatch();
}

View File

@ -89,4 +89,6 @@ extern void _Jv_JVMTI_PostEvent (jvmtiEvent type, jthread event_thread, ...)
// Returns the jvmtiEnv used by the JDWP backend
extern jvmtiEnv *_Jv_GetJDWP_JVMTIEnv (void);
// Reports JVMTI excpetions
extern void _Jv_ReportJVMTIExceptionThrow (jthrowable);
#endif /* __GCJ_JVMTI_INT_H__ */

View File

@ -377,7 +377,9 @@ details. */
} \
while (0)
#else
#undef INTERP_REPORT_EXCEPTION
#define INTERP_REPORT_EXCEPTION(Jthrowable) REPORT_EXCEPTION (Jthrowable)
#else // !DEBUG
#undef NEXT_INSN
#define NEXT_INSN goto *((pc++)->insn)
#define REWRITE_INSN(INSN,SLOT,VALUE) \
@ -386,7 +388,10 @@ details. */
pc[-1].SLOT = VALUE; \
} \
while (0)
#endif
#undef INTERP_REPORT_EXCEPTION
#define INTERP_REPORT_EXCEPTION(Jthrowable) /* not needed when not debugging */
#endif // !DEBUG
#define INTVAL() ((pc++)->int_val)
#define AVAL() ((pc++)->datum)
@ -2355,7 +2360,11 @@ details. */
/* VM spec, section 3.11.5 */
if ((klass->getModifiers() & Modifier::ABSTRACT)
|| klass->isInterface())
throw new java::lang::InstantiationException;
{
jthrowable t = new java::lang::InstantiationException;
INTERP_REPORT_EXCEPTION (t);
throw t;
}
jobject res = _Jv_AllocObject (klass);
PUSHA (res);
@ -2422,7 +2431,9 @@ details. */
insn_athrow:
{
jobject value = POPA();
throw static_cast<jthrowable>(value);
jthrowable t = static_cast<jthrowable> (value);
INTERP_REPORT_EXCEPTION (t);
throw t;
}
NEXT_INSN;
@ -2639,10 +2650,6 @@ details. */
}
catch (java::lang::Throwable *ex)
{
#ifdef DEBUG
// This needs to be done before the pc is changed.
jlong throw_loc = meth->insn_index (pc);
#endif
// Check if the exception is handled and, if so, set the pc to the start
// of the appropriate catch block.
if (meth->check_handler (&pc, meth, ex))
@ -2650,27 +2657,19 @@ details. */
sp = stack;
sp++->o = ex; // Push exception.
#ifdef DEBUG
if (JVMTI_REQUESTED_EVENT (Exception))
if (JVMTI_REQUESTED_EVENT (ExceptionCatch))
{
using namespace gnu::gcj::jvmti;
jlong throw_meth = reinterpret_cast<jlong> (meth->get_method ());
jlong catch_meth = reinterpret_cast<jlong> (meth->get_method ());
jlong catch_loc = meth->insn_index (pc);
ExceptionEvent::postExceptionEvent (thread, throw_meth,
throw_loc, ex, throw_meth,
catch_loc);
_Jv_JVMTI_PostEvent (JVMTI_EVENT_EXCEPTION_CATCH, thread,
_Jv_GetCurrentJNIEnv (), catch_meth,
catch_loc, ex);
}
#endif
NEXT_INSN;
}
#ifdef DEBUG
if (JVMTI_REQUESTED_EVENT (Exception))
{
using namespace gnu::gcj::jvmti;
jlong throw_meth = reinterpret_cast<jlong> (meth->get_method ());
ExceptionEvent::postExceptionEvent (thread, throw_meth, throw_loc,
ex, NULL, NULL);
}
#endif
// No handler, so re-throw.
throw ex;
}

View File

@ -40,7 +40,6 @@ details. */
#include <jvmti.h>
#include "jvmti-int.h"
#include <gnu/classpath/jdwp/Jdwp.h>
#include <gnu/gcj/jvmti/Breakpoint.h>
#include <gnu/gcj/jvmti/BreakpointManager.h>
#include <gnu/gcj/jvmti/ExceptionEvent.h>
@ -66,6 +65,16 @@ static void throw_class_format_error (jstring msg)
static void throw_class_format_error (const char *msg)
__attribute__ ((__noreturn__));
static void find_catch_location (jthrowable, jthread, jmethodID *, jlong *);
// A macro to facilitate JVMTI exception reporting
#define REPORT_EXCEPTION(Jthrowable) \
do { \
if (JVMTI_REQUESTED_EVENT (Exception)) \
_Jv_ReportJVMTIExceptionThrow (Jthrowable); \
} \
while (0)
#ifdef DIRECT_THREADED
// Lock to ensure that methods are not compiled concurrently.
// We could use a finer-grained lock here, however it is not safe to use
@ -956,19 +965,25 @@ _Jv_InterpMethod::run_debug (void *retp, ffi_raw *args, _Jv_InterpMethod *meth)
static void
throw_internal_error (const char *msg)
{
throw new java::lang::InternalError (JvNewStringLatin1 (msg));
jthrowable t = new java::lang::InternalError (JvNewStringLatin1 (msg));
REPORT_EXCEPTION (t);
throw t;
}
static void
throw_incompatible_class_change_error (jstring msg)
{
throw new java::lang::IncompatibleClassChangeError (msg);
jthrowable t = new java::lang::IncompatibleClassChangeError (msg);
REPORT_EXCEPTION (t);
throw t;
}
static void
throw_null_pointer_exception ()
{
throw new java::lang::NullPointerException;
jthrowable t = new java::lang::NullPointerException;
REPORT_EXCEPTION (t);
throw t;
}
/* Look up source code line number for given bytecode (or direct threaded
@ -1613,9 +1628,11 @@ _Jv_JNIMethod::ncode (jclass klass)
static void
throw_class_format_error (jstring msg)
{
throw (msg
jthrowable t = (msg
? new java::lang::ClassFormatError (msg)
: new java::lang::ClassFormatError);
REPORT_EXCEPTION (t);
throw t;
}
static void
@ -1624,6 +1641,70 @@ throw_class_format_error (const char *msg)
throw_class_format_error (JvNewStringLatin1 (msg));
}
/* This function finds the method and location where the exception EXC
is caught in the stack frame. On return, it sets CATCH_METHOD and
CATCH_LOCATION with the method and location where the catch will
occur. If the exception is not caught, these are set to 0.
This function should only be used with the DEBUG interpreter. */
static void
find_catch_location (::java::lang::Throwable *exc, jthread thread,
jmethodID *catch_method, jlong *catch_loc)
{
*catch_method = 0;
*catch_loc = 0;
_Jv_InterpFrame *frame
= reinterpret_cast<_Jv_InterpFrame *> (thread->interp_frame);
while (frame != NULL)
{
pc_t pc = frame->get_pc ();
_Jv_InterpMethod *imeth
= reinterpret_cast<_Jv_InterpMethod *> (frame->self);
if (imeth->check_handler (&pc, imeth, exc))
{
// This method handles the exception.
*catch_method = imeth->get_method ();
*catch_loc = imeth->insn_index (pc);
return;
}
frame = frame->next_interp;
}
}
/* This method handles JVMTI notifications of thrown exceptions. It
calls find_catch_location to figure out where the exception is
caught (if it is caught).
Like find_catch_location, this should only be called with the
DEBUG interpreter. Since a few exceptions occur outside the
interpreter proper, it is important to not call this function
without checking JVMTI_REQUESTED_EVENT(Exception) first. */
void
_Jv_ReportJVMTIExceptionThrow (jthrowable ex)
{
jthread thread = ::java::lang::Thread::currentThread ();
_Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
jmethodID throw_meth = frame->self->get_method ();
jlocation throw_loc = -1;
if (frame->frame_type == frame_interpreter)
{
_Jv_InterpFrame * iframe
= reinterpret_cast<_Jv_InterpFrame *> (frame);
_Jv_InterpMethod *imeth
= reinterpret_cast<_Jv_InterpMethod *> (frame->self);
throw_loc = imeth->insn_index (iframe->get_pc ());
}
jlong catch_loc;
jmethodID catch_method;
find_catch_location (ex, thread, &catch_method, &catch_loc);
_Jv_JVMTI_PostEvent (JVMTI_EVENT_EXCEPTION, thread,
_Jv_GetCurrentJNIEnv (), throw_meth, throw_loc,
ex, catch_method, catch_loc);
}
void

View File

@ -23,6 +23,7 @@ details. */
#include <jvmpi.h>
#endif
#include <jvmti.h>
#include "jvmti-int.h"
#include <java/lang/Class.h>
#include <java/lang/ClassLoader.h>
@ -456,6 +457,8 @@ _Jv_JNI_PopSystemFrame (JNIEnv *env)
{
jthrowable t = env->ex;
env->ex = NULL;
if (JVMTI_REQUESTED_EVENT (Exception))
_Jv_ReportJVMTIExceptionThrow (t);
throw t;
}
}

View File

@ -538,7 +538,6 @@ gnu/gcj/io.list: $(gnu_gcj_io_source_files)
gnu_gcj_jvmti_source_files = \
gnu/gcj/jvmti/Breakpoint.java \
gnu/gcj/jvmti/BreakpointManager.java \
gnu/gcj/jvmti/ExceptionEvent.java \
gnu/gcj/jvmti/Location.java
gnu_gcj_jvmti_header_files = $(patsubst %.java,%.h,$(gnu_gcj_jvmti_source_files))