Patch: JVMPI

Anthony Green green@cygnus.com
Mon Mar 27 00:06:00 GMT 2000


The following patch implements partial support for JVMPI, the
profiling interface.

It is enabled by default.  A configure option, --disable-jvmpi, can
turn it off.  I have not included a patch for the generated configure
file below.

This patch only provides support for object allocation, thread start
and thread end events.

JVMPI is described here...
      http://java.sun.com/products/jdk/1.3/docs/guide/jvmpi/jvmpi.html

Some of the magic numbers aren't defined in the spec, so I made them
up and noted them with FIXME's in the headers.

This patch also introduces a way to call JNI libraries at program
startup.  JNI_OnLoad is defined as a weak symbol in natFirstThread.cc.
If a JNI library providing JNI_OnLoad is linked into an executable
then that function is called just before the main java function.  Some
systems, like Linux, let you preload shared libraries before running a
fully linked executable.  This is a neat trick, and here's how you can
take advantage of it with JVMPI.  Consider sizes.c...

---- cut here ------------------------------------------------------------
#include <jni.h>
#include <jvmpi.h>
#include <stdio.h>

JVMPI_Interface *jvmpi_interface;

void notify (JVMPI_Event *event)
{
  if (event->event_type == JVMPI_EVENT_OBJECT_ALLOC)
    printf ("size = %d\n", event->u.obj_alloc.size);
}

jint JNI_OnLoad (JavaVM *jvm, void *args)
{
  int res = (*jvm)->GetEnv (jvm, (void **)&jvmpi_interface, JVMPI_VERSION_1);
  if (res != 0)
    return JNI_ERR;

  jvmpi_interface->NotifyEvent = notify;
  (*jvmpi_interface->EnableEvent) (JVMPI_EVENT_OBJECT_ALLOC, NULL);

  return JNI_VERSION_1_2;
}
---- cut here ------------------------------------------------------------

Compile it like so...

$ gcc -shared -o libsizes.so sizes.c

