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