This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA/JVMTI] SetEventNotificationMode and SetEventCallbacks


Tom Tromey wrote:

Sorry it took me so long to get back to this.
Please feel free to ping me if my delays are blocking you.

I could say the same thing! You're doing fine. Whenever there is a pause, I just go clean up another patch. [It's amazing how much cleanup I left myself. Man, I'm a slob! :-)]

Keith> +      void (**callback)()
Keith> +	= reinterpret_cast<void (**)()> (&e->env->callbacks) + index;

This looks invalid to me though I don't have a reference to the
standard for it.  Could we use a pointer-to-member instead?
Sorry to keep going around on this.

Okay, I've changed this to use offsetof. Since JNI already has the restriction that function pointers are the same size as void*, this next revision should be closer. [And there's certainly no need to apologize for making sure I'm a straight shooter. You keep "going around on [anything]" you like.]


One or two notes about how this patch differs from the previous (or even
the original):

o It locks the environment list whenever it is traversed. Methinks this is safest to prevent segfaulting if a thread using JVMTI disposes an environment while the JVMTI framework is posting an event or attempting to check for enabled events.

o It corrects some varargs bugs that I discovered while testing.

o It adds (in a separate patch) tests for this stuff.

Keith

ChangeLog
2006-09-20  Keith Seitz  <keiths@redhat.com>

        * jvmti.cc (_Jv_JVMTI_DisposeEnvironment): Check for enabled
        events.
        (check_enabled_event): New function.
        (check_enabled_events): New function.
        (post_event): New function.
        (_Jv_JVMTI_SetEventNotificationMode): New function.
        (_Jv_JVMTI_SetEventCallbacks): New function.
        (_Jv_JVMTI_Interface): Define SetEventNotificationMode and
        SetEventCallbacks members.
        * include/jvmti-int.h: New file.
        * include/jvmti_md.h (EVENT_SLOTS) [__GCJ_JNI_IMP__]: Define.
        (_CLASSPATH_JVMTIENV_CONTENTS) [__GCJ_JNI_IMPL__]: Define.
        * testsuite/libjava.jvmti/events.java: New file.
        * testsuite/libjava.jvmti/events.out: New file.
        * testsuite/libjava.jvmti/natevents.cc: New file.

Index: jvmti.cc
===================================================================
--- jvmti.cc	(revision 117098)
+++ jvmti.cc	(working copy)
@@ -15,6 +15,7 @@
 #include <java-threads.h>
 #include <java-gc.h>
 #include <jvmti.h>
+#include "jvmti-int.h"
 
 #include <gcj/method.h>
 
@@ -32,6 +33,9 @@
 #include <java/util/HashMap.h>
 #include <java/net/URL.h>
 
+static void check_enabled_events (void);
+static void check_enabled_event (jvmtiEvent);
+
 extern struct JNINativeInterface _Jv_JNIFunctions;
 
 struct _Jv_rawMonitorID
@@ -519,6 +523,9 @@
     }
 
   _Jv_Free (env);
+
+  check_enabled_events ();
+
   return JVMTI_ERROR_NONE;
 }
 
@@ -665,6 +672,300 @@
   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
+
+  JvSynchronize dummy (_envListLock);
+  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;
+	  return;
+	}
+    }
+
+  *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)
+    {
+      using namespace java::lang;
+      Thread *t = reinterpret_cast<Thread *> (event_thread);
+      THREAD_CHECK_VALID (t);
+      THREAD_CHECK_IS_ALIVE (t);
+    }
+
+  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;
+}
+
 jvmtiError
 _Jv_JVMTI_GetErrorName (MAYBE_UNUSED jvmtiEnv *env, jvmtiError error,
 			char **name_ptr)