Given a gcj built java program `hello'...

$ hello
Hello World

...using LD_PRELOAD will magically enable the profiling code...

$ LD_PRELOAD=libsizes.so hello
size = 38
size = 12
size = 12
size = 12
size = 68
size = 12
...etc...
size = 16
Hello World
size = 12


This patch also introduces _Jv_DisableGC and _Jv_EnableGC, which are
required by JVMPI.


AG

-- 
Anthony Green                                                        Red Hat
                                                       Sunnyvale, California

2000-03-27  Anthony Green  <green@redhat.com>
 
	* include/config.h.in: Rebuilt.
	* acconfig.h: Add ENABLE_JVMPI.
	* configure: Rebuilt.
	* configure.in: Add --disable-jvmpi.
 
	* java/lang/natThread.cc: Include JVMPI headers if necessary.
	(finish_): Generate JVMPI thread end events.
	(run_): Generate JVMPI thread start events.
	* gnu/gcj/runtime/natFirstThread.cc (run): Call JNI_OnLoad for any
	preloaded JNI library.
	Include JVMPI headers if necessary.
	(run): Generate JVMPI thread start events.
  
	* include/jvm.h: Declare _Jv_DisableGC and _Jv_EnableGC.
  
	* boehm.cc: Define GC_disable and GC_enable.
	(_Jv_DisableGC): New function.
	(_Jv_EnableGC): New function.
  
	* jni.cc (_Jv_JNI_GetEnv): Handle JVMPI interface requests.
	(_Jv_JVMPI_Interface): Define.
	(jvmpiEnableEvent): New function.
	(_Jv_JNI_Init): Initialize _Jv_JVMPI_Interface.
	
	* include/jvmpi.h: New file.

Index: acconfig.h
===================================================================
RCS file: /cvs/java/libgcj/libjava/acconfig.h,v
retrieving revision 1.18
diff -c -r1.18 acconfig.h
*** acconfig.h	2000/01/31 04:53:47	1.18
--- acconfig.h	2000/03/27 07:24:27
***************
*** 137,139 ****
--- 137,142 ----
  
  /* Define if you have working iconv() function.  */
  #undef HAVE_ICONV
+ 
+ /* Define if you are using JVMPI.  */
+ #undef ENABLE_JVMPI
Index: boehm.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/boehm.cc,v
retrieving revision 1.15
diff -c -r1.15 boehm.cc
*** boehm.cc	2000/03/07 19:55:24	1.15
--- boehm.cc	2000/03/27 07:24:28
***************
*** 391,396 ****
--- 391,412 ----
    GC_set_max_heap_size ((GC_word) size);
  }
  
+ // From boehm's misc.c 
+ extern "C" void GC_enable();
+ extern "C" void GC_disable();
+ 
+ void
+ _Jv_DisableGC (void)
+ {
+   GC_disable();
+ }
+ 
+ void
+ _Jv_EnableGC (void)
+ {
+   GC_enable();
+ }
+ 
  void
  _Jv_InitGC (void)
  {
Index: configure.in
===================================================================
RCS file: /cvs/java/libgcj/libjava/configure.in,v
retrieving revision 1.54
diff -c -r1.54 configure.in
*** configure.in	2000/03/26 20:33:03	1.54
--- configure.in	2000/03/27 07:24:31
***************
*** 127,132 ****
--- 127,140 ----
     AC_DEFINE(DISABLE_JAVA_NET)
  fi
  
+ dnl See if the user wants to disable JVMPI support.
+ AC_ARG_ENABLE(jvmpi,
+ [  --disable-jvmpi         disable JVMPI support])
+ 
+ if test "$enable_jvmpi" != no; then
+     AC_DEFINE(ENABLE_JVMPI)
+ fi
+ 
  dnl If the target is an eCos system, use the appropriate eCos
  dnl I/O routines.
  dnl FIXME: this should not be a local option but a global target
Index: jni.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/jni.cc,v
retrieving revision 1.27
diff -c -r1.27 jni.cc
*** jni.cc	2000/03/14 21:59:54	1.27
--- jni.cc	2000/03/27 07:24:34
***************
*** 20,25 ****
--- 20,28 ----
  #include <jvm.h>
  #include <java-assert.h>
  #include <jni.h>
+ #ifdef ENABLE_JVMPI
+ #include <jvmpi.h>
+ #endif
  
  #include <java/lang/Class.h>
  #include <java/lang/ClassLoader.h>
***************
*** 105,116 ****
--- 108,178 ----
  // The only VM.
  static JavaVM *the_vm;
  
+ #ifdef ENABLE_JVMPI
+ extern void (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (JVMPI_Event *event);
+ extern void (*_Jv_JVMPI_Notify_THREAD_END) (JVMPI_Event *event);
+ extern void (*_Jv_JVMPI_Notify_THREAD_START) (JVMPI_Event *event);
+ 
+ // The only JVMPI interface description.
+ static JVMPI_Interface _Jv_JVMPI_Interface;
+ 
+ static jint
+ jvmpiEnableEvent (jint event_type, void *arg)
+ {
+   switch (event_type)
+     {
+     case JVMPI_EVENT_OBJECT_ALLOC:
+       _Jv_JVMPI_Notify_OBJECT_ALLOC = _Jv_JVMPI_Interface.NotifyEvent;
+       break;
+       
+     case JVMPI_EVENT_THREAD_START:
+       _Jv_JVMPI_Notify_THREAD_START = _Jv_JVMPI_Interface.NotifyEvent;
+       break;
+       
+     case JVMPI_EVENT_THREAD_END:
+       _Jv_JVMPI_Notify_THREAD_END = _Jv_JVMPI_Interface.NotifyEvent;
+       break;
+       
+     default:
+       return JVMPI_NOT_AVAILABLE;
+     }
+   
+   return JVMPI_SUCCESS;
+ }
+ 
+ static jint
+ jvmpiDisableEvent (jint event_type, void *arg)
+ {
+   switch (event_type)
+     {
+     case JVMPI_EVENT_OBJECT_ALLOC:
+       _Jv_JVMPI_Notify_OBJECT_ALLOC = NULL;
+       break;
+       
+     default:
+       return JVMPI_NOT_AVAILABLE;
+     }
+   
+   return JVMPI_SUCCESS;
+ }
+ #endif
+ 
  
  
  void
  _Jv_JNI_Init (void)
  {
    ref_table = new java::util::Hashtable;
+   
+ #ifdef ENABLE_JVMPI
+   _Jv_JVMPI_Interface.version = 1;
+   _Jv_JVMPI_Interface.EnableEvent = &jvmpiEnableEvent;
+   _Jv_JVMPI_Interface.DisableEvent = &jvmpiDisableEvent;
+   _Jv_JVMPI_Interface.EnableGC = &_Jv_EnableGC;
+   _Jv_JVMPI_Interface.DisableGC = &_Jv_DisableGC;
+   _Jv_JVMPI_Interface.DisableGC = &_Jv_DisableGC;
+   _Jv_JVMPI_Interface.RunGC = &_Jv_RunGC;
+ #endif
  }
  
  // Tell the GC that a certain pointer is live.
***************
*** 1867,1872 ****
--- 1929,1943 ----
        *penv = NULL;
        return JNI_EDETACHED;
      }
+ 
+ #ifdef ENABLE_JVMPI
+   // Handle JVMPI requests.
+   if (version == JVMPI_VERSION_1)
+     {
+       *penv = (void *) &_Jv_JVMPI_Interface;
+       return 0;
+     }
+ #endif
  
    // FIXME: do we really want to support 1.1?
    if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_1)
Index: prims.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/prims.cc,v
retrieving revision 1.24
diff -c -r1.24 prims.cc
*** prims.cc	2000/03/15 22:03:19	1.24
--- prims.cc	2000/03/27 07:24:34
***************
*** 34,39 ****
--- 34,43 ----
  #include <java-signal.h>
  #include <java-threads.h>
  
+ #ifdef ENABLE_JVMPI
+ #include <jvmpi.h>
+ #endif
+ 
  #ifndef DISABLE_GETENV_PROPERTIES
  #include <ctype.h>
  #include <java-props.h>
***************
*** 83,88 ****
--- 87,96 ----
  // The name of this executable.
  static char * _Jv_execName;
  
+ #ifdef ENABLE_JVMPI
+ // Pointer to JVMPI notification functions.
+ void (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (JVMPI_Event *event);
+ #endif
  
  
  #ifdef HANDLE_SEGV
***************
*** 325,330 ****
--- 333,359 ----
    // appropriate index in the method vector.
    if (c->vtable->method[1] != ObjectClass.vtable->method[1])
      _Jv_RegisterFinalizer (obj, _Jv_FinalizeObject);
+ 
+ #ifdef ENABLE_JVMPI
+   // Service JVMPI request.
+ 
+   if (_Jv_JVMPI_Notify_OBJECT_ALLOC)
+     {
+       JVMPI_Event event;
+ 
+       event.event_type = JVMPI_EVENT_OBJECT_ALLOC;
+       event.env_id = NULL;
+       event.u.obj_alloc.arena_id = 0;
+       event.u.obj_alloc.class_id = (jobjectID) c;
+       event.u.obj_alloc.is_array = 0;
+       event.u.obj_alloc.size = size;
+       event.u.obj_alloc.obj_id = (jobjectID) obj;
+ 
+       _Jv_DisableGC ();
+       (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (&event);
+       _Jv_EnableGC ();
+     }
+ #endif
  
    return obj;
  }
Index: gnu/gcj/runtime/natFirstThread.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/gnu/gcj/runtime/natFirstThread.cc,v
retrieving revision 1.2
diff -c -r1.2 natFirstThread.cc
*** natFirstThread.cc	2000/03/07 19:55:25	1.2
--- natFirstThread.cc	2000/03/27 07:24:35
***************
*** 14,19 ****
--- 14,20 ----
  
  #include <gcj/cni.h>
  #include <jvm.h>
+ #include <jni.h>
  
  #include <gnu/gcj/runtime/FirstThread.h>
  #include <java/lang/Class.h>
***************
*** 22,37 ****
--- 23,78 ----
  #include <java/lang/reflect/Modifier.h>
  #include <java/io/PrintStream.h>
  
+ #ifdef ENABLE_JVMPI
+ #include <jvmpi.h>
+ #include <java/lang/ThreadGroup.h>
+ #include <java/lang/UnsatisfiedLinkError.h>
+ #endif
+ 
  #define DIE(Message)  die (JvNewStringLatin1 (Message))
  
  typedef void main_func (jobject);
  
+ #ifdef WITH_JVMPI
+ extern void (*_Jv_JVMPI_Notify_THREAD_START) (JVMPI_Event *event);
+ #endif
+ 
+ /* This will be non-NULL if the user has preloaded a JNI library, or
+    linked one into the executable.  */
+ extern "C" 
+ {
+ #pragma weak JNI_OnLoad
+   extern jint JNI_OnLoad (JavaVM *, void *) __attribute__((weak));
+ }
+ 
  void
  gnu::gcj::runtime::FirstThread::run (void)
  {
+ 
    Utf8Const* main_signature = _Jv_makeUtf8Const ("([Ljava.lang.String;)V", 22);
    Utf8Const* main_name = _Jv_makeUtf8Const ("main", 4);
  
+   /* Some systems let you preload shared libraries before running a
+      program.  Under Linux, this is done by setting the LD_PRELOAD
+      environment variable.  We take advatage of this here to allow for
+      dynamically loading a JNI library into a fully linked executable.  */
+ 
+   if (JNI_OnLoad != NULL)
+     {
+       JavaVM *vm = _Jv_GetJavaVM ();
+       if (vm == NULL)
+ 	{
+ 	  // FIXME: what?
+ 	  return;
+ 	}
+       jint vers = JNI_OnLoad (vm, NULL);
+       if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2)
+ 	{
+ 	  // FIXME: unload the library.
+ 	  _Jv_Throw (new java::lang::UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from preloaded JNI_OnLoad")));
+ 	}
+     }
+ 
    if (klass == NULL)
      {
        klass = java::lang::Class::forName (klass_name);
***************
*** 47,52 ****
--- 88,147 ----
      DIE ("`main' must be static");
    if (! java::lang::reflect::Modifier::isPublic(meth->accflags))
      DIE ("`main' must be public");
