summaryrefslogtreecommitdiff
path: root/libjava/jvmti.cc
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/jvmti.cc
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'libjava/jvmti.cc')
-rw-r--r--libjava/jvmti.cc2626
1 files changed, 2626 insertions, 0 deletions
diff --git a/libjava/jvmti.cc b/libjava/jvmti.cc
new file mode 100644
index 000000000..7c7923b2e
--- /dev/null
+++ b/libjava/jvmti.cc
@@ -0,0 +1,2626 @@
+// jvmti.cc - JVMTI implementation
+
+/* Copyright (C) 2006, 2007, 2010 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. */
+
+#include <config.h>
+#include <platform.h>
+
+#include <jvm.h>
+#include <java-threads.h>
+#include <java-gc.h>
+#include <java-interp.h>
+#include <jvmti.h>
+#include "jvmti-int.h"
+
+#include <gcj/method.h>
+
+#include <gnu/classpath/SystemProperties.h>
+#include <gnu/gcj/runtime/BootClassLoader.h>
+#include <gnu/gcj/jvmti/Breakpoint.h>
+#include <gnu/gcj/jvmti/BreakpointManager.h>
+
+#include <java/lang/Class.h>
+#include <java/lang/ClassLoader.h>
+#include <java/lang/OutOfMemoryError.h>
+#include <java/lang/Thread.h>
+#include <java/lang/ThreadGroup.h>
+#include <java/lang/Thread$State.h>
+#include <java/lang/Throwable.h>
+#include <java/lang/VMClassLoader.h>
+#include <java/lang/reflect/Field.h>
+#include <java/lang/reflect/Modifier.h>
+#include <java/util/Collection.h>
+#include <java/util/HashMap.h>
+#include <java/util/concurrent/locks/Lock.h>
+#include <java/util/concurrent/locks/ReentrantReadWriteLock.h>
+#include <java/net/URL.h>
+
+static void check_enabled_events (void);
+static void check_enabled_event (jvmtiEvent);
+
+namespace JVMTI
+{
+ // Is JVMTI enabled? (i.e., any jvmtiEnv created?)
+ bool enabled;
+
+ // Event notifications
+ bool VMInit = false;
+ bool VMDeath = false;
+ bool ThreadStart = false;
+ bool ThreadEnd = false;
+ bool ClassFileLoadHook = false;
+ bool ClassLoad = false;
+ bool ClassPrepare = false;
+ bool VMStart = false;
+ bool Exception = false;
+ bool ExceptionCatch = false;
+ bool SingleStep = false;
+ bool FramePop = false;
+ bool Breakpoint = false;
+ bool FieldAccess = false;
+ bool FieldModification = false;
+ bool MethodEntry = false;
+ bool MethodExit = false;
+ bool NativeMethodBind = false;
+ bool CompiledMethodLoad = false;
+ bool CompiledMethodUnload = false;
+ bool DynamicCodeGenerated = false;
+ bool DataDumpRequest = false;
+ bool reserved72 = false;
+ bool MonitorWait = false;
+ bool MonitorWaited = false;
+ bool MonitorContendedEnter = false;
+ bool MonitorContendedEntered = false;
+ bool reserved77 = false;
+ bool reserved78 = false;
+ bool reserved79 = false;
+ bool reserved80 = false;
+ bool GarbageCollectionStart = false;
+ bool GarbageCollectionFinish = false;
+ bool ObjectFree = false;
+ bool VMObjectAlloc = false;
+};
+
+extern struct JNINativeInterface _Jv_JNIFunctions;
+
+struct _Jv_rawMonitorID
+{
+ _Jv_Mutex_t mutex;
+ _Jv_ConditionVariable_t condition;
+};
+
+/* A simple linked list of all JVMTI environments. Since
+ events must be delivered to environments in the order
+ in which the environments were created, new environments
+ are added to the end of the list. */
+struct jvmti_env_list
+{
+ jvmtiEnv *env;
+ struct jvmti_env_list *next;
+};
+static struct jvmti_env_list *_jvmtiEnvironments = NULL;
+static java::util::concurrent::locks::
+ReentrantReadWriteLock *_envListLock = NULL;
+#define FOREACH_ENVIRONMENT(Ele) \
+ for (Ele = _jvmtiEnvironments; Ele != NULL; Ele = Ele->next)
+
+// Some commonly-used checks
+
+#define THREAD_DEFAULT_TO_CURRENT(Ajthread) \
+ do \
+ { \
+ if (Ajthread == NULL) \
+ Ajthread = java::lang::Thread::currentThread (); \
+ } \
+ while (0)
+
+#define THREAD_CHECK_VALID(Athread) \
+ do \
+ { \
+ if (!java::lang::Thread::class$.isAssignableFrom (&(Athread->class$))) \
+ return JVMTI_ERROR_INVALID_THREAD; \
+ } \
+ while (0)
+
+#define THREAD_CHECK_IS_ALIVE(Athread) \
+ do \
+ { \
+ if (!Athread->isAlive ()) \
+ return JVMTI_ERROR_THREAD_NOT_ALIVE; \
+ } \
+ while (0)
+
+// FIXME: if current phase is not set in Phases,
+// return JVMTI_ERROR_WRONG_PHASE
+#define REQUIRE_PHASE(Env, Phases)
+
+#define NULL_CHECK(Ptr) \
+ do \
+ { \
+ if (Ptr == NULL) \
+ return JVMTI_ERROR_NULL_POINTER; \
+ } \
+ while (0)
+
+#define ILLEGAL_ARGUMENT(Cond) \
+ do \
+ { \
+ if ((Cond)) \
+ return JVMTI_ERROR_ILLEGAL_ARGUMENT; \
+ } \
+ while (0)
+
+#define CHECK_FOR_NATIVE_METHOD(AjmethodID) \
+ do \
+ { \
+ jboolean is_native; \
+ jvmtiError jerr = env->IsMethodNative (AjmethodID, &is_native); \
+ if (jerr != JVMTI_ERROR_NONE) \
+ return jerr; \
+ if (is_native) \
+ return JVMTI_ERROR_NATIVE_METHOD; \
+ } \
+ while (0)
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SuspendThread (MAYBE_UNUSED jvmtiEnv *env, jthread thread)
+{
+ using namespace java::lang;
+
+ THREAD_DEFAULT_TO_CURRENT (thread);
+ THREAD_CHECK_VALID (thread);
+ THREAD_CHECK_IS_ALIVE (thread);
+
+ _Jv_Thread_t *data = _Jv_ThreadGetData (thread);
+ _Jv_SuspendThread (data);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_ResumeThread (MAYBE_UNUSED jvmtiEnv *env, jthread thread)
+{
+ using namespace java::lang;
+
+ THREAD_DEFAULT_TO_CURRENT (thread);
+ THREAD_CHECK_VALID (thread);
+ THREAD_CHECK_IS_ALIVE (thread);
+
+ _Jv_Thread_t *data = _Jv_ThreadGetData (thread);
+ _Jv_ResumeThread (data);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_InterruptThread (MAYBE_UNUSED jvmtiEnv *env, jthread thread)
+{
+ using namespace java::lang;
+
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+ // FIXME: capability handling? 'can_signal_thread'
+ if (thread == NULL)
+ return JVMTI_ERROR_INVALID_THREAD;
+
+ THREAD_CHECK_VALID (thread);
+ THREAD_CHECK_IS_ALIVE (thread);
+ thread->interrupt();
+ return JVMTI_ERROR_NONE;
+}
+
+// This method performs the common tasks to get and set variables of all types.
+// It is called by the _Jv_JVMTI_Get/SetLocalInt/Object/.... methods.
+static jvmtiError
+getLocalFrame (jvmtiEnv *env, jthread thread, jint depth, jint slot, char type,
+ _Jv_InterpFrame **iframe)
+{
+ using namespace java::lang;
+
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+
+ ILLEGAL_ARGUMENT (depth < 0);
+
+ THREAD_DEFAULT_TO_CURRENT (thread);
+ THREAD_CHECK_VALID (thread);
+ THREAD_CHECK_IS_ALIVE (thread);
+
+ _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
+
+ for (int i = 0; i < depth; i++)
+ {
+ frame = frame->next;
+
+ if (frame == NULL)
+ return JVMTI_ERROR_NO_MORE_FRAMES;
+ }
+
+ if (frame->frame_type == frame_native)
+ return JVMTI_ERROR_OPAQUE_FRAME;
+
+ jint max_locals;
+ jvmtiError jerr = env->GetMaxLocals (reinterpret_cast<jmethodID>
+ (frame->self->get_method ()),
+ &max_locals);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ _Jv_InterpFrame *tmp_iframe = reinterpret_cast<_Jv_InterpFrame *> (frame);
+
+ // The second slot taken up by a long type is marked as type 'x' meaning it
+ // is not valid for access since it holds only the 4 low bytes of the value.
+ if (tmp_iframe->locals_type[slot] == 'x')
+ return JVMTI_ERROR_INVALID_SLOT;
+
+ if (tmp_iframe->locals_type[slot] != type)
+ return JVMTI_ERROR_TYPE_MISMATCH;
+
+ // Check for invalid slots, if the type is a long type, we must check that
+ // the next slot is valid as well.
+ if (slot < 0 || slot >= max_locals
+ || ((type == 'l' || type == 'd') && slot + 1 >= max_locals))
+ return JVMTI_ERROR_INVALID_SLOT;
+
+ *iframe = tmp_iframe;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetLocalObject (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jobject *value)
+{
+ NULL_CHECK (value);
+
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'o', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ *value = frame->locals[slot].o;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetLocalObject (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jobject value)
+{
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'o', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ frame->locals[slot].o = value;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetLocalInt (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jint *value)
+{
+ NULL_CHECK (value);
+
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'i', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ *value = frame->locals[slot].i;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetLocalInt (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jint value)
+{
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'i', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ frame->locals[slot].i = value;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetLocalLong (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jlong *value)
+{
+ NULL_CHECK (value);
+
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'l', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+#if SIZEOF_VOID_P==8
+ *value = frame->locals[slot].l;
+#else
+ _Jv_word2 val;
+ val.ia[0] = frame->locals[slot].ia[0];
+ val.ia[1] = frame->locals[slot + 1].ia[0];
+ *value = val.l;
+#endif
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetLocalLong (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jlong value)
+{
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'l', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+#if SIZEOF_VOID_P==8
+ frame->locals[slot].l = value;
+#else
+ _Jv_word2 val;
+ val.l = value;
+ frame->locals[slot].ia[0] = val.ia[0];
+ frame->locals[slot + 1].ia[0] = val.ia[1];
+#endif
+
+ return JVMTI_ERROR_NONE;
+}
+
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetLocalFloat (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jfloat *value)
+{
+ NULL_CHECK (value);
+
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'f', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ *value = frame->locals[slot].f;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetLocalFloat (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jfloat value)
+{
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'f', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ frame->locals[slot].f = value;
+
+ return JVMTI_ERROR_NONE;
+}
+
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetLocalDouble (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jdouble *value)
+{
+ NULL_CHECK (value);
+
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'd', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+#if SIZEOF_VOID_P==8
+ *value = frame->locals[slot].d;
+#else
+ _Jv_word2 val;
+ val.ia[0] = frame->locals[slot].ia[0];
+ val.ia[1] = frame->locals[slot + 1].ia[0];
+ *value = val.d;
+#endif
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetLocalDouble (jvmtiEnv *env, jthread thread, jint depth, jint slot,
+ jdouble value)
+{
+ _Jv_InterpFrame *frame;
+ jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'd', &frame);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+#if SIZEOF_VOID_P==8
+ frame->locals[slot].d = value;
+#else
+ _Jv_word2 val;
+ val.d = value;
+ frame->locals[slot].ia[0] = val.ia[0];
+ frame->locals[slot + 1].ia[0] = val.ia[1];
+#endif
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetAllThreads(MAYBE_UNUSED jvmtiEnv *env, jint *thread_cnt,
+ jthread **threads)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+ NULL_CHECK (thread_cnt);
+ NULL_CHECK (threads);
+
+ using namespace java::lang;
+
+ ThreadGroup *root_grp = ThreadGroup::root;
+ jint estimate = root_grp->activeCount ();
+
+ JArray<Thread *> *thr_arr;
+
+ // Allocate some extra space since threads can be created between calls
+ try
+ {
+ thr_arr = reinterpret_cast<JArray<Thread *> *> (JvNewObjectArray
+ ((estimate * 2),
+ &Thread::class$, NULL));
+ }
+ catch (java::lang::OutOfMemoryError *err)
+ {
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+ }
+
+ *thread_cnt = root_grp->enumerate (thr_arr);
+
+ jvmtiError jerr = env->Allocate ((jlong) ((*thread_cnt) * sizeof (jthread)),
+ (unsigned char **) threads);
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ // Transfer the threads to the result array
+ jthread *tmp_arr = reinterpret_cast<jthread *> (elements (thr_arr));
+
+ memcpy ((*threads), tmp_arr, (*thread_cnt));
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetFrameCount (MAYBE_UNUSED jvmtiEnv *env, jthread thread,
+ jint *frame_count)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+
+ NULL_CHECK (frame_count);
+
+ using namespace java::lang;
+
+ THREAD_DEFAULT_TO_CURRENT (thread);
+ THREAD_CHECK_VALID (thread);
+ THREAD_CHECK_IS_ALIVE (thread);
+
+ _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
+ (*frame_count) = frame->depth ();
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetThreadState (MAYBE_UNUSED jvmtiEnv *env, jthread thread,
+ jint *thread_state_ptr)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+
+ THREAD_DEFAULT_TO_CURRENT (thread);
+ THREAD_CHECK_VALID (thread);
+ NULL_CHECK (thread_state_ptr);
+
+ jint state = 0;
+ if (thread->isAlive ())
+ {
+ state |= JVMTI_THREAD_STATE_ALIVE;
+
+ _Jv_Thread_t *data = _Jv_ThreadGetData (thread);
+ if (_Jv_IsThreadSuspended (data))
+ state |= JVMTI_THREAD_STATE_SUSPENDED;
+
+ if (thread->isInterrupted ())
+ state |= JVMTI_THREAD_STATE_INTERRUPTED;
+
+ _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
+ if (frame != NULL && frame->frame_type == frame_native)
+ state |= JVMTI_THREAD_STATE_IN_NATIVE;
+
+ using namespace java::lang;
+ Thread$State *ts = thread->getState ();
+ if (ts == Thread$State::RUNNABLE)
+ state |= JVMTI_THREAD_STATE_RUNNABLE;
+ else if (ts == Thread$State::BLOCKED)
+ state |= JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER;
+ else if (ts == Thread$State::TIMED_WAITING
+ || ts == Thread$State::WAITING)
+ {
+ state |= JVMTI_THREAD_STATE_WAITING;
+ state |= ((ts == Thread$State::WAITING)
+ ? JVMTI_THREAD_STATE_WAITING_INDEFINITELY
+ : JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT);
+
+ /* FIXME: We don't have a way to tell
+ the caller why the thread is suspended,
+ i.e., JVMTI_THREAD_STATE_SLEEPING,
+ JVMTI_THREAD_STATE_PARKED, and
+ JVMTI_THREAD_STATE_IN_OBJECT_WAIT
+ are never set. */
+ }
+ }
+ else
+ {
+ using namespace java::lang;
+ Thread$State *ts = thread->getState ();
+ if (ts == Thread$State::TERMINATED)
+ state |= JVMTI_THREAD_STATE_TERMINATED;
+ }
+
+ *thread_state_ptr = state;
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_CreateRawMonitor (MAYBE_UNUSED jvmtiEnv *env, const char *name,
+ jrawMonitorID *result)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_ONLOAD | JVMTI_PHASE_LIVE);
+ NULL_CHECK (name);
+ NULL_CHECK (result);
+ *result = (jrawMonitorID) _Jv_MallocUnchecked (sizeof (_Jv_rawMonitorID));
+ if (*result == NULL)
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+ _Jv_MutexInit (&(*result)->mutex);
+ _Jv_CondInit (&(*result)->condition);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_DestroyRawMonitor (MAYBE_UNUSED jvmtiEnv *env, jrawMonitorID monitor)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_ONLOAD | JVMTI_PHASE_LIVE);
+ // Note we have no better way of knowing whether this object is
+ // really a raw monitor.
+ if (monitor == NULL)
+ return JVMTI_ERROR_INVALID_MONITOR;
+ // FIXME: perform checks on monitor, release it if this thread owns
+ // it.
+#ifdef _Jv_HaveMutexDestroy
+ _Jv_MutexDestroy (&monitor->mutex);
+#endif
+ _Jv_Free (monitor);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_RawMonitorEnter (MAYBE_UNUSED jvmtiEnv *env, jrawMonitorID monitor)
+{
+ if (monitor == NULL)
+ return JVMTI_ERROR_INVALID_MONITOR;
+ _Jv_MutexLock (&monitor->mutex);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_RawMonitorExit (MAYBE_UNUSED jvmtiEnv *env, jrawMonitorID monitor)
+{
+ if (monitor == NULL)
+ return JVMTI_ERROR_INVALID_MONITOR;
+ if (_Jv_MutexUnlock (&monitor->mutex))
+ return JVMTI_ERROR_NOT_MONITOR_OWNER;
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_RawMonitorWait (MAYBE_UNUSED jvmtiEnv *env, jrawMonitorID monitor,
+ jlong millis)
+{
+ if (monitor == NULL)
+ return JVMTI_ERROR_INVALID_MONITOR;
+ int r = _Jv_CondWait (&monitor->condition, &monitor->mutex, millis, 0);
+ if (r == _JV_NOT_OWNER)
+ return JVMTI_ERROR_NOT_MONITOR_OWNER;
+ if (r == _JV_INTERRUPTED)
+ return JVMTI_ERROR_INTERRUPT;
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_RawMonitorNotify (MAYBE_UNUSED jvmtiEnv *env, jrawMonitorID monitor)
+{
+ if (monitor == NULL)
+ return JVMTI_ERROR_INVALID_MONITOR;
+ if (_Jv_CondNotify (&monitor->condition, &monitor->mutex) == _JV_NOT_OWNER)
+ return JVMTI_ERROR_NOT_MONITOR_OWNER;
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_RawMonitorNotifyAll (MAYBE_UNUSED jvmtiEnv *env,
+ jrawMonitorID monitor)
+{
+ if (monitor == NULL)
+ return JVMTI_ERROR_INVALID_MONITOR;
+ if (_Jv_CondNotifyAll (&monitor->condition, &monitor->mutex)
+ == _JV_NOT_OWNER)
+ return JVMTI_ERROR_NOT_MONITOR_OWNER;
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetBreakpoint (jvmtiEnv *env, jmethodID method, jlocation location)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+
+ using namespace gnu::gcj::jvmti;
+ Breakpoint *bp
+ = BreakpointManager::getBreakpoint (reinterpret_cast<jlong> (method),
+ location);
+ if (bp == NULL)
+ {
+ jclass klass;
+ jvmtiError err = env->GetMethodDeclaringClass (method, &klass);
+ if (err != JVMTI_ERROR_NONE)
+ return err;
+
+ if (!_Jv_IsInterpretedClass (klass))
+ return JVMTI_ERROR_INVALID_CLASS;
+
+ _Jv_MethodBase *base = _Jv_FindInterpreterMethod (klass, method);
+ if (base == NULL)
+ return JVMTI_ERROR_INVALID_METHODID;
+
+ jint flags;
+ err = env->GetMethodModifiers (method, &flags);
+ if (err != JVMTI_ERROR_NONE)
+ return err;
+
+ if (flags & java::lang::reflect::Modifier::NATIVE)
+ return JVMTI_ERROR_NATIVE_METHOD;
+
+ _Jv_InterpMethod *imeth = reinterpret_cast<_Jv_InterpMethod *> (base);
+ if (imeth->get_insn (location) == NULL)
+ return JVMTI_ERROR_INVALID_LOCATION;
+
+ // Now the breakpoint can be safely installed
+ bp = BreakpointManager::newBreakpoint (reinterpret_cast<jlong> (method),
+ location);
+ }
+ else
+ {
+ // Duplicate breakpoints are not permitted by JVMTI
+ return JVMTI_ERROR_DUPLICATE;
+ }
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_ClearBreakpoint (MAYBE_UNUSED jvmtiEnv *env, jmethodID method,
+ jlocation location)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+
+ using namespace gnu::gcj::jvmti;
+
+ Breakpoint *bp
+ = BreakpointManager::getBreakpoint (reinterpret_cast<jlong> (method),
+ location);
+ if (bp == NULL)
+ return JVMTI_ERROR_NOT_FOUND;
+
+ BreakpointManager::deleteBreakpoint (reinterpret_cast<jlong> (method), location);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_Allocate (MAYBE_UNUSED jvmtiEnv *env, jlong size,
+ unsigned char **result)
+{
+ ILLEGAL_ARGUMENT (size < 0);
+ NULL_CHECK (result);
+ if (size == 0)
+ *result = NULL;
+ else
+ {
+ *result = (unsigned char *) _Jv_MallocUnchecked (size);
+ if (*result == NULL)
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+ }
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_Deallocate (MAYBE_UNUSED jvmtiEnv *env, unsigned char *mem)
+{
+ if (mem != NULL)
+ _Jv_Free (mem);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetClassStatus (MAYBE_UNUSED jvmtiEnv *env, jclass klass,
+ jint *status_ptr)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ NULL_CHECK (status_ptr);
+ if (klass == NULL)
+ return JVMTI_ERROR_INVALID_CLASS;
+
+ if (klass->isArray ())
+ *status_ptr = JVMTI_CLASS_STATUS_ARRAY;
+ else if (klass->isPrimitive ())
+ *status_ptr = JVMTI_CLASS_STATUS_PRIMITIVE;
+ else
+ {
+ jbyte state = _Jv_GetClassState (klass);
+ *status_ptr = 0;
+ if (state >= JV_STATE_LINKED)
+ (*status_ptr) |= JVMTI_CLASS_STATUS_VERIFIED;
+ if (state >= JV_STATE_PREPARED)
+ (*status_ptr) |= JVMTI_CLASS_STATUS_PREPARED;
+ if (state == JV_STATE_ERROR || state == JV_STATE_PHANTOM)
+ (*status_ptr) |= JVMTI_CLASS_STATUS_ERROR;
+ else if (state == JV_STATE_DONE)
+ (*status_ptr) |= JVMTI_CLASS_STATUS_INITIALIZED;
+ }
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetClassModifiers (MAYBE_UNUSED jvmtiEnv *env, jclass klass,
+ jint *mods)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ // Don't bother checking KLASS' type.
+ if (klass == NULL)
+ return JVMTI_ERROR_INVALID_CLASS;
+ NULL_CHECK (mods);
+ *mods = klass->getModifiers();
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetClassMethods (MAYBE_UNUSED jvmtiEnv *env, jclass klass,
+ jint *count_ptr, jmethodID **methods_ptr)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ // FIXME: capability can_maintain_original_method_order
+ // Don't bother checking KLASS' type.
+ if (klass == NULL)
+ return JVMTI_ERROR_INVALID_CLASS;
+ NULL_CHECK (count_ptr);
+ NULL_CHECK (methods_ptr);
+ *count_ptr = JvNumMethods(klass);
+
+ *methods_ptr
+ = (jmethodID *) _Jv_MallocUnchecked (*count_ptr * sizeof (jmethodID));
+ if (*methods_ptr == NULL)
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+
+ jmethodID start = JvGetFirstMethod (klass);
+ for (jint i = 0; i < *count_ptr; ++i)
+ // FIXME: correct?
+ (*methods_ptr)[i] = start + i;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_IsInterface (MAYBE_UNUSED jvmtiEnv *env, jclass klass,
+ jboolean *result)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ if (klass == NULL)
+ return JVMTI_ERROR_INVALID_CLASS;
+ NULL_CHECK (result);
+ *result = klass->isInterface();
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_IsArrayClass (MAYBE_UNUSED jvmtiEnv *env, jclass klass,
+ jboolean *result)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ if (klass == NULL)
+ return JVMTI_ERROR_INVALID_CLASS;
+ NULL_CHECK (result);
+ *result = klass->isArray();
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetClassLoader (MAYBE_UNUSED jvmtiEnv *env, jclass klass,
+ jobject *result)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ if (klass == NULL)
+ return JVMTI_ERROR_INVALID_CLASS;
+ NULL_CHECK (result);
+ *result = klass->getClassLoaderInternal();
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetObjectHashCode (MAYBE_UNUSED jvmtiEnv *env, jobject obj,
+ jint *result)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ if (obj == NULL)
+ return JVMTI_ERROR_INVALID_OBJECT;
+ NULL_CHECK (result);
+ *result = _Jv_HashCode (obj);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetFieldModifiers (MAYBE_UNUSED jvmtiEnv *env, jclass klass,
+ jfieldID field, jint *result)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ if (klass == NULL)
+ return JVMTI_ERROR_INVALID_CLASS;
+ if (field == NULL)
+ return JVMTI_ERROR_INVALID_FIELDID;
+ NULL_CHECK (result);
+ *result = field->getModifiers();
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_IsFieldSynthetic (MAYBE_UNUSED jvmtiEnv *env, jclass klass,
+ jfieldID field, jboolean *result)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ if (klass == NULL)
+ return JVMTI_ERROR_INVALID_CLASS;
+ if (field == NULL)
+ return JVMTI_ERROR_INVALID_FIELDID;
+ NULL_CHECK (result);
+
+ // FIXME: capability can_get_synthetic_attribute
+ *result = ((field->getModifiers() & java::lang::reflect::Modifier::SYNTHETIC)
+ != 0);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetMethodName (MAYBE_UNUSED jvmtiEnv *env, jmethodID method,
+ char **name_ptr, char **signature_ptr,
+ char **generic_ptr)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+
+ if (method == NULL)
+ return JVMTI_ERROR_INVALID_METHODID;
+
+ if (name_ptr != NULL)
+ {
+ int len = static_cast<int> (method->name->len ());
+ *name_ptr = (char *) _Jv_MallocUnchecked (len + 1);
+ if (*name_ptr == NULL)
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+ strncpy (*name_ptr, method->name->chars (), len);
+ (*name_ptr)[len] = '\0';
+ }
+
+ if (signature_ptr != NULL)
+ {
+ int len = static_cast<int> (method->signature->len ());
+ *signature_ptr = (char *) _Jv_MallocUnchecked (len + 1);
+ if (*signature_ptr == NULL)
+ {
+ if (name_ptr != NULL)
+ _Jv_Free (*name_ptr);
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+ }
+ strncpy (*signature_ptr, method->signature->chars (), len);
+ (*signature_ptr)[len] = '\0';
+ }
+
+ if (generic_ptr != NULL)
+ {
+ *generic_ptr = NULL;
+ }
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetMethodModifiers (MAYBE_UNUSED jvmtiEnv *env, jmethodID method,
+ jint *result)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ if (method == NULL)
+ return JVMTI_ERROR_INVALID_METHODID;
+ NULL_CHECK (result);
+
+ // FIXME: mask off some internal bits...
+ *result = method->accflags;
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetLineNumberTable (jvmtiEnv *env, jmethodID method,
+ jint *entry_count_ptr,
+ jvmtiLineNumberEntry **table_ptr)
+{
+ NULL_CHECK (entry_count_ptr);
+ NULL_CHECK (table_ptr);
+
+ jclass klass;
+ jvmtiError jerr = env->GetMethodDeclaringClass (method, &klass);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ _Jv_MethodBase *base = _Jv_FindInterpreterMethod (klass, method);
+ if (base == NULL)
+ return JVMTI_ERROR_INVALID_METHODID;
+
+ if (java::lang::reflect::Modifier::isNative (method->accflags)
+ || !_Jv_IsInterpretedClass (klass))
+ return JVMTI_ERROR_NATIVE_METHOD;
+
+ _Jv_InterpMethod *imeth = reinterpret_cast<_Jv_InterpMethod *> (base);
+ jlong start, end;
+ jintArray lines = NULL;
+ jlongArray indices = NULL;
+ imeth->get_line_table (start, end, lines, indices);
+ if (lines == NULL)
+ return JVMTI_ERROR_ABSENT_INFORMATION;
+
+ jvmtiLineNumberEntry *table;
+ jsize len = lines->length * sizeof (jvmtiLineNumberEntry);
+ table = (jvmtiLineNumberEntry *) _Jv_MallocUnchecked (len);
+ if (table == NULL)
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+
+ jint *line = elements (lines);
+ jlong *index = elements (indices);
+ for (int i = 0; i < lines->length; ++i)
+ {
+ table[i].start_location = index[i];
+ table[i].line_number = line[i];
+ }
+
+ *table_ptr = table;
+ *entry_count_ptr = lines->length;
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetLocalVariableTable (MAYBE_UNUSED jvmtiEnv *env, jmethodID method,
+ jint *num_locals,
+ jvmtiLocalVariableEntry **locals)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+ NULL_CHECK (num_locals);
+ NULL_CHECK (locals);
+
+ CHECK_FOR_NATIVE_METHOD(method);
+
+ jclass klass;
+ jvmtiError jerr = env->GetMethodDeclaringClass (method, &klass);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ _Jv_InterpMethod *imeth = reinterpret_cast<_Jv_InterpMethod *>
+ (_Jv_FindInterpreterMethod (klass, method));
+
+ if (imeth == NULL)
+ return JVMTI_ERROR_INVALID_METHODID;
+
+ jerr = env->GetMaxLocals (method, num_locals);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ jerr = env->Allocate (static_cast<jlong>
+ ((*num_locals) * sizeof (jvmtiLocalVariableEntry)),
+ reinterpret_cast<unsigned char **> (locals));
+
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ //the slot in the methods local_var_table to get
+ int table_slot = 0;
+ char *name;
+ char *sig;
+ char *generic_sig;
+
+ while (table_slot < *num_locals
+ && imeth->get_local_var_table (&name, &sig, &generic_sig,
+ &((((*locals)[table_slot].start_location))),
+ &((*locals)[table_slot].length),
+ &((*locals)[table_slot].slot),
+ table_slot)
+ >= 0)
+ {
+ char **str_ptr = &(*locals)[table_slot].name;
+ jerr = env->Allocate (static_cast<jlong> (strlen (name) + 1),
+ reinterpret_cast<unsigned char **> (str_ptr));
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+ strcpy ((*locals)[table_slot].name, name);
+
+ str_ptr = &(*locals)[table_slot].signature;
+ jerr = env->Allocate (static_cast<jlong> (strlen (sig) + 1),
+ reinterpret_cast<unsigned char **> (str_ptr));
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+ strcpy ((*locals)[table_slot].signature, sig);
+
+ str_ptr = &(*locals)[table_slot].generic_signature;
+ jerr = env->Allocate (static_cast<jlong> (strlen (generic_sig) + 1),
+ reinterpret_cast<unsigned char **> (str_ptr));
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+ strcpy ((*locals)[table_slot].generic_signature, generic_sig);
+
+ table_slot++;
+ }
+
+ if (table_slot == 0)
+ return JVMTI_ERROR_ABSENT_INFORMATION;
+
+ // If there are double or long variables in the table, the the table will be
+ // smaller than the max number of slots, so correct for this here.
+ if ((table_slot) < *num_locals)
+ *num_locals = table_slot;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_IsMethodNative (MAYBE_UNUSED jvmtiEnv *env, jmethodID method,
+ jboolean *result)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ if (method == NULL)
+ return JVMTI_ERROR_INVALID_METHODID;
+ NULL_CHECK (result);
+
+ *result = ((method->accflags & java::lang::reflect::Modifier::NATIVE) != 0);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_IsMethodSynthetic (MAYBE_UNUSED jvmtiEnv *env, jmethodID method,
+ jboolean *result)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ if (method == NULL)
+ return JVMTI_ERROR_INVALID_METHODID;
+ NULL_CHECK (result);
+
+ // FIXME capability can_get_synthetic_attribute
+
+ *result = ((method->accflags & java::lang::reflect::Modifier::SYNTHETIC)
+ != 0);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetMaxLocals (jvmtiEnv *env, jmethodID method, jint *max_locals)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ NULL_CHECK (max_locals);
+
+ CHECK_FOR_NATIVE_METHOD (method);
+
+ jclass klass;
+ jvmtiError jerr = env->GetMethodDeclaringClass (method, &klass);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ _Jv_InterpMethod *imeth = reinterpret_cast<_Jv_InterpMethod *>
+ (_Jv_FindInterpreterMethod (klass, method));
+
+ if (imeth == NULL)
+ return JVMTI_ERROR_INVALID_METHODID;
+
+ *max_locals = imeth->get_max_locals ();
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetArgumentsSize (jvmtiEnv *env, jmethodID method, jint *size)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ NULL_CHECK (size);
+
+ CHECK_FOR_NATIVE_METHOD (method);
+
+ jvmtiError jerr;
+ char *sig;
+ jint num_slots = 0;
+
+ jerr = env->GetMethodName (method, NULL, &sig, NULL);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ // If the method is non-static add a slot for the "this" pointer.
+ if ((method->accflags & java::lang::reflect::Modifier::STATIC) == 0)
+ num_slots++;
+
+ for (int i = 0; sig[i] != ')'; i++)
+ {
+ if (sig[i] == 'Z' || sig[i] == 'B' || sig[i] == 'C' || sig[i] == 'S'
+ || sig[i] == 'I' || sig[i] == 'F')
+ num_slots++;
+ else if (sig[i] == 'J' || sig[i] == 'D')
+ {
+ // If this is an array of wide types it uses a single slot
+ if (i > 0 && sig[i - 1] == '[')
+ num_slots++;
+ else
+ num_slots += 2;
+ }
+ else if (sig[i] == 'L')
+ {
+ num_slots++;
+ while (sig[i] != ';')
+ i++;
+ }
+ }
+
+ *size = num_slots;
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetMethodDeclaringClass (MAYBE_UNUSED jvmtiEnv *env,
+ jmethodID method,
+ jclass *declaring_class_ptr)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+ NULL_CHECK (declaring_class_ptr);
+
+ jclass klass = _Jv_GetMethodDeclaringClass (method);
+ if (klass != NULL)
+ {
+ *declaring_class_ptr = klass;
+ return JVMTI_ERROR_NONE;
+ }
+
+ return JVMTI_ERROR_INVALID_METHODID;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetClassLoaderClasses (MAYBE_UNUSED jvmtiEnv *env,
+ jobject init_loader,
+ jint *count_ptr,
+ jclass **result_ptr)
+{
+ using namespace java::lang;
+ using namespace java::util;
+
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+ NULL_CHECK (count_ptr);
+ NULL_CHECK (result_ptr);
+
+ ClassLoader *loader = (ClassLoader *) init_loader;
+ if (loader == NULL)
+ loader = VMClassLoader::bootLoader;
+
+ Collection *values = loader->loadedClasses->values();
+ jobjectArray array = values->toArray();
+ *count_ptr = array->length;
+ jobject *elts = elements (array);
+ jclass *result
+ = (jclass *) _Jv_MallocUnchecked (*count_ptr * sizeof (jclass));
+ if (result == NULL)
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+
+ // FIXME: JNI references...
+ memcpy (result, elts, *count_ptr * sizeof (jclass));
+
+ *result_ptr = result;
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetStackTrace (MAYBE_UNUSED jvmtiEnv *env, jthread thread,
+ jint start_depth, jint max_frames,
+ jvmtiFrameInfo *frames, jint *frame_count)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+
+ ILLEGAL_ARGUMENT (max_frames < 0);
+
+ NULL_CHECK (frames);
+ NULL_CHECK (frame_count);
+
+ using namespace java::lang;
+
+ THREAD_DEFAULT_TO_CURRENT (thread);
+ THREAD_CHECK_VALID (thread);
+ THREAD_CHECK_IS_ALIVE (thread);
+
+ jvmtiError jerr = env->GetFrameCount (thread, frame_count);
+ if (jerr != JVMTI_ERROR_NONE)
+ return jerr;
+
+ // start_depth can be either a positive number, indicating the depth of the
+ // stack at which to begin the trace, or a negative number indicating the
+ // number of frames at the bottom of the stack to exclude. These checks
+ // ensure that it is a valid value in either case
+
+ ILLEGAL_ARGUMENT (start_depth >= (*frame_count));
+ ILLEGAL_ARGUMENT (start_depth < (-(*frame_count)));
+
+ _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame);
+
+ // If start_depth is negative use this to determine at what depth to start
+ // the trace by adding it to the length of the call stack. This allows the
+ // use of the same frame "discarding" mechanism as for a positive start_depth
+ if (start_depth < 0)
+ start_depth = *frame_count + start_depth;
+
+ // If start_depth > 0 "remove" start_depth frames from the beginning
+ // of the stack before beginning the trace by moving along the frame list.
+ while (start_depth > 0)
+ {
+ frame = frame->next;
+ start_depth--;
+ (*frame_count)--;
+ }
+
+ // Now check to see if the array supplied by the agent is large enough to
+ // hold frame_count frames, after adjustment for start_depth.
+ if ((*frame_count) > max_frames)
+ (*frame_count) = max_frames;
+
+ for (int i = 0; i < (*frame_count); i++)
+ {
+ frames[i].method = frame->self->get_method ();
+
+ // Set the location in the frame, native frames have location = -1
+ if (frame->frame_type == frame_interpreter)
+ {
+ _Jv_InterpMethod *imeth
+ = static_cast<_Jv_InterpMethod *> (frame->self);
+ _Jv_InterpFrame *interp_frame
+ = static_cast<_Jv_InterpFrame *> (frame);
+ frames[i].location = imeth->insn_index (interp_frame->get_pc ());
+ }
+ else
+ frames[i].location = -1;
+
+ frame = frame->next;
+ }
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_ForceGarbageCollection (MAYBE_UNUSED jvmtiEnv *env)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_LIVE);
+ _Jv_RunGC();
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetJNIFunctionTable (MAYBE_UNUSED jvmtiEnv *env,
+ const jniNativeInterface *function_table)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ NULL_CHECK (function_table);
+ memcpy (&_Jv_JNIFunctions, function_table, sizeof (jniNativeInterface));
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetJNIFunctionTable (MAYBE_UNUSED jvmtiEnv *env,
+ jniNativeInterface **function_table)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ NULL_CHECK (function_table);
+ *function_table
+ = (jniNativeInterface *) _Jv_MallocUnchecked (sizeof (jniNativeInterface));
+ if (*function_table == NULL)
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+ memcpy (*function_table, &_Jv_JNIFunctions, sizeof (jniNativeInterface));
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_DisposeEnvironment (jvmtiEnv *env)
+{
+ NULL_CHECK (env);
+
+ if (_jvmtiEnvironments == NULL)
+ return JVMTI_ERROR_INVALID_ENVIRONMENT;
+ else
+ {
+ _envListLock->writeLock ()->lock ();
+ if (_jvmtiEnvironments->env == env)
+ {
+ struct jvmti_env_list *next = _jvmtiEnvironments->next;
+ _Jv_Free (_jvmtiEnvironments);
+ _jvmtiEnvironments = next;
+ }
+ else
+ {
+ struct jvmti_env_list *e = _jvmtiEnvironments;
+ while (e->next != NULL && e->next->env != env)
+ e = e->next;
+ if (e->next == NULL)
+ {
+ _envListLock->writeLock ()->unlock ();
+ return JVMTI_ERROR_INVALID_ENVIRONMENT;
+ }
+
+ struct jvmti_env_list *next = e->next->next;
+ _Jv_Free (e->next);
+ e->next = next;
+ }
+ _envListLock->writeLock ()->unlock ();
+ }
+
+ _Jv_Free (env);
+
+ check_enabled_events ();
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetSystemProperty (MAYBE_UNUSED jvmtiEnv *env, const char *property,
+ char **result)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_ONLOAD | JVMTI_PHASE_LIVE);
+ NULL_CHECK (property);
+ NULL_CHECK (result);
+
+ jstring name = JvNewStringUTF(property);
+ jstring result_str = gnu::classpath::SystemProperties::getProperty(name);
+
+ if (result_str == NULL)
+ return JVMTI_ERROR_NOT_AVAILABLE;
+
+ int len = JvGetStringUTFLength (result_str);
+ *result = (char *) _Jv_MallocUnchecked (len + 1);
+ if (*result == NULL)
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+ JvGetStringUTFRegion (result_str, 0, result_str->length(), *result);
+ (*result)[len] = '\0';
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetSystemProperty (MAYBE_UNUSED jvmtiEnv *env, const char *property,
+ const char *value)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_ONLOAD);
+
+ NULL_CHECK (property);
+ if (value == NULL)
+ {
+ // FIXME: When would a property not be writeable?
+ return JVMTI_ERROR_NONE;
+ }
+
+ jstring prop_str = JvNewStringUTF(property);
+ jstring value_str = JvNewStringUTF(value);
+ gnu::classpath::SystemProperties::setProperty(prop_str, value_str);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetTime (MAYBE_UNUSED jvmtiEnv *env, jlong *nanos_ptr)
+{
+ NULL_CHECK (nanos_ptr);
+ *nanos_ptr = _Jv_platform_nanotime();
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetAvailableProcessors (MAYBE_UNUSED jvmtiEnv *env,
+ jint *nprocessors_ptr)
+{
+ NULL_CHECK (nprocessors_ptr);
+#ifdef _SC_NPROCESSORS_ONLN
+ *nprocessors_ptr = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+ *nprocessors_ptr = 1;
+#endif
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_AddToBootstrapClassLoaderSearch (MAYBE_UNUSED jvmtiEnv *env,
+ const char *segment)
+{
+ using namespace java::lang;
+ using namespace java::net;
+ using namespace gnu::gcj::runtime;
+
+ REQUIRE_PHASE (env, JVMTI_PHASE_ONLOAD);
+ NULL_CHECK (segment);
+
+ jstring str_segment = JvNewStringUTF(segment);
+ URL *url;
+ try
+ {
+ url = new URL(JvNewStringUTF("file"), NULL, str_segment);
+ }
+ catch (jthrowable ignore)
+ {
+ return JVMTI_ERROR_ILLEGAL_ARGUMENT;
+ }
+
+ BootClassLoader *loader = VMClassLoader::bootLoader;
+ // Don't call this too early.
+ // assert (loader != NULL);
+ loader->addURL(url);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetVerboseFlag (MAYBE_UNUSED jvmtiEnv *env, jvmtiVerboseFlag flag,
+ jboolean value)
+{
+ switch (flag)
+ {
+ case JVMTI_VERBOSE_OTHER:
+ case JVMTI_VERBOSE_GC:
+ case JVMTI_VERBOSE_JNI:
+ // Ignore.
+ break;
+ case JVMTI_VERBOSE_CLASS:
+ gcj::verbose_class_flag = value;
+ break;
+ default:
+ return JVMTI_ERROR_ILLEGAL_ARGUMENT;
+ }
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetObjectSize (MAYBE_UNUSED jvmtiEnv *env, jobject object,
+ jlong *result)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE);
+ if (object == NULL)
+ return JVMTI_ERROR_INVALID_OBJECT;
+ NULL_CHECK (result);
+
+ jclass klass = object->getClass();
+ if (klass->isArray())
+ {
+ jclass comp = klass->getComponentType();
+ jint base
+ = (jint) (_Jv_uintptr_t) _Jv_GetArrayElementFromElementType(NULL,
+ klass->getComponentType());
+ // FIXME: correct for primitive types?
+ jint compSize = comp->size();
+ __JArray *array = (__JArray *) object;
+ *result = base + array->length * compSize;
+ }
+ else
+ {
+ // Note that if OBJECT is a String then it may (if
+ // str->data==str) take more space. Do we care?
+ *result = klass->size();
+ }
+ return JVMTI_ERROR_NONE;
+}
+
+/* An event is enabled only if it has both an event handler
+ and it is enabled in the environment. */
+static void
+check_enabled_event (jvmtiEvent type)
+{
+ bool *enabled;
+ int offset;
+
+#define GET_OFFSET(Event) \
+ do \
+ { \
+ enabled = &JVMTI::Event; \
+ offset = offsetof (jvmtiEventCallbacks, Event); \
+ } \
+ while (0)
+
+ switch (type)
+ {
+ case JVMTI_EVENT_VM_INIT:
+ GET_OFFSET (VMInit);
+ break;
+
+ case JVMTI_EVENT_VM_DEATH:
+ GET_OFFSET (VMDeath);
+ break;
+
+ case JVMTI_EVENT_THREAD_START:
+ GET_OFFSET (ThreadStart);
+ break;
+
+ case JVMTI_EVENT_THREAD_END:
+ GET_OFFSET (ThreadEnd);
+ break;
+
+ case JVMTI_EVENT_CLASS_FILE_LOAD_HOOK:
+ GET_OFFSET (ClassFileLoadHook);
+ break;
+
+ case JVMTI_EVENT_CLASS_LOAD:
+ GET_OFFSET (ClassLoad);
+ break;
+
+ case JVMTI_EVENT_CLASS_PREPARE:
+ GET_OFFSET (ClassPrepare);
+ break;
+
+ case JVMTI_EVENT_VM_START:
+ GET_OFFSET (VMStart);
+ break;
+
+ case JVMTI_EVENT_EXCEPTION:
+ GET_OFFSET (Exception);
+ break;
+
+ case JVMTI_EVENT_EXCEPTION_CATCH:
+ GET_OFFSET (ExceptionCatch);
+ break;
+
+ case JVMTI_EVENT_SINGLE_STEP:
+ GET_OFFSET (SingleStep);
+ break;
+
+ case JVMTI_EVENT_FRAME_POP:
+ GET_OFFSET (FramePop);
+ break;
+
+ case JVMTI_EVENT_BREAKPOINT:
+ GET_OFFSET (Breakpoint);
+ break;
+
+ case JVMTI_EVENT_FIELD_ACCESS:
+ GET_OFFSET (FieldAccess);
+ break;
+
+ case JVMTI_EVENT_FIELD_MODIFICATION:
+ GET_OFFSET (FieldModification);
+ break;
+
+ case JVMTI_EVENT_METHOD_ENTRY:
+ GET_OFFSET (MethodEntry);
+ break;
+
+ case JVMTI_EVENT_METHOD_EXIT:
+ GET_OFFSET (MethodExit);
+ break;
+
+ case JVMTI_EVENT_NATIVE_METHOD_BIND:
+ GET_OFFSET (NativeMethodBind);
+ break;
+
+ case JVMTI_EVENT_COMPILED_METHOD_LOAD:
+ GET_OFFSET (CompiledMethodLoad);
+ break;
+
+ case JVMTI_EVENT_COMPILED_METHOD_UNLOAD:
+ GET_OFFSET (CompiledMethodUnload);
+ break;
+
+ case JVMTI_EVENT_DYNAMIC_CODE_GENERATED:
+ GET_OFFSET (DynamicCodeGenerated);
+ break;
+
+ case JVMTI_EVENT_DATA_DUMP_REQUEST:
+ GET_OFFSET (DataDumpRequest);
+ break;
+
+ case JVMTI_EVENT_MONITOR_WAIT:
+ GET_OFFSET (MonitorWait);
+ break;
+
+ case JVMTI_EVENT_MONITOR_WAITED:
+ GET_OFFSET (MonitorWaited);
+ break;
+
+ case JVMTI_EVENT_MONITOR_CONTENDED_ENTER:
+ GET_OFFSET (MonitorContendedEnter);
+ break;
+
+ case JVMTI_EVENT_MONITOR_CONTENDED_ENTERED:
+ GET_OFFSET (MonitorContendedEntered);
+ break;
+
+ case JVMTI_EVENT_GARBAGE_COLLECTION_START:
+ GET_OFFSET (GarbageCollectionStart);
+ break;
+
+ case JVMTI_EVENT_GARBAGE_COLLECTION_FINISH:
+ GET_OFFSET (GarbageCollectionFinish);
+ break;
+
+ case JVMTI_EVENT_OBJECT_FREE:
+ GET_OFFSET (ObjectFree);
+ break;
+
+ case JVMTI_EVENT_VM_OBJECT_ALLOC:
+ GET_OFFSET (VMObjectAlloc);
+ break;
+
+ default:
+ fprintf (stderr,
+ "libgcj: check_enabled_event for unknown JVMTI event (%d)\n",
+ (int) type);
+ return;
+ }
+#undef GET_OFFSET
+
+ int index = EVENT_INDEX (type); // safe since caller checks this
+
+ if (_jvmtiEnvironments != NULL)
+ {
+ _envListLock->readLock ()->lock ();
+ struct jvmti_env_list *e;
+ FOREACH_ENVIRONMENT (e)
+ {
+ char *addr
+ = reinterpret_cast<char *> (&e->env->callbacks) + offset;
+ void **callback = reinterpret_cast<void **> (addr);
+ if (e->env->enabled[index] && *callback != NULL)
+ {
+ *enabled = true;
+ _envListLock->readLock ()->unlock ();
+ return;
+ }
+ }
+
+ _envListLock->readLock ()->unlock ();
+ }
+
+ *enabled = false;
+}
+
+static void
+check_enabled_events ()
+{
+ check_enabled_event (JVMTI_EVENT_VM_INIT);
+ check_enabled_event (JVMTI_EVENT_VM_DEATH);
+ check_enabled_event (JVMTI_EVENT_THREAD_START);
+ check_enabled_event (JVMTI_EVENT_THREAD_END);
+ check_enabled_event (JVMTI_EVENT_CLASS_FILE_LOAD_HOOK);
+ check_enabled_event (JVMTI_EVENT_CLASS_LOAD);
+ check_enabled_event (JVMTI_EVENT_CLASS_PREPARE);
+ check_enabled_event (JVMTI_EVENT_VM_START);
+ check_enabled_event (JVMTI_EVENT_EXCEPTION);
+ check_enabled_event (JVMTI_EVENT_EXCEPTION_CATCH);
+ check_enabled_event (JVMTI_EVENT_SINGLE_STEP);
+ check_enabled_event (JVMTI_EVENT_FRAME_POP);
+ check_enabled_event (JVMTI_EVENT_BREAKPOINT);
+ check_enabled_event (JVMTI_EVENT_FIELD_ACCESS);
+ check_enabled_event (JVMTI_EVENT_FIELD_MODIFICATION);
+ check_enabled_event (JVMTI_EVENT_METHOD_ENTRY);
+ check_enabled_event (JVMTI_EVENT_METHOD_EXIT);
+ check_enabled_event (JVMTI_EVENT_NATIVE_METHOD_BIND);
+ check_enabled_event (JVMTI_EVENT_COMPILED_METHOD_LOAD);
+ check_enabled_event (JVMTI_EVENT_COMPILED_METHOD_UNLOAD);
+ check_enabled_event (JVMTI_EVENT_DYNAMIC_CODE_GENERATED);
+ check_enabled_event (JVMTI_EVENT_DATA_DUMP_REQUEST);
+ check_enabled_event (JVMTI_EVENT_MONITOR_WAIT);
+ check_enabled_event (JVMTI_EVENT_MONITOR_WAITED);
+ check_enabled_event (JVMTI_EVENT_MONITOR_CONTENDED_ENTER);
+ check_enabled_event (JVMTI_EVENT_MONITOR_CONTENDED_ENTERED);
+ check_enabled_event (JVMTI_EVENT_GARBAGE_COLLECTION_START);
+ check_enabled_event (JVMTI_EVENT_GARBAGE_COLLECTION_FINISH);
+ check_enabled_event (JVMTI_EVENT_OBJECT_FREE);
+ check_enabled_event (JVMTI_EVENT_VM_OBJECT_ALLOC);
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetEventNotificationMode (jvmtiEnv *env, jvmtiEventMode mode,
+ jvmtiEvent type, jthread event_thread, ...)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_ONLOAD | JVMTI_PHASE_LIVE);
+
+ if (event_thread != NULL)
+ {
+ THREAD_CHECK_VALID (event_thread);
+ THREAD_CHECK_IS_ALIVE (event_thread);
+ }
+
+ bool enabled;
+ switch (mode)
+ {
+ case JVMTI_DISABLE:
+ enabled = false;
+ break;
+ case JVMTI_ENABLE:
+ enabled = true;
+ break;
+
+ default:
+ return JVMTI_ERROR_ILLEGAL_ARGUMENT;
+ }
+
+ switch (type)
+ {
+ case JVMTI_EVENT_VM_INIT:
+ case JVMTI_EVENT_VM_DEATH:
+ case JVMTI_EVENT_THREAD_START:
+ case JVMTI_EVENT_VM_START:
+ case JVMTI_EVENT_COMPILED_METHOD_LOAD:
+ case JVMTI_EVENT_COMPILED_METHOD_UNLOAD:
+ case JVMTI_EVENT_DYNAMIC_CODE_GENERATED:
+ case JVMTI_EVENT_DATA_DUMP_REQUEST:
+ ILLEGAL_ARGUMENT (event_thread != NULL);
+ break;
+
+ case JVMTI_EVENT_THREAD_END:
+ case JVMTI_EVENT_CLASS_FILE_LOAD_HOOK:
+ case JVMTI_EVENT_CLASS_LOAD:
+ case JVMTI_EVENT_CLASS_PREPARE:
+ case JVMTI_EVENT_EXCEPTION:
+ case JVMTI_EVENT_EXCEPTION_CATCH:
+ case JVMTI_EVENT_SINGLE_STEP:
+ case JVMTI_EVENT_FRAME_POP:
+ case JVMTI_EVENT_BREAKPOINT:
+ case JVMTI_EVENT_FIELD_ACCESS:
+ case JVMTI_EVENT_FIELD_MODIFICATION:
+ case JVMTI_EVENT_METHOD_ENTRY:
+ case JVMTI_EVENT_METHOD_EXIT:
+ case JVMTI_EVENT_NATIVE_METHOD_BIND:
+ case JVMTI_EVENT_MONITOR_WAIT:
+ case JVMTI_EVENT_MONITOR_WAITED:
+ case JVMTI_EVENT_MONITOR_CONTENDED_ENTER:
+ case JVMTI_EVENT_MONITOR_CONTENDED_ENTERED:
+ case JVMTI_EVENT_GARBAGE_COLLECTION_START:
+ case JVMTI_EVENT_GARBAGE_COLLECTION_FINISH:
+ case JVMTI_EVENT_OBJECT_FREE:
+ case JVMTI_EVENT_VM_OBJECT_ALLOC:
+ break;
+
+ default:
+ return JVMTI_ERROR_INVALID_EVENT_TYPE;
+ }
+
+ env->thread[EVENT_INDEX(type)] = event_thread;
+ env->enabled[EVENT_INDEX(type)] = enabled;
+ check_enabled_event (type);
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_SetEventCallbacks (jvmtiEnv *env,
+ const jvmtiEventCallbacks *callbacks,
+ jint size_of_callbacks)
+{
+ REQUIRE_PHASE (env, JVMTI_PHASE_ONLOAD | JVMTI_PHASE_LIVE);
+ ILLEGAL_ARGUMENT (size_of_callbacks < 0);
+
+ // Copy the list of callbacks into the environment
+ memcpy (&env->callbacks, callbacks, sizeof (jvmtiEventCallbacks));
+
+ /* Check which events are now enabeld (JVMTI makes no requirements
+ about the order in which SetEventCallbacks and SetEventNotifications
+ are called. So we must check all events here. */
+ check_enabled_events ();
+
+ return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError JNICALL
+_Jv_JVMTI_GetErrorName (MAYBE_UNUSED jvmtiEnv *env, jvmtiError error,
+ char **name_ptr)
+{
+ NULL_CHECK (name_ptr);
+
+ const char *name;
+ switch (error)
+ {
+ case JVMTI_ERROR_NONE:
+ name = "none";
+ break;
+
+ case JVMTI_ERROR_NULL_POINTER:
+ name = "null pointer";
+ break;
+
+ case JVMTI_ERROR_OUT_OF_MEMORY:
+ name = "out of memory";
+ break;
+
+ case JVMTI_ERROR_ACCESS_DENIED:
+ name = "access denied";
+ break;
+
+ case JVMTI_ERROR_WRONG_PHASE:
+ name = "wrong phase";
+ break;
+
+ case JVMTI_ERROR_INTERNAL:
+ name = "internal error";
+ break;
+
+ case JVMTI_ERROR_UNATTACHED_THREAD:
+ name = "unattached thread";
+ break;
+
+ case JVMTI_ERROR_INVALID_ENVIRONMENT:
+ name = "invalid environment";
+ break;
+
+ case JVMTI_ERROR_INVALID_PRIORITY:
+ name = "invalid priority";
+ break;
+
+ case JVMTI_ERROR_THREAD_NOT_SUSPENDED:
+ name = "thread not suspended";
+ break;
+
+ case JVMTI_ERROR_THREAD_SUSPENDED:
+ name = "thread suspended";
+ break;
+
+ case JVMTI_ERROR_THREAD_NOT_ALIVE:
+ name = "thread not alive";
+ break;
+
+ case JVMTI_ERROR_CLASS_NOT_PREPARED:
+ name = "class not prepared";
+ break;
+
+ case JVMTI_ERROR_NO_MORE_FRAMES:
+ name = "no more frames";
+ break;
+
+ case JVMTI_ERROR_OPAQUE_FRAME:
+ name = "opaque frame";
+ break;
+
+ case JVMTI_ERROR_DUPLICATE:
+ name = "duplicate";
+ break;
+
+ case JVMTI_ERROR_NOT_FOUND:
+ name = "not found";
+ break;
+
+ case JVMTI_ERROR_NOT_MONITOR_OWNER:
+ name = "not monitor owner";
+ break;
+
+ case JVMTI_ERROR_INTERRUPT:
+ name = "interrupted";
+ break;
+
+ case JVMTI_ERROR_UNMODIFIABLE_CLASS:
+ name = "unmodifiable class";
+ break;
+
+ case JVMTI_ERROR_NOT_AVAILABLE:
+ name = "not available";
+ break;
+
+ case JVMTI_ERROR_ABSENT_INFORMATION:
+ name = "absent information";
+ break;
+
+ case JVMTI_ERROR_INVALID_EVENT_TYPE:
+ name = "invalid event type";
+ break;
+
+ case JVMTI_ERROR_NATIVE_METHOD:
+ name = "native method";
+ break;
+
+ case JVMTI_ERROR_INVALID_THREAD:
+ name = "invalid thread";
+ break;
+
+ case JVMTI_ERROR_INVALID_THREAD_GROUP:
+ name = "invalid thread group";
+ break;
+
+ case JVMTI_ERROR_INVALID_OBJECT:
+ name = "invalid object";
+ break;
+
+ case JVMTI_ERROR_INVALID_CLASS:
+ name = "invalid class";
+ break;
+
+ case JVMTI_ERROR_INVALID_METHODID:
+ name = "invalid method ID";
+ break;
+
+ case JVMTI_ERROR_INVALID_LOCATION:
+ name = "invalid location";
+ break;
+
+ case JVMTI_ERROR_INVALID_FIELDID:
+ name = "invalid field ID";
+ break;
+
+ case JVMTI_ERROR_TYPE_MISMATCH:
+ name = "type mismatch";
+ break;
+
+ case JVMTI_ERROR_INVALID_SLOT:
+ name = "invalid slot";
+ break;
+
+ case JVMTI_ERROR_INVALID_MONITOR:
+ name = "invalid monitor";
+ break;
+
+ case JVMTI_ERROR_INVALID_CLASS_FORMAT:
+ name = "invalid class format";
+ break;
+
+ case JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION:
+ name = "circular class definition";
+ break;
+
+ case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED:
+ name = "unsupported redefinition: method added";
+ break;
+
+ case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED:
+ name = "unsupported redefinition: schema changed";
+ break;
+
+ case JVMTI_ERROR_INVALID_TYPESTATE:
+ name = "invalid type state";
+ break;
+
+ case JVMTI_ERROR_FAILS_VERIFICATION:
+ name = "fails verification";
+ break;
+
+ case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED:
+ name = "unsupported redefinition: hierarchy changed";
+ break;
+
+ case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED:
+ name = "unsupported redefinition: method deleted";
+ break;
+
+ case JVMTI_ERROR_UNSUPPORTED_VERSION:
+ name = "unsupported version";
+ break;
+
+ case JVMTI_ERROR_NAMES_DONT_MATCH:
+ name = "names do not match";
+ break;
+
+ case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED:
+ name = "unsupported redefinition: class modifiers changed";
+ break;
+
+ case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:
+ name = "unsupported redefinition: method modifiers changed";
+ break;
+
+ case JVMTI_ERROR_MUST_POSSESS_CAPABILITY:
+ name = "must possess capability";
+ break;
+
+ case JVMTI_ERROR_ILLEGAL_ARGUMENT:
+ name = "illegal argument";
+ break;
+
+ default:
+ return JVMTI_ERROR_ILLEGAL_ARGUMENT;
+ }
+
+ *name_ptr = (char *) _Jv_MallocUnchecked (strlen (name) + 1);
+ if (*name_ptr == NULL)
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+
+ strcpy (*name_ptr, name);
+ return JVMTI_ERROR_NONE;
+}
+
+#define RESERVED NULL
+#define UNIMPLEMENTED NULL
+
+struct _Jv_jvmtiEnv _Jv_JVMTI_Interface =
+{
+ RESERVED, // reserved1
+ _Jv_JVMTI_SetEventNotificationMode, // SetEventNotificationMode
+ RESERVED, // reserved3
+ _Jv_JVMTI_GetAllThreads, // GetAllThreads
+ _Jv_JVMTI_SuspendThread, // SuspendThread
+ _Jv_JVMTI_ResumeThread, // ResumeThread
+ UNIMPLEMENTED, // StopThread
+ _Jv_JVMTI_InterruptThread, // InterruptThread
+ UNIMPLEMENTED, // GetThreadInfo
+ UNIMPLEMENTED, // GetOwnedMonitorInfo
+ UNIMPLEMENTED, // GetCurrentContendedMonitor
+ UNIMPLEMENTED, // RunAgentThread
+ UNIMPLEMENTED, // GetTopThreadGroups
+ UNIMPLEMENTED, // GetThreadGroupInfo
+ UNIMPLEMENTED, // GetThreadGroupChildren
+ _Jv_JVMTI_GetFrameCount, // GetFrameCount
+ _Jv_JVMTI_GetThreadState, // GetThreadState
+ RESERVED, // reserved18
+ UNIMPLEMENTED, // GetFrameLocation
+ UNIMPLEMENTED, // NotifyPopFrame
+ _Jv_JVMTI_GetLocalObject, // GetLocalObject
+ _Jv_JVMTI_GetLocalInt, // GetLocalInt
+ _Jv_JVMTI_GetLocalLong, // GetLocalLong
+ _Jv_JVMTI_GetLocalFloat, // GetLocalFloat
+ _Jv_JVMTI_GetLocalDouble, // GetLocalDouble
+ _Jv_JVMTI_SetLocalObject, // SetLocalObject
+ _Jv_JVMTI_SetLocalInt, // SetLocalInt
+ _Jv_JVMTI_SetLocalLong, // SetLocalLong
+ _Jv_JVMTI_SetLocalFloat, // SetLocalFloat
+ _Jv_JVMTI_SetLocalDouble, // SetLocalDouble
+ _Jv_JVMTI_CreateRawMonitor, // CreateRawMonitor
+ _Jv_JVMTI_DestroyRawMonitor, // DestroyRawMonitor
+ _Jv_JVMTI_RawMonitorEnter, // RawMonitorEnter
+ _Jv_JVMTI_RawMonitorExit, // RawMonitorExit
+ _Jv_JVMTI_RawMonitorWait, // RawMonitorWait
+ _Jv_JVMTI_RawMonitorNotify, // RawMonitorNotify
+ _Jv_JVMTI_RawMonitorNotifyAll, // RawMonitorNotifyAll
+ _Jv_JVMTI_SetBreakpoint, // SetBreakpoint
+ _Jv_JVMTI_ClearBreakpoint, // ClearBreakpoint
+ RESERVED, // reserved40
+ UNIMPLEMENTED, // SetFieldAccessWatch
+ UNIMPLEMENTED, // ClearFieldAccessWatch
+ UNIMPLEMENTED, // SetFieldModificationWatch
+ UNIMPLEMENTED, // ClearFieldModificationWatch
+ RESERVED, // reserved45
+ _Jv_JVMTI_Allocate, // Allocate
+ _Jv_JVMTI_Deallocate, // Deallocate
+ UNIMPLEMENTED, // GetClassSignature
+ _Jv_JVMTI_GetClassStatus, // GetClassStatus
+ UNIMPLEMENTED, // GetSourceFileName
+ _Jv_JVMTI_GetClassModifiers, // GetClassModifiers
+ _Jv_JVMTI_GetClassMethods, // GetClassMethods
+ UNIMPLEMENTED, // GetClassFields
+ UNIMPLEMENTED, // GetImplementedInterfaces
+ _Jv_JVMTI_IsInterface, // IsInterface
+ _Jv_JVMTI_IsArrayClass, // IsArrayClass
+ _Jv_JVMTI_GetClassLoader, // GetClassLoader
+ _Jv_JVMTI_GetObjectHashCode, // GetObjectHashCode
+ UNIMPLEMENTED, // GetObjectMonitorUsage
+ UNIMPLEMENTED, // GetFieldName
+ UNIMPLEMENTED, // GetFieldDeclaringClass
+ _Jv_JVMTI_GetFieldModifiers, // GetFieldModifiers
+ _Jv_JVMTI_IsFieldSynthetic, // IsFieldSynthetic
+ _Jv_JVMTI_GetMethodName, // GetMethodName
+ _Jv_JVMTI_GetMethodDeclaringClass, // GetMethodDeclaringClass
+ _Jv_JVMTI_GetMethodModifiers, // GetMethodModifers
+ RESERVED, // reserved67
+ _Jv_JVMTI_GetMaxLocals, // GetMaxLocals
+ _Jv_JVMTI_GetArgumentsSize, // GetArgumentsSize
+ _Jv_JVMTI_GetLineNumberTable, // GetLineNumberTable
+ UNIMPLEMENTED, // GetMethodLocation
+ _Jv_JVMTI_GetLocalVariableTable, // GetLocalVariableTable
+ RESERVED, // reserved73
+ RESERVED, // reserved74
+ UNIMPLEMENTED, // GetBytecodes
+ _Jv_JVMTI_IsMethodNative, // IsMethodNative
+ _Jv_JVMTI_IsMethodSynthetic, // IsMethodSynthetic
+ UNIMPLEMENTED, // GetLoadedClasses
+ _Jv_JVMTI_GetClassLoaderClasses, // GetClassLoaderClasses
+ UNIMPLEMENTED, // PopFrame
+ RESERVED, // reserved81
+ RESERVED, // reserved82
+ RESERVED, // reserved83
+ RESERVED, // reserved84
+ RESERVED, // reserved85
+ RESERVED, // reserved86
+ UNIMPLEMENTED, // RedefineClasses
+ UNIMPLEMENTED, // GetVersionNumber
+ UNIMPLEMENTED, // GetCapabilities
+ UNIMPLEMENTED, // GetSourceDebugExtension
+ UNIMPLEMENTED, // IsMethodObsolete
+ UNIMPLEMENTED, // SuspendThreadList
+ UNIMPLEMENTED, // ResumeThreadList
+ RESERVED, // reserved94
+ RESERVED, // reserved95
+ RESERVED, // reserved96
+ RESERVED, // reserved97
+ RESERVED, // reserved98
+ RESERVED, // reserved99
+ UNIMPLEMENTED, // GetAllStackTraces
+ UNIMPLEMENTED, // GetThreadListStackTraces
+ UNIMPLEMENTED, // GetThreadLocalStorage
+ UNIMPLEMENTED, // SetThreadLocalStorage
+ _Jv_JVMTI_GetStackTrace, // GetStackTrace
+ RESERVED, // reserved105
+ UNIMPLEMENTED, // GetTag
+ UNIMPLEMENTED, // SetTag
+ _Jv_JVMTI_ForceGarbageCollection, // ForceGarbageCollection
+ UNIMPLEMENTED, // IterateOverObjectsReachable
+ UNIMPLEMENTED, // IterateOverReachableObjects
+ UNIMPLEMENTED, // IterateOverHeap
+ UNIMPLEMENTED, // IterateOverInstanceOfClass
+ RESERVED, // reserved113
+ UNIMPLEMENTED, // GetObjectsWithTags
+ RESERVED, // reserved115
+ RESERVED, // reserved116
+ RESERVED, // reserved117
+ RESERVED, // reserved118
+ RESERVED, // reserved119
+ _Jv_JVMTI_SetJNIFunctionTable, // SetJNIFunctionTable
+ _Jv_JVMTI_GetJNIFunctionTable, // GetJNIFunctionTable
+ _Jv_JVMTI_SetEventCallbacks, // SetEventCallbacks
+ UNIMPLEMENTED, // GenerateEvents
+ UNIMPLEMENTED, // GetExtensionFunctions
+ UNIMPLEMENTED, // GetExtensionEvents
+ UNIMPLEMENTED, // SetExtensionEventCallback
+ _Jv_JVMTI_DisposeEnvironment, // DisposeEnvironment
+ _Jv_JVMTI_GetErrorName, // GetErrorName
+ UNIMPLEMENTED, // GetJLocationFormat
+ UNIMPLEMENTED, // GetSystemProperties
+ _Jv_JVMTI_GetSystemProperty, // GetSystemProperty
+ _Jv_JVMTI_SetSystemProperty, // SetSystemProperty
+ UNIMPLEMENTED, // GetPhase
+ UNIMPLEMENTED, // GetCurrentThreadCpuTimerInfo
+ UNIMPLEMENTED, // GetCurrentThreadCpuTime
+ UNIMPLEMENTED, // GetThreadCpuTimerInfo
+ UNIMPLEMENTED, // GetThreadCpuTime
+ UNIMPLEMENTED, // GetTimerInfo
+ _Jv_JVMTI_GetTime, // GetTime
+ UNIMPLEMENTED, // GetPotentialCapabilities
+ RESERVED, // reserved141
+ UNIMPLEMENTED, // AddCapabilities
+ UNIMPLEMENTED, // RelinquishCapabilities
+ _Jv_JVMTI_GetAvailableProcessors, // GetAvailableProcessors
+ RESERVED, // reserved145
+ RESERVED, // reserved146
+ UNIMPLEMENTED, // GetEnvironmentLocalStorage
+ UNIMPLEMENTED, // SetEnvironmentLocalStorage
+ _Jv_JVMTI_AddToBootstrapClassLoaderSearch, // AddToBootstrapClassLoaderSearch
+ _Jv_JVMTI_SetVerboseFlag, // SetVerboseFlag
+ RESERVED, // reserved151
+ RESERVED, // reserved152
+ RESERVED, // reserved153
+ _Jv_JVMTI_GetObjectSize // GetObjectSize
+};
+
+_Jv_JVMTIEnv *
+_Jv_GetJVMTIEnv (void)
+{
+ _Jv_JVMTIEnv *env
+ = (_Jv_JVMTIEnv *) _Jv_MallocUnchecked (sizeof (_Jv_JVMTIEnv));
+ memset (env, 0, sizeof (_Jv_JVMTIEnv));
+ env->p = &_Jv_JVMTI_Interface;
+ struct jvmti_env_list *element
+ = (struct jvmti_env_list *) _Jv_MallocUnchecked (sizeof (struct jvmti_env_list));
+ element->env = env;
+ element->next = NULL;
+
+ _envListLock->writeLock ()->lock ();
+ if (_jvmtiEnvironments == NULL)
+ _jvmtiEnvironments = element;
+ else
+ {
+ struct jvmti_env_list *e;
+ for (e = _jvmtiEnvironments; e->next != NULL; e = e->next)
+ ;
+ e->next = element;
+ }
+ _envListLock->writeLock ()->unlock ();
+
+ /* Mark JVMTI active. This is used to force the interpreter
+ to use either debugging or non-debugging code. Once JVMTI
+ has been enabled, the non-debug interpreter cannot be used. */
+ JVMTI::enabled = true;
+ return env;
+}
+
+void
+_Jv_JVMTI_Init ()
+{
+ _jvmtiEnvironments = NULL;
+ _envListLock
+ = new java::util::concurrent::locks::ReentrantReadWriteLock ();
+
+ // No environments, so this should set all JVMTI:: members to false
+ check_enabled_events ();
+}
+
+static void
+post_event (jvmtiEnv *env, jvmtiEvent type, jthread event_thread, va_list args)
+{
+#define ARG(Type,Name) Type Name = (Type) va_arg (args, Type)
+
+#define GET_BOOLEAN_ARG(Name) \
+ ARG (int, b); \
+ jboolean Name = (b == 0) ? false : true
+
+#define GET_CHAR_ARG(Name) \
+ ARG (int, c); \
+ char Name = static_cast<char> (c)
+
+ switch (type)
+ {
+ case JVMTI_EVENT_VM_INIT:
+ if (env->callbacks.VMInit != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ env->callbacks.VMInit (env, jni_env, event_thread);
+ }
+ break;
+
+ case JVMTI_EVENT_VM_DEATH:
+ if (env->callbacks.VMDeath != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ env->callbacks.VMDeath (env, jni_env);
+ }
+ break;
+
+ case JVMTI_EVENT_THREAD_START:
+ if (env->callbacks.ThreadStart != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ env->callbacks.ThreadStart (env, jni_env, event_thread);
+ }
+ break;
+
+ case JVMTI_EVENT_THREAD_END:
+ if (env->callbacks.ThreadEnd != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ env->callbacks.ThreadEnd (env, jni_env, event_thread);
+ }
+ break;
+
+ case JVMTI_EVENT_CLASS_FILE_LOAD_HOOK:
+ if (env->callbacks.ClassFileLoadHook != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jclass, class_being_redefined);
+ ARG (jobject, loader);
+ ARG (const char *, name);
+ ARG (jobject, protection_domain);
+ ARG (jint, class_data_len);
+ ARG (const unsigned char *, class_data);
+ ARG (jint *, new_class_data_len);
+ ARG (unsigned char **, new_class_data);
+ env->callbacks.ClassFileLoadHook (env, jni_env,
+ class_being_redefined, loader,
+ name, protection_domain,
+ class_data_len, class_data,
+ new_class_data_len,
+ new_class_data);
+ }
+ break;
+
+ case JVMTI_EVENT_CLASS_LOAD:
+ if (env->callbacks.ClassLoad != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jclass, klass);
+ env->callbacks.ClassLoad (env, jni_env, event_thread, klass);
+ }
+ break;
+
+ case JVMTI_EVENT_CLASS_PREPARE:
+ if (env->callbacks.ClassPrepare != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jclass, klass);
+ env->callbacks.ClassPrepare (env, jni_env, event_thread, klass);
+ }
+ break;
+
+ case JVMTI_EVENT_VM_START:
+ if (env->callbacks.VMStart != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ env->callbacks.VMStart (env, jni_env);
+ }
+ break;
+
+ case JVMTI_EVENT_EXCEPTION:
+ if (env->callbacks.Exception != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jmethodID, method);
+ ARG (jlocation, location);
+ ARG (jobject, exception);
+ ARG (jmethodID, catch_method);
+ ARG (jlocation, catch_location);
+ env->callbacks.Exception (env, jni_env, event_thread, method,
+ location, exception, catch_method,
+ catch_location);
+ }
+ break;
+
+ case JVMTI_EVENT_EXCEPTION_CATCH:
+ if (env->callbacks.ExceptionCatch != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jmethodID, method);
+ ARG (jlocation, location);
+ ARG (jobject, exception);
+ env->callbacks.ExceptionCatch (env, jni_env, event_thread, method,
+ location, exception);
+ }
+ break;
+
+ case JVMTI_EVENT_SINGLE_STEP:
+ if (env->callbacks.SingleStep != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jmethodID, method);
+ ARG (jlocation, location);
+ env->callbacks.SingleStep (env, jni_env, event_thread, method,
+ location);
+ }
+ break;
+
+ case JVMTI_EVENT_FRAME_POP:
+ if (env->callbacks.FramePop != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jmethodID, method);
+ GET_BOOLEAN_ARG (was_popped_by_exception);
+ env->callbacks.FramePop (env, jni_env, event_thread, method,
+ was_popped_by_exception);
+ }
+ break;
+
+ case JVMTI_EVENT_BREAKPOINT:
+ if (env->callbacks.Breakpoint != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jmethodID, method);
+ ARG (jlocation, location);
+ env->callbacks.Breakpoint (env, jni_env, event_thread, method,
+ location);
+ }
+ break;
+
+ case JVMTI_EVENT_FIELD_ACCESS:
+ if (env->callbacks.FieldAccess != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jmethodID, method);
+ ARG (jlocation, location);
+ ARG (jclass, field_class);
+ ARG (jobject, object);
+ ARG (jfieldID, field);
+ env->callbacks.FieldAccess (env, jni_env, event_thread, method,
+ location, field_class, object, field);
+ }
+ break;
+
+ case JVMTI_EVENT_FIELD_MODIFICATION:
+ if (env->callbacks.FieldModification != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jmethodID, method);
+ ARG (jlocation, location);
+ ARG (jclass, field_class);
+ ARG (jobject, object);
+ ARG (jfieldID, field);
+ GET_CHAR_ARG (signature_type);
+ ARG (jvalue, new_value);
+ env->callbacks.FieldModification (env, jni_env, event_thread, method,
+ location, field_class, object,
+ field, signature_type, new_value);
+ }
+ break;
+
+ case JVMTI_EVENT_METHOD_ENTRY:
+ if (env->callbacks.MethodEntry != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jmethodID, method);
+ env->callbacks.MethodEntry (env, jni_env, event_thread, method);
+ }
+ break;
+
+ case JVMTI_EVENT_METHOD_EXIT:
+ if (env->callbacks.MethodExit != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jmethodID, method);
+ GET_BOOLEAN_ARG (was_popped_by_exception);
+ ARG (jvalue, return_value);
+ env->callbacks.MethodExit (env, jni_env, event_thread, method,
+ was_popped_by_exception, return_value);
+ }
+ break;
+
+ case JVMTI_EVENT_NATIVE_METHOD_BIND:
+ if (env->callbacks.NativeMethodBind != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jmethodID, method);
+ ARG (void *, address);
+ ARG (void **, new_address_ptr);
+ env->callbacks.NativeMethodBind (env, jni_env, event_thread, method,
+ address, new_address_ptr);
+ }
+ break;
+
+ case JVMTI_EVENT_COMPILED_METHOD_LOAD:
+ if (env->callbacks.CompiledMethodLoad != NULL)
+ {
+ ARG (jmethodID, method);
+ ARG (jint, code_size);
+ ARG (const void *, code_addr);
+ ARG (jint, map_length);
+ ARG (const jvmtiAddrLocationMap *, map);
+ ARG (const void *, compile_info);
+ env->callbacks.CompiledMethodLoad (env, method, code_size, code_addr,
+ map_length, map, compile_info);
+ }
+ break;
+
+ case JVMTI_EVENT_COMPILED_METHOD_UNLOAD:
+ if (env->callbacks.CompiledMethodUnload != NULL)
+ {
+ ARG (jmethodID, method);
+ ARG (const void *, code_addr);
+ env->callbacks.CompiledMethodUnload (env, method, code_addr);
+ }
+ break;
+
+ case JVMTI_EVENT_DYNAMIC_CODE_GENERATED:
+ if (env->callbacks.DynamicCodeGenerated != NULL)
+ {
+ ARG (const char *, name);
+ ARG (const void *, address);
+ ARG (jint, length);
+ env->callbacks.DynamicCodeGenerated (env, name, address, length);
+ }
+ break;
+
+ case JVMTI_EVENT_DATA_DUMP_REQUEST:
+ if (env->callbacks.DataDumpRequest != NULL)
+ {
+ env->callbacks.DataDumpRequest (env);
+ }
+ break;
+
+ case JVMTI_EVENT_MONITOR_WAIT:
+ if (env->callbacks.MonitorWait != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jobject, object);
+ ARG (jlong, timeout);
+ env->callbacks.MonitorWait (env, jni_env, event_thread, object,
+ timeout);
+ }
+ break;
+
+ case JVMTI_EVENT_MONITOR_WAITED:
+ if (env->callbacks.MonitorWaited != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jobject, object);
+ GET_BOOLEAN_ARG (timed_out);
+ env->callbacks.MonitorWaited (env, jni_env, event_thread, object,
+ timed_out);
+ }
+ break;
+
+ case JVMTI_EVENT_MONITOR_CONTENDED_ENTER:
+ if (env->callbacks.MonitorContendedEnter != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jobject, object);
+ env->callbacks.MonitorContendedEnter (env, jni_env, event_thread,
+ object);
+ }
+ break;
+
+ case JVMTI_EVENT_MONITOR_CONTENDED_ENTERED:
+ if (env->callbacks.MonitorContendedEntered != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jobject, object);
+ env->callbacks.MonitorContendedEntered (env, jni_env, event_thread,
+ object);
+ }
+ break;
+
+ case JVMTI_EVENT_GARBAGE_COLLECTION_START:
+ if (env->callbacks.GarbageCollectionStart != NULL)
+ {
+ env->callbacks.GarbageCollectionStart (env);
+ }
+ break;
+
+ case JVMTI_EVENT_GARBAGE_COLLECTION_FINISH:
+ if (env->callbacks.GarbageCollectionFinish != NULL)
+ {
+ env->callbacks.GarbageCollectionFinish (env);
+ }
+ break;
+
+ case JVMTI_EVENT_OBJECT_FREE:
+ if (env->callbacks.ObjectFree != NULL)
+ {
+ ARG (jlong, tag);
+ env->callbacks.ObjectFree (env, tag);
+ }
+ break;
+
+ case JVMTI_EVENT_VM_OBJECT_ALLOC:
+ if (env->callbacks.VMObjectAlloc != NULL)
+ {
+ ARG (JNIEnv *, jni_env);
+ ARG (jobject, object);
+ ARG (jclass, object_class);
+ ARG (jlong, size);
+ env->callbacks.VMObjectAlloc (env, jni_env, event_thread,
+ object, object_class, size);
+ }
+ break;
+
+ default:
+ fprintf (stderr, "libgcj: post of unknown JVMTI event (%d)\n",
+ (int) type);
+ break;
+ }
+ va_end (args);
+#undef ARG
+#undef GET_BOOLEAN_ARG
+#undef GET_CHAR_ARG
+}
+
+/* Post an event to requesting JVMTI environments
+ *
+ * This function should not be called without consulting the
+ * JVMTI_REQUESTED_EVENT macro first (for speed). It does no real
+ * harm (other than kill speed), since this function will still
+ * only send the event if it was properly requested by an environment.
+ */
+void
+_Jv_JVMTI_PostEvent (jvmtiEvent type, jthread event_thread, ...)
+{
+ va_list args;
+ va_start (args, event_thread);
+
+ _envListLock->readLock ()->lock ();
+ struct jvmti_env_list *e;
+ FOREACH_ENVIRONMENT (e)
+ {
+ /* Events are only posted if the event was explicitly enabled,
+ it has a registered event handler, and the event thread
+ matches (either globally or restricted to a specific thread).
+ Here we check all but the event handler, which will be handled
+ by post_event. */
+ if (e->env->enabled[EVENT_INDEX(type)]
+ && (e->env->thread[EVENT_INDEX(type)] == NULL
+ || e->env->thread[EVENT_INDEX(type)] == event_thread))
+ {
+ post_event (e->env, type, event_thread, args);
+ }
+ }
+ _envListLock->readLock ()->unlock ();
+ va_end (args);
+}