@@ -884,7 +1185,7 @@
 struct _Jv_jvmtiEnv _Jv_JVMTI_Interface =
 {
   RESERVED,			// reserved1
-  UNIMPLEMENTED,		// SetEventNotification
+  _Jv_JVMTI_SetEventNotificationMode, // SetEventNotificationMode
   RESERVED,			// reserved3
   UNIMPLEMENTED,		// GetAllThreads
   _Jv_JVMTI_SuspendThread,	// SuspendThread
@@ -1004,7 +1305,7 @@
   RESERVED,			// reserved119
   _Jv_JVMTI_SetJNIFunctionTable, // SetJNIFunctionTable
   _Jv_JVMTI_GetJNIFunctionTable, // GetJNIFunctionTable
-  UNIMPLEMENTED,		// SetEventCallbacks
+  _Jv_JVMTI_SetEventCallbacks,	// SetEventCallbacks
   UNIMPLEMENTED,		// GenerateEvents
   UNIMPLEMENTED,		// GetExtensionFunctions
   UNIMPLEMENTED,		// GetExtensionEvents
@@ -1072,4 +1373,385 @@
 {
   _jvmtiEnvironments = NULL;
   _envListLock = new java::lang::Object ();
+
+  // 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);
+
+  JvSynchronize dummy (_envListLock);
+  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);
+	}
+    }
+
+  va_end (args);
+}
Index: include/jvmti-int.h
===================================================================
--- include/jvmti-int.h	(revision 0)
+++ include/jvmti-int.h	(revision 0)
@@ -0,0 +1,85 @@
+/* jvmti-int.h -- Internal JVMTI definitions
+   Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
+
+#ifndef __GCJ_JVTMI_INT_H__
+#define __GCJ_JVMTI_INT_H__
+
+/* A macro to map jvmtiEvent to an index in thread[] and enabled[]
+   in the jvmtiEnv. This will only work if the order of events listed
+   in jvmtiEvent and jvmtiEventCallbacks is kept the same (which should
+   not be a problem). */
+#define EVENT_INDEX(jvmtievent) (int)(jvmtievent - JVMTI_EVENT_VM_INIT)
+
+/* A few globals to help limit the impact of JVMTI on normal operations.
+   False means no JVMTI environment requested that event type. */
+namespace JVMTI
+{
+  bool VMInit;
+  bool VMDeath;
+  bool ThreadStart;
+  bool ThreadEnd;
+  bool ClassFileLoadHook;
+  bool ClassLoad;
+  bool ClassPrepare;
+  bool VMStart;
+  bool Exception;
+  bool ExceptionCatch;
+  bool SingleStep;
+  bool FramePop;
+  bool Breakpoint;
+  bool FieldAccess;
+  bool FieldModification;
+  bool MethodEntry;
+  bool MethodExit;
+  bool NativeMethodBind;
+  bool CompiledMethodLoad;
+  bool CompiledMethodUnload;
+  bool DynamicCodeGenerated;
+  bool DataDumpRequest;
+  bool reserved72;
+  bool MonitorWait;
+  bool MonitorWaited;
+  bool MonitorContendedEnter;
+  bool MonitorContendedEntered;
+  bool reserved77;
+  bool reserved78;
+  bool reserved79;
+  bool reserved80;
+  bool GarbageCollectionStart;
+  bool GarbageCollectionFinish;
+  bool ObjectFree;
+  bool VMObjectAlloc;
+};
+
+/* A macro to test whether an event should be posted to JVMTI.*/
+#define JVMTI_REQUESTED_EVENT(Event) __builtin_expect (JVMTI::Event, false)
+
+/* Post the event to requesting JVMTI environments.
+
+   For speed, this function should only be called after 
+   JVMTI_REQUESTED_EVENT is checked. */
+extern void _Jv_JVMTI_PostEvent (jvmtiEvent type, jthread event_thread,				 ...);
+#endif /* __GCJ_JVMTI_INT_H__ */
Index: include/jvmti_md.h
===================================================================
--- include/jvmti_md.h	(revision 117093)
+++ include/jvmti_md.h	(working copy)
@@ -27,6 +27,32 @@
 #ifndef __GCJ_JVMTI_MD_H__
 #define __GCJ_JVMTI_MD_H__
 
-// nothing
+#ifdef __GCJ_JNI_IMPL__
 
+/* If __GCJ_JNI_IMPL__ is defined, then we assume that we're building
+   libgcj itself, and we include functions which should not be exposed
+   to JVMTI users. */
+
+/* The number of event slots needed to keep track of event reporting
+   constraints for an environment. This will only work if the order of
+   events listed in jvmtiEvent and jvmtiEventCallbacks is kept the same
+   (which should not be a problem). */
+#define EVENT_SLOTS \
+  (int)(JVMTI_EVENT_VM_OBJECT_ALLOC - JVMTI_EVENT_VM_INIT + 1)
+
+/* Contents of the jvmtiEnv; but only inside the implementation. */
+#define _CLASSPATH_JVMTIENV_CONTENTS					\
+  /* Event handlers registered via SetEventCallbacks */			\
+  jvmtiEventCallbacks callbacks;					\
+									\
+  /* Array of event thread for which to report event. */		\
+  /* NULL means all threads. One for each callback.   */		\
+  jthread thread[EVENT_SLOTS];						\
+  									\
+  /* Array of notification modes for callbacks. */			\
+  /* One for each callback.                     */			\
+  bool enabled[EVENT_SLOTS];
+
+#endif /* __GCJ_JNI_IMPL__ */
+
 #endif /* __GCJ_JVMTI_MD_H__ */