+ 
+ #ifdef WITH_JVMPI
+   if (_Jv_JVMPI_Notify_THREAD_START)
+     {
+       JVMPI_Event event;
+ 
+       jstring thread_name = getName ();
+       jstring group_name = NULL, parent_name = NULL;
+       java::lang::ThreadGroup *group = getThreadGroup ();
+ 
+       if (group)
+ 	{
+ 	  group_name = group->getName ();
+ 	  group = group->getParent ();
+ 
+ 	  if (group)
+ 	    parent_name = group->getName ();
+ 	}
+ 
+       int thread_len = thread_name ? JvGetStringUTFLength (thread_name) : 0;
+       int group_len = group_name ? JvGetStringUTFLength (group_name) : 0;
+       int parent_len = parent_name ? JvGetStringUTFLength (parent_name) : 0;
+ 
+       char thread_chars[thread_len + 1];
+       char group_chars[group_len + 1];
+       char parent_chars[parent_len + 1];
+ 
+       if (thread_name)
+ 	JvGetStringUTFRegion (thread_name, 0, 
+ 			      thread_name->length(), thread_chars);
+       if (group_name)
+ 	JvGetStringUTFRegion (group_name, 0, 
+ 			      group_name->length(), group_chars);
+       if (parent_name)
+ 	JvGetStringUTFRegion (parent_name, 0, 
+ 			      parent_name->length(), parent_chars);
+ 
+       thread_chars[thread_len] = '\0';
+       group_chars[group_len] = '\0';
+       parent_chars[parent_len] = '\0';
+ 
+       event.event_type = JVMPI_EVENT_THREAD_START;
+       event.env_id = NULL;
+       event.u.thread_start.thread_name = thread_chars;
+       event.u.thread_start.group_name = group_chars;
+       event.u.thread_start.parent_name = parent_chars;
+       event.u.thread_start.thread_id = (jobjectID) this;
+       event.u.thread_start.thread_env_id = _Jv_GetCurrentJNIEnv ();
+ 
+       _Jv_DisableGC ();
+       (*_Jv_JVMPI_Notify_THREAD_START) (&event);
+       _Jv_EnableGC ();
+     }
+ #endif
  
    main_func *real_main = (main_func *) meth->ncode;
    (*real_main) (args);
Index: include/config.h.in
===================================================================
RCS file: /cvs/java/libgcj/libjava/include/config.h.in,v
retrieving revision 1.22
diff -c -r1.22 config.h.in
*** config.h.in	2000/01/31 04:53:47	1.22
--- config.h.in	2000/03/27 07:24:35
***************
*** 152,157 ****
--- 152,163 ----
  /* Define if g++ has a bug preventing us from inlining math routines.  */
  #undef __NO_MATH_INLINES
  
+ /* Define if you are using JVMPI.  */
+ #undef ENABLE_JVMPI
+ 
+ /* The number of bytes in a void *.  */
+ #undef SIZEOF_VOID_P
+ 
  /* Define if you have the access function.  */
  #undef HAVE_ACCESS
  
Index: include/jvm.h
===================================================================
RCS file: /cvs/java/libgcj/libjava/include/jvm.h,v
retrieving revision 1.19
diff -c -r1.19 jvm.h
*** jvm.h	2000/03/07 19:55:25	1.19
--- jvm.h	2000/03/27 07:24:35
***************
*** 82,87 ****
--- 82,90 ----
  void _Jv_RunAllFinalizers (void);
  /* Perform a GC.  */
  void _Jv_RunGC (void);
+ /* Disable and enable GC.  */
+ void _Jv_DisableGC (void);
+ void _Jv_EnableGC (void);
  
  /* Return approximation of total size of heap.  */
  long _Jv_GCTotalMemory (void);