Index: testsuite/libjava.jvmti/events.java
===================================================================
--- testsuite/libjava.jvmti/events.java	(revision 0)
+++ testsuite/libjava.jvmti/events.java	(revision 0)
@@ -0,0 +1,12 @@
+// Test JVMTI event notifications
+
+public class events
+{
+  public static native void do_events_tests ();
+
+  public static void main (String[] args)
+  {
+    System.out.println ("JVMTI event notification tests");
+    do_events_tests ();
+  }
+}
Index: testsuite/libjava.jvmti/natevents.cc
===================================================================
--- testsuite/libjava.jvmti/natevents.cc	(revision 0)
+++ testsuite/libjava.jvmti/natevents.cc	(revision 0)
@@ -0,0 +1,544 @@
+#include <gcj/cni.h>
+
+#include <jvm.h>
+#include <jvmti.h>
+#include <stdio.h>
+
+#include "jvmti-int.h"
+#include "events.h"
+
+static jvmtiEnv *env = NULL;
+
+void
+print_events ()
+{
+#define DO(X)					\
+  do						\
+    {						\
+      if (JVMTI_REQUESTED_EVENT (X))		\
+	printf (#X ",");			\
+    }						\
+  while (0)
+
+  printf ("RequestedEvents: ");
+  DO (VMInit);
+  DO (VMDeath);
+  DO (ThreadStart);
+  DO (ThreadEnd);
+  DO (ClassFileLoadHook);
+  DO (ClassLoad);
+  DO (ClassPrepare);
+  DO (VMStart);
+  DO (Exception);
+  DO (ExceptionCatch);
+  DO (SingleStep);
+  DO (FramePop);
+  DO (Breakpoint);
+  DO (FieldAccess);
+  DO (FieldModification);
+  DO (MethodEntry);
+  DO (MethodExit);
+  DO (NativeMethodBind);
+  DO (CompiledMethodLoad);
+  DO (CompiledMethodUnload);
+  DO (DynamicCodeGenerated);
+  DO (DataDumpRequest);
+  DO (MonitorWait);
+  DO (MonitorWaited);
+  DO (MonitorContendedEnter);
+  DO (MonitorContendedEntered);
+  DO (GarbageCollectionStart);
+  DO (GarbageCollectionFinish);
+  DO (ObjectFree);
+  DO (VMObjectAlloc);
+  printf ("\n");
+#undef DO
+}
+
+static void
+VMInitCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread)
+{
+  printf ("VMInitCB jni_env=%p thread=%p\n", jni_env, thread);
+}
+
+static void
+VMDeathCB (jvmtiEnv *env, JNIEnv *jni_env)
+{
+  printf ("VMDeathCB jni_env=%p\n", jni_env);
+}
+
+static void
+ThreadStartCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread)
+{
+  printf ("ThreadStartCB jni_env=%p thread=%p\n", jni_env, thread);
+}
+
+static void
+ThreadEndCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread)
+{
+  printf ("ThreadEndCB jni_env=%p thread=%p\n", jni_env, thread);
+}
+
+static void
+ClassFileLoadHookCB (jvmtiEnv *env, JNIEnv *jni_env,
+		     jclass class_being_redefined, jobject loader,
+		     const char *name, jobject protection_domain,
+		     jint class_data_len, const unsigned char *class_data,
+		     jint *new_class_data_len, unsigned char **new_class_data)
+{
+  printf ("ClassFileLoadHookCB jni_env=%p class_being_redefined=%p loader=%p",
+	  jni_env, class_being_redefined, loader);
+  printf (" name=%s protection_domain=%p class_data_len=%d class_data=%p",
+	  name, protection_domain, (int) class_data_len, class_data);
+  printf (" new_class_data_len=%p new_class_data=%p\n", new_class_data_len,
+	  new_class_data);
+}
+
+static void
+ClassLoadCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread, jclass klass)
+{
+  printf ("ClassLoadCB jni_env=%p thread=%p klass=%p\n", jni_env, thread,
+	  klass);
+}
+
+static void
+ClassPrepareCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread, jclass klass)
+{
+  printf ("ClassPrepareCB jni_env=%p thread=%p klass=%p\n", jni_env,
+	  thread, klass);
+}
+
+static void
+VMStartCB (jvmtiEnv *env, JNIEnv *jni_env)
+{
+  printf ("VMStartCB jni_env=%p\n", jni_env);
+}
+
+static void
+ExceptionCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread, jmethodID method,
+	     jlocation location, jobject exception, jmethodID catch_method,
+	     jlocation catch_location)
+{
+  printf ("ExceptionCB jni_env=%p thread=%p method=%p location=%p", jni_env,
+	  thread, method, location);
+  printf (" exception=%p catch_method=%p catch_location=%p\n", exception,
+	  catch_method, catch_location);
+}
+
+static void
+ExceptionCatchCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread,
+		  jmethodID method, jlocation location, jobject exception)
+{
+  printf ("ExceptionCatchCB jni_env=%p thread=%p method=%p location=%p",
+	  jni_env, thread, method, location);
+  printf (" exception=%p\n", exception);
+}
+
+static void
+SingleStepCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread, jmethodID method,
+	      jlocation location)
+{
+  printf ("SingleStepCB jni_env=%p thread=%p method=%p location=%p\n", 
+	  jni_env, thread, method, location);
+}
+
+static void
+FramePopCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread, jmethodID method,
+	    jboolean was_popped_by_exception)
+{
+  printf ("FramePopCB jni_env=%p thread=%p method=%p", jni_env, thread,
+	  method);
+  printf (" was_pooped_by_exception=%d\n", (was_popped_by_exception ?
+					    1 : 0));
+}
+
+static void
+BreakpointCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread, jmethodID method,
+	      jlocation location)
+{
+  printf ("BreakpointCB  jni_env=%p thread=%p method=%p location=%p\n",
+	  jni_env, thread, method, location);
+}
+
+static void
+FieldAccessCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread,
+	       jmethodID method, jlocation location, jclass field_klass,
+	       jobject object, jfieldID field)
+{
+  printf ("FieldAccessCB jni_env=%p thread=%p method=%p location=%p",
+	  jni_env, thread, method, location);
+  printf (" field_klass=%p object=%p field=%p\n", field_klass, object, field);
+}
+
+static void
+FieldModificationCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread,
+		     jmethodID method, jlocation location, jclass field_klass,
+		     jobject object, jfieldID field, char signature_type,
+		     jvalue new_value)
+
+{
+  printf ("FieldModificationCB  jni_env=%p thread=%p method=%p location=%p",
+	  jni_env, thread, method, location);
+  printf (" field_klass=%p object=%p field=%p signature_type=%c", field_klass,
+	  object, field, signature_type);
+  printf (" new_value=%d\n", (int) new_value.i);
+}
+
+static void
+MethodEntryCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread,
+	       jmethodID method)
+{
+  printf ("MethodEntryCB jni_env=%p thread=%p method=%p\n", jni_env, thread,
+	  method);
+}
+
+static void
+MethodExitCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread,
+	      jmethodID method, jboolean was_popped_by_exception,
+	      jvalue return_value)
+{
+  printf ("MethodExitCB jni_env=%p thread=%p method=%p", jni_env, thread,
+	  method);
+  printf (" was_popped_by_exception=%d return_value=%d\n",
+	  (was_popped_by_exception) ? 1 : 0, (int) return_value.i);
+}
+
+static void
+NativeMethodBindCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread,
+		    jmethodID method, void *address, void **new_address_ptr)
+{
+  printf ("NativeMethodBindCB jni_env=%p thread=%p method=%p", jni_env,
+	  thread, method);
+  printf (" address=%p new_address_ptr=%p\n", address, new_address_ptr);
+}
+
+static void
+CompiledMethodLoadCB (jvmtiEnv *env, jmethodID method, jint code_size,
+		      const void *code_addr, jint map_length,
+		      const jvmtiAddrLocationMap *map,
+		      const void *compile_info)
+{
+  printf ("CompiledMethodLoadCB method=%p code_size=%p code_addr=%p",
+	  method, code_size, code_addr);
+  printf (" map_length=%d map=%p compile_info=%p\n", (int) map_length, map,
+	  compile_info);
+}
+
+static void
+CompiledMethodUnloadCB (jvmtiEnv *env, jmethodID method, const void *code_addr)
+{
+  printf ("CompiledMethodUnloadCB method=%p code_addr=%p\n", method, 
+	  code_addr);
+}
+
+static void
+DynamicCodeGeneratedCB (jvmtiEnv *env, const char *name, const void *address,
+			jint length)
+{
+  printf ("DynamicCodeGeneratedCB name=%s address=%p length=%d\n", name,
+	  address, (int) length);
+}
+
+static void
+DataDumpRequestCB (jvmtiEnv *env)
+{
+  printf ("DataDumpRequestCB\n");
+}
+
+static void
+MonitorWaitCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread, jobject object,
+	       jlong timeout)
+{
+  printf ("MonitorWaitCB jni_env=%p thread=%p object=%p timeout=%ld\n",
+	  jni_env, thread, object, (long) timeout);
+}
+
+static void
+MonitorWaitedCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread,
+		 jobject object, jboolean timed_out)
+{
+  printf ("MonitorWaitedCB jni_env=%p thread=%p object=%p timed_out=%d\n",
+	  jni_env, thread, object, (timed_out) ? 1 : 0);
+}
+
+static void
+MonitorContendedEnterCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread,
+			 jobject object)
+{
+  printf ("MonitorContendedEnterCB jni_env=%p thread=%p object=%p\n",
+	  jni_env, thread, object);
+}
+
+static void
+MonitorContendedEnteredCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread,
+			   jobject object)
+{
+  printf ("MonitorContendedEnteredCB jni_env=%p thread=%p object=%p\n",
+	  jni_env, thread, object);
+}
+
+static void
+GarbageCollectionStartCB (jvmtiEnv *env)
+{
+  printf ("GarbageCollectionStartCB\n");
+}
+
+static void
+GarbageCollectionFinishCB (jvmtiEnv *env)
+{
+  printf ("GarbageCollectionFinishCB\n");
+}
+
+static void
+ObjectFreeCB (jvmtiEnv *env, jlong tag)
+{
+  printf ("ObjectFreeCB tag=%ld\n", (long) tag);
+}
+
+static void
+VMObjectAllocCB (jvmtiEnv *env, JNIEnv *jni_env, jthread thread,
+		 jobject object, jclass object_klass, jlong size)
+{
+  printf ("VMObjectAllocCB jni_env=%p thread=%p object=%p", jni_env,
+	  thread, object);
+  printf (" object_klass=%p size=%ld\n", object_klass, (long) size);
+}
+
+static void
+do_enable_tests ()
+{
+  printf ("- enable tests -\n");
+  JavaVM *vm = _Jv_GetJavaVM ();
+  jvmtiEnv *env[3];
+  int i;
+  for (i = 0; i < 3; ++i)
+    {
+      vm->GetEnv (reinterpret_cast<void **> (&env[i]), JVMTI_VERSION_1_0);
+      printf ("created JVMTI environment #%d\n", i);
+    }
+
+  jvmtiEventCallbacks callbacks;
+  memset (&callbacks, 0, sizeof (jvmtiEventCallbacks));
+
+  printf ("setting callbacks for envs\n");
+  callbacks.VMInit = VMInitCB;
+  env[0]->SetEventCallbacks (&callbacks, sizeof (callbacks));
+  callbacks.VMDeath = VMDeathCB;
+  env[1]->SetEventCallbacks (&callbacks, sizeof (callbacks));
+  callbacks.ThreadEnd = ThreadEndCB;
+  env[2]->SetEventCallbacks (&callbacks, sizeof (callbacks));
+  print_events ();
+
+  printf ("enable VM_INIT for env0, env1, env2\n");
+  env[0]->SetEventNotificationMode (JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
+  env[1]->SetEventNotificationMode (JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
+  env[2]->SetEventNotificationMode (JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
+  print_events ();
+
+  printf ("enable VM_DEATH for env1,env2\n");
+  env[1]->SetEventNotificationMode (JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL);
+  env[2]->SetEventNotificationMode (JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL);
+  print_events ();
+
+  /* Used to use a non-NULL event thread, but that causes problems
+     when SetEventNotificationMode tries to validate the thread. */
+  printf ("enable THREAD_END for env2\n");
+  env[2]->SetEventNotificationMode (JVMTI_ENABLE, JVMTI_EVENT_THREAD_END,
+				    NULL);
+  print_events ();
+
+  printf ("disposing of env1\n");
+  env[1]->DisposeEnvironment ();
+  print_events ();
+
+  printf ("disposing of env0\n");
+  env[0]->DisposeEnvironment ();
+  print_events ();
+
+  printf ("disable VMInit in env2\n");
+  env[2]->SetEventNotificationMode (JVMTI_DISABLE, JVMTI_EVENT_VM_INIT, NULL);
+  print_events ();
+
+  printf ("clear VMDeath callback in env2\n");
+  callbacks.VMDeath = NULL;
+  env[2]->SetEventCallbacks (&callbacks, sizeof (callbacks));
+  print_events ();
+
+  printf ("sending VMInit\n");
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_VM_INIT, (jthread) 0x1234,
+		       (JNIEnv *) 0x5678);
+
+  printf ("sending ThreadEnd\n");
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_THREAD_END, (jthread) 0x1234,
+		       (JNIEnv *) 0x5678);
+
+  /* See comment above re: SetEventNotificationMode and validity
+     checking
+  printf ("sending ThreadEnd (no match)\n");
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_THREAD_END, (jthread) 0x4321,
+		       (JNIEnv *) 0x5678);
+  */
+
+  printf ("sending VMDeath\n");
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_VM_DEATH, (jthread) NULL,
+		       (JNIEnv *) 0x5678);
+
+  printf ("disposing of env2\n");
+  env[2]->DisposeEnvironment ();
+  print_events ();
+}
+
+static void
+do_callback_arg_tests ()
+{
+  printf ("- callback arg tests -\n");
+  JavaVM *vm = _Jv_GetJavaVM ();
+  jvmtiEnv *env;
+  vm->GetEnv (reinterpret_cast<void **> (&env), JVMTI_VERSION_1_0);
+
+  // Define all the callbacks
+#define DEFINE(Event) callbacks.Event = Event ## CB;
+  jvmtiEventCallbacks callbacks;
+  DEFINE(VMInit);
+  DEFINE(VMDeath);
+  DEFINE(ThreadStart);
+  DEFINE(ThreadEnd);
+  DEFINE(ClassFileLoadHook);
+  DEFINE(ClassLoad);
+  DEFINE(ClassPrepare);
+  DEFINE(VMStart);
+  DEFINE(Exception);
+  DEFINE(ExceptionCatch);
+  DEFINE(SingleStep);
+  DEFINE(FramePop);
+  DEFINE(Breakpoint);
+  DEFINE(FieldAccess);
+  DEFINE(FieldModification);
+  DEFINE(MethodEntry);
+  DEFINE(MethodExit);
+  DEFINE(NativeMethodBind);
+  DEFINE(CompiledMethodLoad);
+  DEFINE(CompiledMethodUnload);
+  DEFINE(DynamicCodeGenerated);
+  DEFINE(DataDumpRequest);
+  DEFINE(MonitorWait);
+  DEFINE(MonitorWaited);
+  DEFINE(MonitorContendedEnter);
+  DEFINE(MonitorContendedEntered);
+  DEFINE(GarbageCollectionStart);
+  DEFINE(GarbageCollectionFinish);
+  DEFINE(ObjectFree);
+  DEFINE(VMObjectAlloc);
+#undef DEFINE
+  env->SetEventCallbacks (&callbacks, sizeof (callbacks));
+
+  // Enable all the callbacks
+#define ENABLE(Event)							\
+  env->SetEventNotificationMode (JVMTI_ENABLE, JVMTI_EVENT_ ## Event, NULL)
+  ENABLE (VM_INIT);
+  ENABLE (VM_DEATH);
+  ENABLE (THREAD_START);
+  ENABLE (THREAD_END);
+  ENABLE (CLASS_FILE_LOAD_HOOK);
+  ENABLE (CLASS_LOAD);
+  ENABLE (CLASS_PREPARE);
+  ENABLE (VM_START);
+  ENABLE (EXCEPTION);
+  ENABLE (EXCEPTION_CATCH);
+  ENABLE (SINGLE_STEP);
+  ENABLE (FRAME_POP);
+  ENABLE (BREAKPOINT);
+  ENABLE (FIELD_ACCESS);
+  ENABLE (FIELD_MODIFICATION);
+  ENABLE (METHOD_ENTRY);
+  ENABLE (METHOD_EXIT);
+  ENABLE (NATIVE_METHOD_BIND);
+  ENABLE (COMPILED_METHOD_LOAD);
+  ENABLE (COMPILED_METHOD_UNLOAD);
+  ENABLE (DYNAMIC_CODE_GENERATED);
+  ENABLE (DATA_DUMP_REQUEST);
+  ENABLE (MONITOR_WAIT);
+  ENABLE (MONITOR_WAITED);
+  ENABLE (MONITOR_CONTENDED_ENTER);
+  ENABLE (MONITOR_CONTENDED_ENTERED);
+  ENABLE (GARBAGE_COLLECTION_START);
+  ENABLE (GARBAGE_COLLECTION_FINISH);
+  ENABLE (OBJECT_FREE);
+  ENABLE (VM_OBJECT_ALLOC);
+
+  // All events should now be enabled.
+  print_events ();
+
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_VM_INIT, (jthread) 0x2, (JNIEnv *) 0x1);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_VM_DEATH, (jthread) 0x2, (JNIEnv *) 0x1);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_THREAD_START, (jthread) 0x2,
+		       (JNIEnv *) 0x1);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_THREAD_END, (jthread) 0x2,
+		       (JNIEnv *) 0x1);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, (jthread) 0xb00,
+		       (JNIEnv *) 0x1, (jclass) 0x2, (jobject) 0x3,
+		       "4", (jobject) 0x5, (jint) 6,
+		       (const unsigned char *) 0x7, (jint *) 0x8,
+		       (unsigned char **) 0x9);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_CLASS_LOAD, (jthread) 0x2, (JNIEnv *) 0x1,
+		       (jclass) 0x3);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_CLASS_PREPARE, (jthread) 0x2,
+		       (JNIEnv *) 0x1, (jclass) 0x3);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_VM_START, (jthread) 0xb00, (JNIEnv *) 0x1);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_EXCEPTION, (jthread) 0x2, (JNIEnv *) 0x1,
+		       (jmethodID) 0x3, (jlocation) 0x4, (jobject) 0x5,
+		       (jmethodID) 0x6, (jlocation) 0x7);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_EXCEPTION_CATCH, (jthread) 0x2,
+		       (JNIEnv *) 0x1, (jmethodID) 0x3, (jlocation) 0x4,
+		       (jobject) 0x5);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_SINGLE_STEP, (jthread) 0x2, (JNIEnv *) 0x1,
+		       (jmethodID) 0x3, (jlocation) 0x4);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_FRAME_POP, (jthread) 0x2, (JNIEnv *) 0x1,
+		       (jmethodID) 0x3, 4);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_BREAKPOINT, (jthread) 0x2, (JNIEnv *) 0x1,
+		       (jmethodID) 0x3, (jlocation) 0x4);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_FIELD_ACCESS, (jthread) 0x2,
+		       (JNIEnv *) 0x1, (jmethodID) 0x3, (jlocation) 0x4,
+		       (jclass) 0x5, (jobject) 0x6, (jfieldID) 0x7);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_FIELD_MODIFICATION, (jthread) 0x2,
+		       (JNIEnv *) 0x1, (jmethodID) 0x3, (jlocation) 0x4,
+		       (jclass) 0x5, (jobject) 0x6, (jfieldID) 0x7,
+		       (int) '8', (/*jvalue*/ jobject) 0x9);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_METHOD_ENTRY, (jthread) 0x2,
+		       (JNIEnv *) 0x1, (jmethodID) 0x3);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_METHOD_EXIT, (jthread) 0x2,
+		       (JNIEnv *) 0x1, (jmethodID) 0x3, 4, /*jvalue*/ 5);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_NATIVE_METHOD_BIND, (jthread) 0x2,
+		       (JNIEnv *) 0x1, (jmethodID) 0x3, (void *) 0x4,
+		       (void **) 0x5);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_COMPILED_METHOD_LOAD, (jthread) 0xb00,
+		       (jmethodID) 0x1, (jint) 2, (const void *) 0x3,
+		       (jint) 4, (const jvmtiAddrLocationMap *) 0x5,
+		       (const void *) 0x6);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_COMPILED_METHOD_UNLOAD, (jthread) 0xb00,
+		       (jmethodID) 0x1, (const void *) 0x2);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_DYNAMIC_CODE_GENERATED, (jthread) 0xb00,
+		       "1", (const void *) 0x2, (jint) 3);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_DATA_DUMP_REQUEST, (jthread) 0xb00);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_MONITOR_WAIT, (jthread) 0x2,
+		       (JNIEnv *) 0x1, (jobject) 0x3, (jlong) 4);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_MONITOR_WAITED, (jthread) 0x2,
+		       (JNIEnv *) 0x1, (jobject) 0x3, (int) 4);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_MONITOR_CONTENDED_ENTER, (jthread) 0x2,
+		       (JNIEnv *) 0x1, (jobject) 0x3);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, (jthread) 0x2,
+		       (JNIEnv *) 0x1, (jobject) 0x3);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_GARBAGE_COLLECTION_START, (jthread) 0xb00);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, (jthread) 0xb00);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_OBJECT_FREE, (jthread) 0xb00, (jlong) 1);
+  _Jv_JVMTI_PostEvent (JVMTI_EVENT_VM_OBJECT_ALLOC, (jthread) 0x2,
+		       (JNIEnv *) 0x1, (jobject) 0x3, (jclass) 0x4,
+		       (jlong) 5);
+}
+
+void
+events::do_events_tests ()
+{
+  do_enable_tests ();
+  do_callback_arg_tests ();
+}
Index: testsuite/libjava.jvmti/events.out
===================================================================
--- testsuite/libjava.jvmti/events.out	(revision 0)
+++ testsuite/libjava.jvmti/events.out	(revision 0)
@@ -0,0 +1,59 @@
+JVMTI event notification tests
+- enable tests -
+created JVMTI environment #0
+created JVMTI environment #1
+created JVMTI environment #2
+setting callbacks for envs
+RequestedEvents: 
+enable VM_INIT for env0, env1, env2
+RequestedEvents: VMInit,
+enable VM_DEATH for env1,env2
+RequestedEvents: VMInit,VMDeath,
+enable THREAD_END for env2
+RequestedEvents: VMInit,VMDeath,ThreadEnd,
+disposing of env1
+RequestedEvents: VMInit,VMDeath,ThreadEnd,
+disposing of env0
+RequestedEvents: VMInit,VMDeath,ThreadEnd,
+disable VMInit in env2
+RequestedEvents: VMDeath,ThreadEnd,
+clear VMDeath callback in env2
+RequestedEvents: ThreadEnd,
+sending VMInit
+sending ThreadEnd
+ThreadEndCB jni_env=0x5678 thread=0x1234
+sending VMDeath
+disposing of env2
+RequestedEvents: 
+- callback arg tests -
+RequestedEvents: VMInit,VMDeath,ThreadStart,ThreadEnd,ClassFileLoadHook,ClassLoad,ClassPrepare,VMStart,Exception,ExceptionCatch,SingleStep,FramePop,Breakpoint,FieldAccess,FieldModification,MethodEntry,MethodExit,NativeMethodBind,CompiledMethodLoad,CompiledMethodUnload,DynamicCodeGenerated,DataDumpRequest,MonitorWait,MonitorWaited,MonitorContendedEnter,MonitorContendedEntered,GarbageCollectionStart,GarbageCollectionFinish,ObjectFree,VMObjectAlloc,
+VMInitCB jni_env=0x1 thread=0x2
+VMDeathCB jni_env=0x1
+ThreadStartCB jni_env=0x1 thread=0x2
+ThreadEndCB jni_env=0x1 thread=0x2
+ClassFileLoadHookCB jni_env=0x1 class_being_redefined=0x2 loader=0x3 name=4 protection_domain=0x5 class_data_len=6 class_data=0x7 new_class_data_len=0x8 new_class_data=0x9
+ClassLoadCB jni_env=0x1 thread=0x2 klass=0x3
+ClassPrepareCB jni_env=0x1 thread=0x2 klass=0x3
+VMStartCB jni_env=0x1
+ExceptionCB jni_env=0x1 thread=0x2 method=0x3 location=0x4 exception=0x5 catch_method=0x6 catch_location=0x7
+ExceptionCatchCB jni_env=0x1 thread=0x2 method=0x3 location=0x4 exception=0x5
+SingleStepCB jni_env=0x1 thread=0x2 method=0x3 location=0x4
+FramePopCB jni_env=0x1 thread=0x2 method=0x3 was_pooped_by_exception=1
+BreakpointCB  jni_env=0x1 thread=0x2 method=0x3 location=0x4
+FieldAccessCB jni_env=0x1 thread=0x2 method=0x3 location=0x4 field_klass=0x5 object=0x6 field=0x7
+FieldModificationCB  jni_env=0x1 thread=0x2 method=0x3 location=0x4 field_klass=0x5 object=0x6 field=0x7 signature_type=8 new_value=9
+MethodEntryCB jni_env=0x1 thread=0x2 method=0x3
+MethodExitCB jni_env=0x1 thread=0x2 method=0x3 was_popped_by_exception=1 return_value=5
+NativeMethodBindCB jni_env=0x1 thread=0x2 method=0x3 address=0x4 new_address_ptr=0x5
+CompiledMethodLoadCB method=0x1 code_size=0x2 code_addr=0x3 map_length=4 map=0x5 compile_info=0x6
+CompiledMethodUnloadCB method=0x1 code_addr=0x2
+DynamicCodeGeneratedCB name=1 address=0x2 length=3
+DataDumpRequestCB
+MonitorWaitCB jni_env=0x1 thread=0x2 object=0x3 timeout=4
+MonitorWaitedCB jni_env=0x1 thread=0x2 object=0x3 timed_out=1
+MonitorContendedEnterCB jni_env=0x1 thread=0x2 object=0x3
+MonitorContendedEnteredCB jni_env=0x1 thread=0x2 object=0x3
+GarbageCollectionStartCB
+GarbageCollectionFinishCB
+ObjectFreeCB tag=1
+VMObjectAllocCB jni_env=0x1 thread=0x2 object=0x3 object_klass=0x4 size=5

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]