Index: include/jvmpi.h
===================================================================
RCS file: jvmpi.h
diff -N jvmpi.h
*** /dev/null	Tue May  5 13:32:27 1998
--- jvmpi.h	Sun Mar 26 23:24:35 2000
***************
*** 0 ****
--- 1,230 ----
+ /* Copyright (C) 2000  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.  */
+ 
+ /* Note: this file must be compilable by the C compiler (for now,
+    assuming GNU C is ok).  This means you must never use `//'
+    comments, and all C++-specific code must be conditional on
+    __cplusplus.  */
+ 
+ #ifndef __GCJ_JVMPI_H__
+ #define __GCJ_JVMPI_H__
+ 
+ #include <jni.h>
+ 
+ /* JVMPI version numbers.  FIXME: this is a semi-random number.  The
+    documentation doesn't say what it should be.  */
+ #define JVMPI_VERSION_1 0x00020001
+ 
+ /* JVMPI return codes.  FIXME: These are semi-random numbers.  The
+    documentation doesn't say what they should be.  */
+ #define JVMPI_SUCCESS       0
+ #define JVMPI_FAIL          1
+ #define JVMPI_NOT_AVAILABLE 2
+ 
+ /* An opaque pointer representing an object ID.  */
+ struct _jobjectID;
+ typedef struct _jobjectID * jobjectID;       
+ 
+ typedef struct
+ {
+   /* Source line number.  */
+   jint lineno;
+   /* Method being executed.  */
+   jmethodID method_id;
+ } JVMPI_CallFrame;
+ 
+ typedef struct 
+ {
+   JNIEnv *env_id;
+   /* Number of frames in the call trace.  */
+   jint num_frames;
+   /* An array of frames representing the trace.  Callees first.  */
+   JVMPI_CallFrame *frames;
+ } JVMPI_CallTrace;
+ 
+ typedef struct
+ {
+   /* Name of the field.  */
+   char *field_name;
+   /* Signature of the field.  */
+   char *field_signature;
+ } JVMPI_Field;
+ 
+ /* The documentation doesn't actually specify what the
+    JVMPI_DUMP_LEVEL macros should be defined to.  Here's a reasonable
+    guess.  */
+ #define JVMPI_DUMP_LEVEL_0 0
+ #define JVMPI_DUMP_LEVEL_1 1
+ #define JVMPI_DUMP_LEVEL_2 2
+ #define JVMPI_DUMP_LEVEL_3 3
+ 
+ typedef struct
+ {
+   /* One of JVMPI_DUMP_LEVEL_0, JVMPI_DUMP_LEVEL_1 or
+      JVMPI_DUMP_LEVEL_2.  */
+   jint heap_dump_level;
+ } JVMPI_HeapDumpArg;
+ 
+ typedef struct
+ {
+   /* Offset from the beginning of the method.  */
+   jint offset;
+   /* Line number from the beginning of the source file.  */
+   jint lineno;
+ } JVMPI_Lineno;
+ 
+ typedef struct
+ {
+   /* Name of the method.  */
+   char *method_name;
+   /* Signature of the method.  */
+   char *method_signature;
+   /* Start line number from the beginning of the source file.  */
+   jint start_lineno;
+   /* End line number from the beginning of the source file.  */
+   jint end_lineno;
+   /* The method ID.  */
+   jmethodID method_id;
+ } JVMPI_Method;
+ 
+ /* An opaque pointer representing a raw monitor.  */
+ struct _JVMPI_RawMonitor;
+ typedef struct _JVMPI_RawMonitor *JVMPI_RawMonitor;
+ 
+ /* JVMPI event codes.  FIXME: These are semi-random numbers.  The
+    documentation doesn't say what they should be.  */
+ #define JVMPI_EVENT_ARENA_DELETE                   0
+ #define JVMPI_EVENT_ARENA_NEW                      1
+ #define JVMPI_EVENT_CLASS_LOAD                     2
+ #define JVMPI_EVENT_CLASS_LOAD_HOOK                3
+ #define JVMPI_EVENT_CLASS_UNLOAD                   4
+ #define JVMPI_EVENT_COMPILED_METHOD_LOAD           5
+ #define JVMPI_EVENT_COMPILED_METHOD_UNLOAD         6
+ #define JVMPI_EVENT_DATA_DUMP_REQUEST              7
+ #define JVMPI_EVENT_DATA_RESET_REQUEST             8
+ #define JVMPI_EVENT_GC_FINISH                      9
+ #define JVMPI_EVENT_GC_START                      10
+ #define JVMPI_EVENT_HEAP_DUMP                     11
+ #define JVMPI_EVENT_JNI_GLOBALREF_ALLOC           12
+ #define JVMPI_EVENT_JNI_GLOBALREF_FREE            13
+ #define JVMPI_EVENT_JNI_WEAK_GLOBALREF_ALLOC      14
+ #define JVMPI_EVENT_JNI_WEAK_GLOBALREF_FREE       15
+ #define JVMPI_EVENT_JVM_INIT_DONE                 16
+ #define JVMPI_EVENT_JVM_SHUT_DOWN                 17
+ #define JVMPI_EVENT_METHOD_ENTRY                  18
+ #define JVMPI_EVENT_METHOD_ENTRY2                 19
+ #define JVMPI_EVENT_METHOD_EXIT                   20
+ #define JVMPI_EVENT_MONITOR_CONTENDED_ENTER       21
+ #define JVMPI_EVENT_MONITOR_CONTENDED_ENTERED     22
+ #define JVMPI_EVENT_MONITOR_CONTENDED_EXIT        23
+ #define JVMPI_EVENT_MONITOR_DUMP                  24
+ #define JVMPI_EVENT_MONITOR_WAIT                  25
+ #define JVMPI_EVENT_MONITOR_WAITED                26
+ #define JVMPI_EVENT_OBJECT_ALLOC                  27
+ #define JVMPI_EVENT_OBJECT_DUMP                   28
+ #define JVMPI_EVENT_OBJECT_FREE                   29
+ #define JVMPI_EVENT_OBJECT_MOVE                   30
+ #define JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTER   31
+ #define JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTERED 32
+ #define JVMPI_EVENT_RAW_MONITOR_CONTENDED_EXIT    33
+ #define JVMPI_EVENT_THREAD_END                    34
+ #define JVMPI_EVENT_THREAD_START                  35
+ #define JVMPI_EVENT_INSTRUCTION_START             36
+ 
+ 
+ typedef struct
+ {
+   /* Event type.  */
+   jint event_type;
+ 
+   /* Evn where this event occurred.  */
+   JNIEnv *env_id;
+ 
+   union 
+   {
+     struct
+     {
+       char *class_name;
+       char *source_name;
+       jint num_interfaces;
+       jint num_methods;
+       JVMPI_Method *methods;
+       jint num_static_fields;
+       JVMPI_Field *statics;
+       jint num_instance_fields;
+       JVMPI_Field *instances;
+       jobjectID class_id;
+     } class_load;
+ 
+     struct
+     {
+       jobjectID class_id;
+     } class_unload;
+ 
+     struct
+     {
+       jint arena_id;
+       jobjectID class_id;
+       jint is_array;
+       jint size;
+       jobjectID obj_id;
+     } obj_alloc;
+ 
+     struct
+     {
+       char *thread_name;
+       char *group_name;
+       char *parent_name;
+       jobjectID thread_id;
+       JNIEnv *thread_env_id;
+     } thread_start;
+ 
+   } u;
+ 
+ } JVMPI_Event;
+ 
+ typedef struct
+ {
+   /* JVMPI version number.  */
+   jint version;
+   
+   /* Implemented by the user...  */
+   void (*NotifyEvent) (JVMPI_Event *event);
+   
+   /* Implemented by the runtime...  */
+   jint (*EnableEvent) (jint event_type, void *arg);
+   jint (*DisableEvent) (jint event_type, void *arg);
+   jint (*RequestEvent) (jint event_type, void *arg);
+   void (*GetCallTrace) (JVMPI_CallTrace *trace, jint depth);
+   void (*ProfilerExit) (jint);
+   JVMPI_RawMonitor (*RawMonitorCreate) (char *lock_name);
+   void (*RawMonitorEnter) (JVMPI_RawMonitor lock_id);
+   void (*RawMonitorExit) (JVMPI_RawMonitor lock_id);
+   void (*RawMonitorWait) (JVMPI_RawMonitor lock_id, jlong ms);
+   void (*RawMonitorNotifyAll) (JVMPI_RawMonitor lock_id);
+   void (*RawMonitorDestroy) (JVMPI_RawMonitor lock_id);
+   jlong (*GetCurrentThreadCpuTime) (void);
+   void (*SuspendThread) (JNIEnv *env);
+   void (*ResumeThread) (JNIEnv *env);
+   jint (*GetThreadStatus) (JNIEnv *env);
+   jboolean (*ThreadHasRun) (JNIEnv *env);
+   jint (*CreateSystemThread) (char *name, jint priority, void (*f) (void *));
+   void (*SetThreadLocalStorage) (JNIEnv *env_id, void *ptr);
+   void *(*GetThreadLocalStorage) (JNIEnv *env_id);
+   void (*DisableGC) (void);
+   void (*EnableGC) (void);
+   void (*RunGC) (void);
+   jobjectID (*GetThreadObject) (JNIEnv *env);
+   jobjectID (*GetMethodClass) (jmethodID mid);
+   
+ } JVMPI_Interface;
+ 
+ /* Global event flags.  */
+ extern void (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (JVMPI_Event *event);
+ 
+ #endif /* __GCJ_JVMPI_H__ */
Index: java/lang/natThread.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/lang/natThread.cc,v
retrieving revision 1.15
diff -c -r1.15 natThread.cc
*** natThread.cc	2000/03/07 19:55:26	1.15
--- natThread.cc	2000/03/27 07:24:35
***************
*** 27,32 ****
--- 27,38 ----
  
  #include <jni.h>
  
+ #ifdef ENABLE_JVMPI
+ #include <jvmpi.h>
+ void (*_Jv_JVMPI_Notify_THREAD_END) (JVMPI_Event *event);
+ void (*_Jv_JVMPI_Notify_THREAD_START) (JVMPI_Event *event);
+ #endif
+ 
  
  
  // This structure is used to represent all the data the native side
***************
*** 281,286 ****
--- 287,306 ----
  
    group->remove (this);
  
+ #ifdef ENABLE_JVMPI  
+   if (_Jv_JVMPI_Notify_THREAD_END)
+     {
+       JVMPI_Event event;
+ 
+       event.event_type = JVMPI_EVENT_THREAD_END;
+       event.env_id = _Jv_GetCurrentJNIEnv ();
+ 
+       _Jv_DisableGC ();
+       (*_Jv_JVMPI_Notify_THREAD_END) (&event);
+       _Jv_EnableGC ();
+     }
+ #endif
+ 
    _Jv_MonitorExit (this);
  }
  
***************
*** 290,295 ****
--- 310,370 ----
    java::lang::Thread *thread = (java::lang::Thread *) obj;
    try
      {
+ 
+ #ifdef ENABLE_JVMPI
+       if (_Jv_JVMPI_Notify_THREAD_START)
+ 	{
+ 	  JVMPI_Event event;
+ 	  
+ 	  jstring thread_name = thread->getName ();
+ 	  jstring group_name = NULL, parent_name = NULL;
+ 	  java::lang::ThreadGroup *group = thread->getThreadGroup ();
+ 
+ 	  if (group)
+ 	    {
+ 	      group_name = group->getName ();
+ 	      group = group->getParent ();
+ 	      
+ 	      if (group)
+ 		parent_name = group->getName ();
+ 	    }
+ 	  
+ 	  int thread_len = thread_name ? JvGetStringUTFLength (thread_name) : 0;
+ 	  int group_len = group_name ? JvGetStringUTFLength (group_name) : 0;
+ 	  int parent_len = parent_name ? JvGetStringUTFLength (parent_name) : 0;
+ 	  
+ 	  char thread_chars[thread_len + 1];
+ 	  char group_chars[group_len + 1];
+ 	  char parent_chars[parent_len + 1];
+ 	  
+ 	  if (thread_name)
+ 	    JvGetStringUTFRegion (thread_name, 0, 
+ 				  thread_name->length(), thread_chars);
+ 	  if (group_name)
+ 	    JvGetStringUTFRegion (group_name, 0, 
+ 				  group_name->length(), group_chars);
+ 	  if (parent_name)
+ 	    JvGetStringUTFRegion (parent_name, 0, 
+ 				  parent_name->length(), parent_chars);
+ 	  
+ 	  thread_chars[thread_len] = '\0';
+ 	  group_chars[group_len] = '\0';
+ 	  parent_chars[parent_len] = '\0';
+ 	  
+ 	  event.event_type = JVMPI_EVENT_THREAD_START;
+ 	  event.env_id = NULL;
+ 	  event.u.thread_start.thread_name = thread_chars;
+ 	  event.u.thread_start.group_name = group_chars;
+ 	  event.u.thread_start.parent_name = parent_chars;
+ 	  event.u.thread_start.thread_id = (jobjectID) thread;
+ 	  event.u.thread_start.thread_env_id = _Jv_GetCurrentJNIEnv ();
+ 	  
+ 	  _Jv_DisableGC ();
+ 	  (*_Jv_JVMPI_Notify_THREAD_START) (&event);
+ 	  _Jv_EnableGC ();
+ 	}
+ #endif
+ 
        thread->run ();
      }
    catch (java::lang::Throwable *t)



...and from boehm-gc...

2000-03-26  Anthony Green  <green@redhat.com>

	* misc.c (GC_enable): Always define GC_enable and GC_disable.


Index: misc.c
===================================================================
RCS file: /cvs/cvsfiles/devo/boehm-gc/misc.c,v
retrieving revision 1.14
diff -c -r1.14 misc.c
*** misc.c     2000/03/13 21:02:57	1.14
--- misc.c     2000/03/27 07:49:00
***************
*** 819,825 ****
  
  #endif /* SAVE_CALL_CHAIN */
  
- # ifdef SRC_M3
  void GC_enable()
  {
      GC_dont_gc--;
--- 819,824 ----
***************
*** 829,835 ****
  {
      GC_dont_gc++;
  }
- # endif
  
  #if !defined(NO_DEBUGGING)



More information about the Java-patches mailing list