--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.hprof.agent/share/native/libhprof/hprof_util.c Tue Aug 26 07:55:08 2014 +0200
@@ -0,0 +1,1738 @@
+/*
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This source code is provided to illustrate the usage of a given feature
+ * or technique and has been deliberately simplified. Additional steps
+ * required for a production-quality application, such as security checks,
+ * input validation and proper error handling, might not be present in
+ * this sample code.
+ */
+
+
+/* General utility functions. */
+
+/*
+ * Wrappers over JVM, JNI, and JVMTI functions are placed here.
+ *
+ * All memory allocation and deallocation goes through jvmtiAllocate()
+ * and jvmtiDeallocate().
+ *
+ */
+
+
+#include "hprof.h"
+
+/* Macro to get JNI function pointer. */
+#define JNI_FUNC_PTR(env,f) (*((*(env))->f))
+
+/* Macro to get JVM function pointer. */
+#define JVM_FUNC_PTR(env,f) (*((*(env))->f))
+
+/* Macro to get JVMTI function pointer. */
+#define JVMTI_FUNC_PTR(env,f) (*((*(env))->f))
+
+/* ------------------------------------------------------------------- */
+/* JVM functions */
+
+JNIEnv *
+getEnv(void)
+{
+ JNIEnv *env;
+ jint res;
+
+ res = JVM_FUNC_PTR(gdata->jvm,GetEnv)
+ (gdata->jvm, (void **)&env, JNI_VERSION_1_2);
+ if (res != JNI_OK) {
+ char buf[256];
+
+ (void)md_snprintf(buf, sizeof(buf),
+ "Unable to access JNI Version 1.2 (0x%x),"
+ " is your JDK a 5.0 or newer version?"
+ " JNIEnv's GetEnv() returned %d",
+ JNI_VERSION_1_2, res);
+ buf[sizeof(buf)-1] = 0;
+ HPROF_ERROR(JNI_FALSE, buf);
+ error_exit_process(1); /* Kill entire process, no core dump */
+ }
+ return env;
+}
+
+/* ------------------------------------------------------------------- */
+/* Memory Allocation */
+
+void *
+jvmtiAllocate(int size)
+{
+ jvmtiError error;
+ unsigned char *ptr;
+
+ HPROF_ASSERT(size>=0);
+ ptr = NULL;
+ if ( size == 0 ) {
+ return ptr;
+ }
+ error = JVMTI_FUNC_PTR(gdata->jvmti,Allocate)
+ (gdata->jvmti, (jlong)size, &ptr);
+ if ( error != JVMTI_ERROR_NONE || ptr == NULL ) {
+ HPROF_JVMTI_ERROR(error, "Cannot allocate jvmti memory");
+ }
+ return (void*)ptr;
+}
+
+void
+jvmtiDeallocate(void *ptr)
+{
+ if ( ptr != NULL ) {
+ jvmtiError error;
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,Deallocate)
+ (gdata->jvmti, (unsigned char*)ptr);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot deallocate jvmti memory");
+ }
+ }
+}
+
+#ifdef DEBUG
+
+void *
+hprof_debug_malloc(int size, char *file, int line)
+{
+ void *ptr;
+
+ HPROF_ASSERT(size>0);
+
+ rawMonitorEnter(gdata->debug_malloc_lock); {
+ ptr = debug_malloc(size, file, line);
+ } rawMonitorExit(gdata->debug_malloc_lock);
+
+ if ( ptr == NULL ) {
+ HPROF_ERROR(JNI_TRUE, "Cannot allocate malloc memory");
+ }
+ return ptr;
+}
+
+void
+hprof_debug_free(void *ptr, char *file, int line)
+{
+ HPROF_ASSERT(ptr!=NULL);
+
+ rawMonitorEnter(gdata->debug_malloc_lock); {
+ (void)debug_free(ptr, file, line);
+ } rawMonitorExit(gdata->debug_malloc_lock);
+}
+
+#endif
+
+void *
+hprof_malloc(int size)
+{
+ void *ptr;
+
+ HPROF_ASSERT(size>0);
+ ptr = malloc(size);
+ if ( ptr == NULL ) {
+ HPROF_ERROR(JNI_TRUE, "Cannot allocate malloc memory");
+ }
+ return ptr;
+}
+
+void
+hprof_free(void *ptr)
+{
+ HPROF_ASSERT(ptr!=NULL);
+ (void)free(ptr);
+}
+
+/* ------------------------------------------------------------------- */
+/* JVMTI Version functions */
+
+jint
+jvmtiVersion(void)
+{
+ if (gdata->cachedJvmtiVersion == 0) {
+ jvmtiError error;
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetVersionNumber)
+ (gdata->jvmti, &(gdata->cachedJvmtiVersion));
+ if (error != JVMTI_ERROR_NONE) {
+ HPROF_JVMTI_ERROR(error, "Cannot get jvmti version number");
+ }
+ }
+ return gdata->cachedJvmtiVersion;
+}
+
+static jint
+jvmtiMajorVersion(void)
+{
+ return (jvmtiVersion() & JVMTI_VERSION_MASK_MAJOR)
+ >> JVMTI_VERSION_SHIFT_MAJOR;
+}
+
+static jint
+jvmtiMinorVersion(void)
+{
+ return (jvmtiVersion() & JVMTI_VERSION_MASK_MINOR)
+ >> JVMTI_VERSION_SHIFT_MINOR;
+}
+
+static jint
+jvmtiMicroVersion(void)
+{
+ return (jvmtiVersion() & JVMTI_VERSION_MASK_MICRO)
+ >> JVMTI_VERSION_SHIFT_MICRO;
+}
+
+/* Logic to determine JVMTI version compatibility */
+static jboolean
+compatible_versions(jint major_runtime, jint minor_runtime,
+ jint major_compiletime, jint minor_compiletime)
+{
+ /* Runtime major version must match. */
+ if ( major_runtime != major_compiletime ) {
+ return JNI_FALSE;
+ }
+ /* Runtime minor version must be >= the version compiled with. */
+ if ( minor_runtime < minor_compiletime ) {
+ return JNI_FALSE;
+ }
+ /* Assumed compatible */
+ return JNI_TRUE;
+}
+
+/* ------------------------------------------------------------------- */
+/* JVMTI Raw Monitor support functions */
+
+jrawMonitorID
+createRawMonitor(const char *str)
+{
+ jvmtiError error;
+ jrawMonitorID m;
+
+ m = NULL;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,CreateRawMonitor)
+ (gdata->jvmti, str, &m);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot create raw monitor");
+ }
+ return m;
+}
+
+void
+rawMonitorEnter(jrawMonitorID m)
+{
+ jvmtiError error;
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorEnter)
+ (gdata->jvmti, m);
+ if ( error == JVMTI_ERROR_WRONG_PHASE ) {
+ /* Treat this as ok, after agent shutdown CALLBACK code may call this */
+ error = JVMTI_ERROR_NONE;
+ }
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot enter with raw monitor");
+ }
+}
+
+void
+rawMonitorWait(jrawMonitorID m, jlong pause_time)
+{
+ jvmtiError error;
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorWait)
+ (gdata->jvmti, m, pause_time);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot wait with raw monitor");
+ }
+}
+
+void
+rawMonitorNotifyAll(jrawMonitorID m)
+{
+ jvmtiError error;
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorNotifyAll)
+ (gdata->jvmti, m);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot notify all with raw monitor");
+ }
+}
+
+void
+rawMonitorExit(jrawMonitorID m)
+{
+ jvmtiError error;
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorExit)
+ (gdata->jvmti, m);
+ if ( error == JVMTI_ERROR_WRONG_PHASE ) {
+ /* Treat this as ok, after agent shutdown CALLBACK code may call this */
+ error = JVMTI_ERROR_NONE;
+ }
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot exit with raw monitor");
+ }
+}
+
+void
+destroyRawMonitor(jrawMonitorID m)
+{
+ jvmtiError error;
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,DestroyRawMonitor)
+ (gdata->jvmti, m);
+ if ( error == JVMTI_ERROR_WRONG_PHASE ) {
+ /* Treat this as ok */
+ error = JVMTI_ERROR_NONE;
+ }
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot destroy raw monitor");
+ }
+}
+
+/* ------------------------------------------------------------------- */
+/* JVMTI Event enabling/disabilin */
+
+void
+setEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event, jthread thread)
+{
+ jvmtiError error;
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
+ (gdata->jvmti, mode, event, thread);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot set event notification");
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+/* JNI Support Functions */
+
+jobject
+exceptionOccurred(JNIEnv *env)
+{
+ return JNI_FUNC_PTR(env,ExceptionOccurred)(env);
+}
+
+void
+exceptionDescribe(JNIEnv *env)
+{
+ JNI_FUNC_PTR(env,ExceptionDescribe)(env);
+}
+
+void
+exceptionClear(JNIEnv *env)
+{
+ JNI_FUNC_PTR(env,ExceptionClear)(env);
+}
+
+jobject
+newGlobalReference(JNIEnv *env, jobject object)
+{
+ jobject gref;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(object!=NULL);
+ gref = JNI_FUNC_PTR(env,NewGlobalRef)(env, object);
+ HPROF_ASSERT(gref!=NULL);
+ return gref;
+}
+
+jobject
+newWeakGlobalReference(JNIEnv *env, jobject object)
+{
+ jobject gref;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(object!=NULL);
+ gref = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, object);
+ HPROF_ASSERT(gref!=NULL);
+ return gref;
+}
+
+void
+deleteGlobalReference(JNIEnv *env, jobject object)
+{
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(object!=NULL);
+ JNI_FUNC_PTR(env,DeleteGlobalRef)(env, object);
+}
+
+jobject
+newLocalReference(JNIEnv *env, jobject object)
+{
+ jobject lref;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(object!=NULL);
+ lref = JNI_FUNC_PTR(env,NewLocalRef)(env, object);
+ /* Possible for a non-null weak reference to return a NULL localref */
+ return lref;
+}
+
+void
+deleteLocalReference(JNIEnv *env, jobject object)
+{
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(object!=NULL);
+ JNI_FUNC_PTR(env,DeleteLocalRef)(env, object);
+}
+
+void
+deleteWeakGlobalReference(JNIEnv *env, jobject object)
+{
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(object!=NULL);
+ JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, object);
+}
+
+jclass
+getObjectClass(JNIEnv *env, jobject object)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jclass clazz;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(object!=NULL);
+ clazz = JNI_FUNC_PTR(env,GetObjectClass)(env, object);
+ HPROF_ASSERT(clazz!=NULL);
+ return clazz;
+}
+
+jclass
+getSuperclass(JNIEnv *env, jclass klass)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jclass super_klass;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(klass!=NULL);
+ super_klass = JNI_FUNC_PTR(env,GetSuperclass)(env, klass);
+ return super_klass;
+}
+
+jmethodID
+getStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig)
+{
+ jmethodID method;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(clazz!=NULL);
+ HPROF_ASSERT(name!=NULL);
+ HPROF_ASSERT(sig!=NULL);
+ CHECK_EXCEPTIONS(env) {
+ method = JNI_FUNC_PTR(env,GetStaticMethodID)(env, clazz, name, sig);
+ } END_CHECK_EXCEPTIONS;
+ HPROF_ASSERT(method!=NULL);
+ return method;
+}
+
+jmethodID
+getMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig)
+{
+ jmethodID method;
+ jobject exception;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(clazz!=NULL);
+ HPROF_ASSERT(name!=NULL);
+ HPROF_ASSERT(sig!=NULL);
+ method = JNI_FUNC_PTR(env,GetMethodID)(env, clazz, name, sig);
+ /* Might be a static method */
+ exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
+ if ( exception != NULL ) {
+ JNI_FUNC_PTR(env,ExceptionClear)(env);
+ method = getStaticMethodID(env, clazz, name, sig);
+ }
+ HPROF_ASSERT(method!=NULL);
+ return method;
+}
+
+jclass
+findClass(JNIEnv *env, const char *name)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jclass clazz;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(name!=NULL);
+ LOG2("FindClass", name);
+ CHECK_EXCEPTIONS(env) {
+ clazz = JNI_FUNC_PTR(env,FindClass)(env, name);
+ } END_CHECK_EXCEPTIONS;
+ HPROF_ASSERT(clazz!=NULL);
+ return clazz;
+}
+
+jfieldID
+getStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig)
+{
+ jfieldID field;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(clazz!=NULL);
+ HPROF_ASSERT(name!=NULL);
+ HPROF_ASSERT(sig!=NULL);
+ CHECK_EXCEPTIONS(env) {
+ field = JNI_FUNC_PTR(env,GetStaticFieldID)(env, clazz, name, sig);
+ } END_CHECK_EXCEPTIONS;
+ return field;
+}
+
+void
+setStaticIntField(JNIEnv *env, jclass clazz, jfieldID field, jint value)
+{
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(clazz!=NULL);
+ HPROF_ASSERT(field!=NULL);
+ CHECK_EXCEPTIONS(env) {
+ JNI_FUNC_PTR(env,SetStaticIntField)(env, clazz, field, value);
+ } END_CHECK_EXCEPTIONS;
+}
+
+static jobject
+callStaticObjectMethod(JNIEnv *env, jclass klass, jmethodID method)
+{
+ jobject x;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(klass!=NULL);
+ HPROF_ASSERT(method!=NULL);
+ CHECK_EXCEPTIONS(env) {
+ x = JNI_FUNC_PTR(env,CallStaticObjectMethod)(env, klass, method);
+ } END_CHECK_EXCEPTIONS;
+ return x;
+}
+
+static jlong
+callLongMethod(JNIEnv *env, jobject object, jmethodID method)
+{
+ jlong x;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(object!=NULL);
+ HPROF_ASSERT(method!=NULL);
+ CHECK_EXCEPTIONS(env) {
+ x = JNI_FUNC_PTR(env,CallLongMethod)(env, object, method);
+ } END_CHECK_EXCEPTIONS;
+ return x;
+}
+
+static void
+callVoidMethod(JNIEnv *env, jobject object, jmethodID method, jboolean arg)
+{
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(object!=NULL);
+ HPROF_ASSERT(method!=NULL);
+ CHECK_EXCEPTIONS(env) {
+ JNI_FUNC_PTR(env,CallVoidMethod)(env, object, method, arg);
+ } END_CHECK_EXCEPTIONS;
+}
+
+static jstring
+newStringUTF(JNIEnv *env, const char *name)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jstring string;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(name!=NULL);
+ CHECK_EXCEPTIONS(env) {
+ string = JNI_FUNC_PTR(env,NewStringUTF)(env, name);
+ } END_CHECK_EXCEPTIONS;
+ HPROF_ASSERT(string!=NULL);
+ return string;
+}
+
+static jobject
+newThreadObject(JNIEnv *env, jclass clazz, jmethodID method,
+ jthreadGroup group, jstring name)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jthread thread;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(clazz!=NULL);
+ HPROF_ASSERT(method!=NULL);
+ CHECK_EXCEPTIONS(env) {
+ thread = JNI_FUNC_PTR(env,NewObject)(env, clazz, method, group, name);
+ } END_CHECK_EXCEPTIONS;
+ HPROF_ASSERT(thread!=NULL);
+ return thread;
+}
+
+jboolean
+isSameObject(JNIEnv *env, jobject o1, jobject o2)
+{
+ HPROF_ASSERT(env!=NULL);
+ if ( o1 == o2 || JNI_FUNC_PTR(env,IsSameObject)(env, o1, o2) ) {
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+}
+
+void
+pushLocalFrame(JNIEnv *env, jint capacity)
+{
+ HPROF_ASSERT(env!=NULL);
+ CHECK_EXCEPTIONS(env) {
+ jint ret;
+
+ ret = JNI_FUNC_PTR(env,PushLocalFrame)(env, capacity);
+ if ( ret != 0 ) {
+ HPROF_ERROR(JNI_TRUE, "JNI PushLocalFrame returned non-zero");
+ }
+ } END_CHECK_EXCEPTIONS;
+}
+
+void
+popLocalFrame(JNIEnv *env, jobject result)
+{
+ jobject ret;
+
+ HPROF_ASSERT(env!=NULL);
+ ret = JNI_FUNC_PTR(env,PopLocalFrame)(env, result);
+ if ( (result != NULL && ret == NULL) || (result == NULL && ret != NULL) ) {
+ HPROF_ERROR(JNI_TRUE, "JNI PopLocalFrame returned wrong object");
+ }
+}
+
+void
+registerNatives(JNIEnv *env, jclass clazz,
+ JNINativeMethod *methods, jint count)
+{
+ jint ret;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(clazz!=NULL);
+ HPROF_ASSERT(methods!=NULL);
+ HPROF_ASSERT(count>0);
+ ret = JNI_FUNC_PTR(env,RegisterNatives)(env, clazz, methods, count);
+ if ( ret != 0 ) {
+ HPROF_ERROR(JNI_TRUE, "JNI RegisterNatives returned non-zero");
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+/* JVMTI Support Functions */
+
+char *
+getErrorName(jvmtiError error_number)
+{
+ char *error_name;
+
+ error_name = NULL;
+ (void)JVMTI_FUNC_PTR(gdata->jvmti,GetErrorName)
+ (gdata->jvmti, error_number, &error_name);
+ return error_name;
+}
+
+jvmtiPhase
+getPhase(void)
+{
+ jvmtiPhase phase;
+
+ phase = 0;
+ (void)JVMTI_FUNC_PTR(gdata->jvmti,GetPhase)(gdata->jvmti, &phase);
+ return phase;
+}
+
+char *
+phaseString(jvmtiPhase phase)
+{
+ switch ( phase ) {
+ case JVMTI_PHASE_ONLOAD:
+ return "onload";
+ case JVMTI_PHASE_PRIMORDIAL:
+ return "primordial";
+ case JVMTI_PHASE_START:
+ return "start";
+ case JVMTI_PHASE_LIVE:
+ return "live";
+ case JVMTI_PHASE_DEAD:
+ return "dead";
+ }
+ return "unknown";
+}
+
+void
+disposeEnvironment(void)
+{
+ (void)JVMTI_FUNC_PTR(gdata->jvmti,DisposeEnvironment)
+ (gdata->jvmti);
+}
+
+jlong
+getObjectSize(jobject object)
+{
+ jlong size;
+ jvmtiError error;
+
+ HPROF_ASSERT(object!=NULL);
+ size = 0;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetObjectSize)
+ (gdata->jvmti, object, &size);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get object size");
+ }
+ return size;
+}
+
+static jboolean
+isInterface(jclass klass)
+{
+ jvmtiError error;
+ jboolean answer;
+
+ HPROF_ASSERT(klass!=NULL);
+ answer = JNI_FALSE;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,IsInterface)
+ (gdata->jvmti, klass, &answer);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot call IsInterface");
+ }
+ return answer;
+}
+
+jint
+getClassStatus(jclass klass)
+{
+ jvmtiError error;
+ jint status;
+
+ HPROF_ASSERT(klass!=NULL);
+ status = 0;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassStatus)
+ (gdata->jvmti, klass, &status);
+ if ( error == JVMTI_ERROR_WRONG_PHASE ) {
+ /* Treat this as ok */
+ error = JVMTI_ERROR_NONE;
+ status = 0;
+ }
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get class status");
+ }
+ return status;
+}
+
+jobject
+getClassLoader(jclass klass)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jvmtiError error;
+ jobject loader;
+
+ HPROF_ASSERT(klass!=NULL);
+ loader = NULL;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassLoader)
+ (gdata->jvmti, klass, &loader);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get class loader");
+ }
+ return loader;
+}
+
+jlong
+getTag(jobject object)
+{
+ jlong tag;
+ jvmtiError error;
+
+ HPROF_ASSERT(object!=NULL);
+ tag = 0;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetTag)
+ (gdata->jvmti, object, &tag);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get object tag");
+ }
+ return tag;
+}
+
+void
+setTag(jobject object, jlong tag)
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(object!=NULL);
+ error = JVMTI_FUNC_PTR(gdata->jvmti,SetTag)
+ (gdata->jvmti, object, tag);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot set object tag");
+ }
+}
+
+void
+getObjectMonitorUsage(jobject object, jvmtiMonitorUsage *uinfo)
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(object!=NULL);
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetObjectMonitorUsage)
+ (gdata->jvmti, object, uinfo);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get monitor usage info");
+ }
+}
+
+void
+getOwnedMonitorInfo(jthread thread, jobject **ppobjects, jint *pcount)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(thread!=NULL);
+ HPROF_ASSERT(ppobjects!=NULL);
+ HPROF_ASSERT(pcount!=NULL);
+ *pcount = 0;
+ *ppobjects = NULL;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetOwnedMonitorInfo)
+ (gdata->jvmti, thread, pcount, ppobjects);
+ if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE ) {
+ *pcount = 0;
+ error = JVMTI_ERROR_NONE;
+ }
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get thread owned monitor info");
+ }
+}
+
+void
+getSystemProperty(const char *name, char **value)
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(name!=NULL);
+ *value = NULL;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetSystemProperty)
+ (gdata->jvmti, name, value);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get system property");
+ }
+}
+
+void
+getClassSignature(jclass klass, char** psignature, char **pgeneric_signature)
+{
+ jvmtiError error;
+ char *generic_signature;
+
+ HPROF_ASSERT(klass!=NULL);
+ *psignature = NULL;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassSignature)
+ (gdata->jvmti, klass, psignature, &generic_signature);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get class signature");
+ }
+ if ( pgeneric_signature != NULL ) {
+ *pgeneric_signature = generic_signature;
+ } else {
+ jvmtiDeallocate(generic_signature);
+ }
+}
+
+void
+getSourceFileName(jclass klass, char** pname)
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(klass!=NULL);
+ *pname = NULL;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetSourceFileName)
+ (gdata->jvmti, klass, pname);
+ if ( error == JVMTI_ERROR_ABSENT_INFORMATION ) {
+ error = JVMTI_ERROR_NONE;
+ *pname = NULL;
+ }
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get source file name");
+ }
+}
+
+static void
+getClassFields(jclass klass, jint* pn_fields, jfieldID** pfields)
+{
+ jvmtiError error;
+ jint status;
+
+ HPROF_ASSERT(klass!=NULL);
+ *pn_fields = 0;
+ *pfields = NULL;
+
+ /* Get class status */
+ status = getClassStatus(klass);
+
+ /* Arrays have no fields */
+ if ( status & JVMTI_CLASS_STATUS_ARRAY ) {
+ return;
+ }
+
+ /* Primitives have no fields */
+ if ( status & JVMTI_CLASS_STATUS_PRIMITIVE ) {
+ return;
+ }
+
+ /* If the class is not prepared, we have a problem? */
+ if ( !(status & JVMTI_CLASS_STATUS_PREPARED) ) {
+ HPROF_ERROR(JNI_FALSE, "Class not prepared when needing fields");
+ return;
+ }
+
+ /* Now try and get all the fields */
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassFields)
+ (gdata->jvmti, klass, pn_fields, pfields);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get class field list");
+ }
+}
+
+static jint
+getFieldModifiers(jclass klass, jfieldID field)
+{
+ jvmtiError error;
+ jint modifiers;
+
+ HPROF_ASSERT(klass!=NULL);
+ HPROF_ASSERT(field!=NULL);
+ modifiers = 0;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetFieldModifiers)
+ (gdata->jvmti, klass, field, &modifiers);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get field modifiers");
+ }
+ return modifiers;
+}
+
+static void
+getFieldName(jclass klass, jfieldID field, char** pname, char** psignature,
+ char **pgeneric_signature)
+{
+ jvmtiError error;
+ char *generic_signature;
+
+ generic_signature = NULL;
+ *pname = NULL;
+ *psignature = NULL;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetFieldName)
+ (gdata->jvmti, klass, field, pname, psignature, &generic_signature);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get field name");
+ }
+ if ( pgeneric_signature != NULL ) {
+ *pgeneric_signature = generic_signature;
+ } else {
+ jvmtiDeallocate(generic_signature);
+ }
+}
+
+static void
+getImplementedInterfaces(jclass klass, jint* pn_interfaces,
+ jclass** pinterfaces)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jvmtiError error;
+
+ *pn_interfaces = 0;
+ *pinterfaces = NULL;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetImplementedInterfaces)
+ (gdata->jvmti, klass, pn_interfaces, pinterfaces);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get class interface list");
+ }
+}
+
+static ClassIndex
+get_cnum(JNIEnv *env, jclass klass)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ ClassIndex cnum;
+ LoaderIndex loader_index;
+ char *sig;
+ jobject loader;
+
+ loader = getClassLoader(klass);
+ loader_index = loader_find_or_create(env, loader);
+ getClassSignature(klass, &sig, NULL);
+ cnum = class_find_or_create(sig, loader_index);
+ jvmtiDeallocate(sig);
+ (void)class_new_classref(env, cnum, klass);
+ return cnum;
+}
+
+/* From primitive type, get signature letter */
+char
+primTypeToSigChar(jvmtiPrimitiveType primType)
+{
+ char sig_ch;
+
+ sig_ch = 0;
+ switch ( primType ) {
+ case JVMTI_PRIMITIVE_TYPE_BYTE:
+ sig_ch = JVM_SIGNATURE_BYTE;
+ break;
+ case JVMTI_PRIMITIVE_TYPE_CHAR:
+ sig_ch = JVM_SIGNATURE_CHAR;
+ break;
+ case JVMTI_PRIMITIVE_TYPE_FLOAT:
+ sig_ch = JVM_SIGNATURE_FLOAT;
+ break;
+ case JVMTI_PRIMITIVE_TYPE_DOUBLE:
+ sig_ch = JVM_SIGNATURE_DOUBLE;
+ break;
+ case JVMTI_PRIMITIVE_TYPE_INT:
+ sig_ch = JVM_SIGNATURE_INT;
+ break;
+ case JVMTI_PRIMITIVE_TYPE_LONG:
+ sig_ch = JVM_SIGNATURE_LONG;
+ break;
+ case JVMTI_PRIMITIVE_TYPE_SHORT:
+ sig_ch = JVM_SIGNATURE_SHORT;
+ break;
+ case JVMTI_PRIMITIVE_TYPE_BOOLEAN:
+ sig_ch = JVM_SIGNATURE_BOOLEAN;
+ break;
+ default:
+ sig_ch = 0;
+ break;
+ }
+ return sig_ch;
+}
+
+/* From signature, get primitive type */
+jvmtiPrimitiveType
+sigToPrimType(char *sig)
+{
+ jvmtiPrimitiveType primType;
+
+ primType = 0;
+ if ( sig == NULL || sig[0] == 0 ) {
+ return primType;
+ }
+ switch ( sig[0] ) {
+ case JVM_SIGNATURE_BYTE:
+ primType = JVMTI_PRIMITIVE_TYPE_BYTE;
+ break;
+ case JVM_SIGNATURE_CHAR:
+ primType = JVMTI_PRIMITIVE_TYPE_CHAR;
+ break;
+ case JVM_SIGNATURE_FLOAT:
+ primType = JVMTI_PRIMITIVE_TYPE_FLOAT;
+ break;
+ case JVM_SIGNATURE_DOUBLE:
+ primType = JVMTI_PRIMITIVE_TYPE_DOUBLE;
+ break;
+ case JVM_SIGNATURE_INT:
+ primType = JVMTI_PRIMITIVE_TYPE_INT;
+ break;
+ case JVM_SIGNATURE_LONG:
+ primType = JVMTI_PRIMITIVE_TYPE_LONG;
+ break;
+ case JVM_SIGNATURE_SHORT:
+ primType = JVMTI_PRIMITIVE_TYPE_SHORT;
+ break;
+ case JVM_SIGNATURE_BOOLEAN:
+ primType = JVMTI_PRIMITIVE_TYPE_BOOLEAN;
+ break;
+ }
+ return primType;
+}
+
+/* From signature, get primitive size */
+int
+sigToPrimSize(char *sig)
+{
+ unsigned size;
+
+ size = 0;
+ if ( sig == NULL || sig[0] == 0 ) {
+ return size;
+ }
+ switch ( sig[0] ) {
+ case JVM_SIGNATURE_BYTE:
+ case JVM_SIGNATURE_BOOLEAN:
+ size = 1;
+ break;
+ case JVM_SIGNATURE_CHAR:
+ case JVM_SIGNATURE_SHORT:
+ size = 2;
+ break;
+ case JVM_SIGNATURE_FLOAT:
+ case JVM_SIGNATURE_INT:
+ size = 4;
+ break;
+ case JVM_SIGNATURE_DOUBLE:
+ case JVM_SIGNATURE_LONG:
+ size = 8;
+ break;
+ }
+ return size;
+}
+
+static void
+add_class_fields(JNIEnv *env, ClassIndex top_cnum, ClassIndex cnum,
+ jclass klass, Stack *field_list, Stack *class_list)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jclass *interfaces;
+ jint n_interfaces;
+ jfieldID *idlist;
+ jint n_fields;
+ int i;
+ int depth;
+ int skip_static_field_names;
+ jint status;
+
+ HPROF_ASSERT(env!=NULL);
+ HPROF_ASSERT(klass!=NULL);
+ HPROF_ASSERT(field_list!=NULL);
+ HPROF_ASSERT(class_list!=NULL);
+
+ /* If not the initial class, we can skip the static fields (perf issue) */
+ skip_static_field_names = (cnum != top_cnum);
+
+ /* Get class status */
+ status = getClassStatus(klass);
+
+ /* Arrays have no fields */
+ if ( status & JVMTI_CLASS_STATUS_ARRAY ) {
+ return;
+ }
+
+ /* Primitives have no fields */
+ if ( status & JVMTI_CLASS_STATUS_PRIMITIVE ) {
+ return;
+ }
+
+ /* If the class is not prepared, we have a problem? */
+ if ( !(status & JVMTI_CLASS_STATUS_PREPARED) ) {
+ char *sig;
+
+ getClassSignature(klass, &sig, NULL);
+ debug_message("Class signature is: %s\n", sig);
+ HPROF_ERROR(JNI_FALSE, "Class not prepared when needing all fields");
+ jvmtiDeallocate(sig);
+ return;
+ }
+
+ /* See if class already processed */
+ depth = stack_depth(class_list);
+ for ( i = depth-1 ; i >= 0 ; i-- ) {
+ if ( isSameObject(env, klass, *(jclass*)stack_element(class_list, i)) ) {
+ return;
+ }
+ }
+
+ /* Class or Interface, do implemented interfaces recursively */
+ getImplementedInterfaces(klass, &n_interfaces, &interfaces);
+ for ( i = 0 ; i < n_interfaces ; i++ ) {
+ add_class_fields(env, top_cnum,
+ get_cnum(env, interfaces[i]), interfaces[i],
+ field_list, class_list);
+ }
+ jvmtiDeallocate(interfaces);
+
+ /* Begin graph traversal, go up super chain recursively */
+ if ( !isInterface(klass) ) {
+ jclass super_klass;
+
+ super_klass = getSuperclass(env, klass);
+ if ( super_klass != NULL ) {
+ add_class_fields(env, top_cnum,
+ get_cnum(env, super_klass), super_klass,
+ field_list, class_list);
+ }
+ }
+
+
+ /* Only now we add klass to list so we don't repeat it later */
+ stack_push(class_list, &klass);
+
+ /* Now actually add the fields for this klass */
+ getClassFields(klass, &n_fields, &idlist);
+ for ( i = 0 ; i < n_fields ; i++ ) {
+ FieldInfo finfo;
+ static FieldInfo empty_finfo;
+
+ finfo = empty_finfo;
+ finfo.cnum = cnum;
+ finfo.modifiers = (unsigned short)getFieldModifiers(klass, idlist[i]);
+ if ( ( finfo.modifiers & JVM_ACC_STATIC ) == 0 ||
+ !skip_static_field_names ) {
+ char *field_name;
+ char *field_sig;
+
+ getFieldName(klass, idlist[i], &field_name, &field_sig, NULL);
+ finfo.name_index = string_find_or_create(field_name);
+ finfo.sig_index = string_find_or_create(field_sig);
+ finfo.primType = sigToPrimType(field_sig);
+ finfo.primSize = sigToPrimSize(field_sig);
+ jvmtiDeallocate(field_name);
+ jvmtiDeallocate(field_sig);
+ }
+ stack_push(field_list, &finfo);
+ }
+ jvmtiDeallocate(idlist);
+}
+
+void
+getAllClassFieldInfo(JNIEnv *env, jclass klass,
+ jint* pn_fields, FieldInfo** pfields)
+{
+ ClassIndex cnum;
+
+ *pfields = NULL;
+ *pn_fields = 0;
+
+ WITH_LOCAL_REFS(env, 1) {
+ Stack *class_list;
+ Stack *field_list;
+ int nbytes;
+
+ cnum = get_cnum(env, klass);
+ class_list = stack_init( 16, 16, (int)sizeof(jclass));
+ field_list = stack_init(128, 128, (int)sizeof(FieldInfo));
+ add_class_fields(env, cnum, cnum, klass, field_list, class_list);
+ *pn_fields = stack_depth(field_list);
+ if ( (*pn_fields) > 0 ) {
+ nbytes = (*pn_fields) * (int)sizeof(FieldInfo);
+ *pfields = (FieldInfo*)HPROF_MALLOC(nbytes);
+ (void)memcpy(*pfields, stack_element(field_list, 0), nbytes);
+ }
+ stack_term(field_list);
+ stack_term(class_list);
+ } END_WITH_LOCAL_REFS;
+}
+
+void
+getMethodClass(jmethodID method, jclass *pclazz)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(method!=NULL);
+ *pclazz = NULL;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass)
+ (gdata->jvmti, method, pclazz);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get method class");
+ }
+}
+
+jboolean
+isMethodNative(jmethodID method)
+{
+ jvmtiError error;
+ jboolean isNative;
+
+ HPROF_ASSERT(method!=NULL);
+ error = JVMTI_FUNC_PTR(gdata->jvmti,IsMethodNative)
+ (gdata->jvmti, method, &isNative);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot check is method native");
+ }
+ return isNative;
+}
+
+void
+getMethodName(jmethodID method, char** pname, char** psignature)
+{
+ jvmtiError error;
+ char *generic_signature;
+
+ HPROF_ASSERT(method!=NULL);
+ generic_signature = NULL;
+ *pname = NULL;
+ *psignature = NULL;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName)
+ (gdata->jvmti, method, pname, psignature, &generic_signature);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get method name");
+ }
+ jvmtiDeallocate(generic_signature);
+}
+
+void
+getPotentialCapabilities(jvmtiCapabilities *pcapabilities)
+{
+ jvmtiError error;
+
+ (void)memset(pcapabilities,0,sizeof(jvmtiCapabilities));
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetPotentialCapabilities)
+ (gdata->jvmti, pcapabilities);
+ if (error != JVMTI_ERROR_NONE) {
+ HPROF_ERROR(JNI_FALSE, "Unable to get potential JVMTI capabilities.");
+ error_exit_process(1); /* Kill entire process, no core dump wanted */
+ }
+}
+
+void
+addCapabilities(jvmtiCapabilities *pcapabilities)
+{
+ jvmtiError error;
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,AddCapabilities)
+ (gdata->jvmti, pcapabilities);
+ if (error != JVMTI_ERROR_NONE) {
+ HPROF_ERROR(JNI_FALSE, "Unable to get necessary JVMTI capabilities.");
+ error_exit_process(1); /* Kill entire process, no core dump wanted */
+ }
+}
+
+void
+setEventCallbacks(jvmtiEventCallbacks *pcallbacks)
+{
+ jvmtiError error;
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventCallbacks)
+ (gdata->jvmti, pcallbacks, (int)sizeof(jvmtiEventCallbacks));
+ if (error != JVMTI_ERROR_NONE) {
+ HPROF_JVMTI_ERROR(error, "Cannot set jvmti callbacks");
+ }
+
+}
+
+void *
+getThreadLocalStorage(jthread thread)
+{
+ jvmtiError error;
+ void *ptr;
+
+ HPROF_ASSERT(thread!=NULL);
+ ptr = NULL;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadLocalStorage)
+ (gdata->jvmti, thread, &ptr);
+ if ( error == JVMTI_ERROR_WRONG_PHASE ) {
+ /* Treat this as ok */
+ error = JVMTI_ERROR_NONE;
+ ptr = NULL;
+ }
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get thread local storage");
+ }
+ return ptr;
+}
+
+void
+setThreadLocalStorage(jthread thread, void *ptr)
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(thread!=NULL);
+ error = JVMTI_FUNC_PTR(gdata->jvmti,SetThreadLocalStorage)
+ (gdata->jvmti, thread, (const void *)ptr);
+ if ( error == JVMTI_ERROR_WRONG_PHASE ) {
+ /* Treat this as ok */
+ error = JVMTI_ERROR_NONE;
+ }
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot set thread local storage");
+ }
+}
+
+void
+getThreadState(jthread thread, jint *threadState)
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(thread!=NULL);
+ HPROF_ASSERT(threadState!=NULL);
+ *threadState = 0;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState)
+ (gdata->jvmti, thread, threadState);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get thread state");
+ }
+}
+
+void
+getThreadInfo(jthread thread, jvmtiThreadInfo *info)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(thread!=NULL);
+ HPROF_ASSERT(info!=NULL);
+ (void)memset((void*)info, 0, sizeof(jvmtiThreadInfo));
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo)
+ (gdata->jvmti, thread, info);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get thread info");
+ }
+}
+
+void
+getThreadGroupInfo(jthreadGroup thread_group, jvmtiThreadGroupInfo *info)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(info!=NULL);
+ (void)memset((void*)info, 0, sizeof(jvmtiThreadGroupInfo));
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadGroupInfo)
+ (gdata->jvmti, thread_group, info);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get thread group info");
+ }
+}
+
+void
+getLoadedClasses(jclass **ppclasses, jint *pcount)
+/* WARNING: Must be called inside WITH_LOCAL_REFS */
+{
+ jvmtiError error;
+
+ *ppclasses = NULL;
+ *pcount = 0;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetLoadedClasses)
+ (gdata->jvmti, pcount, ppclasses);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get all loaded class list");
+ }
+}
+
+static void
+getLineNumberTable(jmethodID method, jvmtiLineNumberEntry **ppentries,
+ jint *pcount)
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(method!=NULL);
+ *ppentries = NULL;
+ *pcount = 0;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetLineNumberTable)
+ (gdata->jvmti, method, pcount, ppentries);
+ if ( error == JVMTI_ERROR_ABSENT_INFORMATION ) {
+ error = JVMTI_ERROR_NONE;
+ *ppentries = NULL;
+ *pcount = 0;
+ }
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get source line numbers");
+ }
+}
+
+static jint
+map_loc2line(jlocation location, jvmtiLineNumberEntry *table, jint count)
+{
+ jint line_number;
+ int i;
+ int start;
+ int half;
+
+ HPROF_ASSERT(location>=0);
+ HPROF_ASSERT(count>=0);
+
+ line_number = -1;
+ if ( count == 0 ) {
+ return line_number;
+ }
+
+ /* Do a binary search */
+ half = count >> 1;
+ start = 0;
+ while ( half > 0 ) {
+ jlocation start_location;
+
+ start_location = table[start + half].start_location;
+ if ( location > start_location ) {
+ start = start + half;
+ } else if ( location == start_location ) {
+ start = start + half;
+ break;
+ }
+ half = half >> 1;
+ }
+
+ HPROF_ASSERT(start < count);
+
+ /* Now start the table search */
+ for ( i = start ; i < count ; i++ ) {
+ if ( location < table[i].start_location ) {
+ HPROF_ASSERT( ((int)location) < ((int)table[i].start_location) );
+ break;
+ }
+ line_number = table[i].line_number;
+ }
+ HPROF_ASSERT(line_number > 0);
+ return line_number;
+}
+
+jint
+getLineNumber(jmethodID method, jlocation location)
+{
+ jvmtiLineNumberEntry *line_table;
+ jint line_count;
+ jint lineno;
+
+ HPROF_ASSERT(method!=NULL);
+ if ( location < 0 ) {
+ HPROF_ASSERT(location > -4);
+ return (jint)location;
+ }
+ lineno = -1;
+
+ getLineNumberTable(method, &line_table, &line_count);
+ lineno = map_loc2line(location, line_table, line_count);
+ jvmtiDeallocate(line_table);
+
+ return lineno;
+}
+
+jlong
+getMaxMemory(JNIEnv *env)
+{
+ jlong max;
+
+ HPROF_ASSERT(env!=NULL);
+
+ max = (jlong)0;
+ WITH_LOCAL_REFS(env, 1) {
+ jclass clazz;
+ jmethodID getRuntime;
+ jobject runtime;
+ jmethodID maxMemory;
+
+ clazz = findClass(env, "java/lang/Runtime");
+ getRuntime = getStaticMethodID(env, clazz, "getRuntime",
+ "()Ljava/lang/Runtime;");
+ runtime = callStaticObjectMethod(env, clazz, getRuntime);
+ maxMemory = getMethodID(env, clazz, "maxMemory", "()J");
+ max = callLongMethod(env, runtime, maxMemory);
+ } END_WITH_LOCAL_REFS;
+ return max;
+}
+
+void
+createAgentThread(JNIEnv *env, const char *name, jvmtiStartFunction func)
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(name!=NULL);
+ HPROF_ASSERT(func!=NULL);
+
+ WITH_LOCAL_REFS(env, 1) {
+ jclass clazz;
+ jmethodID threadConstructor;
+ jmethodID threadSetDaemon;
+ jthread thread;
+ jstring nameString;
+ jthreadGroup systemThreadGroup;
+ jthreadGroup * groups;
+ jint groupCount;
+
+ thread = NULL;
+ systemThreadGroup = NULL;
+ groups = NULL;
+ clazz = class_get_class(env, gdata->thread_cnum);
+ HPROF_ASSERT(clazz!=NULL);
+ threadConstructor = getMethodID(env, clazz, "<init>",
+ "(Ljava/lang/ThreadGroup;Ljava/lang/String;)V");
+ threadSetDaemon = getMethodID(env, clazz, "setDaemon",
+ "(Z)V");
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetTopThreadGroups)
+ (gdata->jvmti, &groupCount, &groups);
+ if ( error == JVMTI_ERROR_NONE ) {
+ if ( groupCount > 0 ) {
+ systemThreadGroup = groups[0];
+ }
+ jvmtiDeallocate(groups);
+
+ nameString = newStringUTF(env, name);
+ HPROF_ASSERT(nameString!=NULL);
+ thread = newThreadObject(env, clazz, threadConstructor,
+ systemThreadGroup, nameString);
+ HPROF_ASSERT(thread!=NULL);
+ callVoidMethod(env, thread, threadSetDaemon, JNI_TRUE);
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,RunAgentThread)
+ (gdata->jvmti, thread, func, NULL, JVMTI_THREAD_MAX_PRIORITY);
+
+ /* After the thread is running... */
+
+ /* Make sure the TLS table has this thread as an agent thread */
+ tls_agent_thread(env, thread);
+ }
+ } END_WITH_LOCAL_REFS;
+
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot create agent thread");
+ }
+}
+
+jlong
+getThreadCpuTime(jthread thread)
+{
+ jvmtiError error;
+ jlong cpuTime;
+
+ HPROF_ASSERT(thread!=NULL);
+ cpuTime = -1;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadCpuTime)
+ (gdata->jvmti, thread, &cpuTime);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get cpu time");
+ }
+ return cpuTime;
+}
+
+/* Get frame count */
+void
+getFrameCount(jthread thread, jint *pcount)
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(thread!=NULL);
+ HPROF_ASSERT(pcount!=NULL);
+ *pcount = 0;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount)
+ (gdata->jvmti, thread, pcount);
+ if ( error != JVMTI_ERROR_NONE ) {
+ *pcount = 0;
+ }
+}
+
+/* Get call trace */
+void
+getStackTrace(jthread thread, jvmtiFrameInfo *pframes, jint depth, jint *pcount)
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(thread!=NULL);
+ HPROF_ASSERT(pframes!=NULL);
+ HPROF_ASSERT(depth >= 0);
+ HPROF_ASSERT(pcount!=NULL);
+ *pcount = 0;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetStackTrace)
+ (gdata->jvmti, thread, 0, depth, pframes, pcount);
+ if ( error != JVMTI_ERROR_NONE ) {
+ *pcount = 0;
+ }
+}
+
+void
+getThreadListStackTraces(jint count, jthread *threads,
+ jint depth, jvmtiStackInfo **stack_info)
+{
+ jvmtiError error;
+
+ HPROF_ASSERT(threads!=NULL);
+ HPROF_ASSERT(stack_info!=NULL);
+ HPROF_ASSERT(depth >= 0);
+ HPROF_ASSERT(count > 0);
+ *stack_info = NULL;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadListStackTraces)
+ (gdata->jvmti, count, threads, depth, stack_info);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot get thread list stack info");
+ }
+}
+
+void
+followReferences(jvmtiHeapCallbacks *pHeapCallbacks, void *user_data)
+{
+ jvmtiError error;
+
+ error = JVMTI_FUNC_PTR(gdata->jvmti,FollowReferences)
+ (gdata->jvmti, 0, NULL, NULL, pHeapCallbacks, user_data);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot follow references");
+ }
+}
+
+/* GC control */
+void
+runGC(void)
+{
+ jvmtiError error;
+ error = JVMTI_FUNC_PTR(gdata->jvmti,ForceGarbageCollection)
+ (gdata->jvmti);
+ if ( error != JVMTI_ERROR_NONE ) {
+ HPROF_JVMTI_ERROR(error, "Cannot force garbage collection");
+ }
+}
+
+/* ------------------------------------------------------------------- */
+/* Getting the initial JVMTI environment */
+
+void
+getJvmti(void)
+{
+ jvmtiEnv *jvmti = NULL;
+ jint res;
+ jint jvmtiCompileTimeMajorVersion;
+ jint jvmtiCompileTimeMinorVersion;
+ jint jvmtiCompileTimeMicroVersion;
+
+ res = JVM_FUNC_PTR(gdata->jvm,GetEnv)
+ (gdata->jvm, (void **)&jvmti, JVMTI_VERSION_1);
+ if (res != JNI_OK) {
+ char buf[256];
+
+ (void)md_snprintf(buf, sizeof(buf),
+ "Unable to access JVMTI Version 1 (0x%x),"
+ " is your JDK a 5.0 or newer version?"
+ " JNIEnv's GetEnv() returned %d",
+ JVMTI_VERSION_1, res);
+ buf[sizeof(buf)-1] = 0;
+ HPROF_ERROR(JNI_FALSE, buf);
+ error_exit_process(1); /* Kill entire process, no core dump */
+ }
+ gdata->jvmti = jvmti;
+
+ /* Check to make sure the version of jvmti.h we compiled with
+ * matches the runtime version we are using.
+ */
+ jvmtiCompileTimeMajorVersion = ( JVMTI_VERSION & JVMTI_VERSION_MASK_MAJOR )
+ >> JVMTI_VERSION_SHIFT_MAJOR;
+ jvmtiCompileTimeMinorVersion = ( JVMTI_VERSION & JVMTI_VERSION_MASK_MINOR )
+ >> JVMTI_VERSION_SHIFT_MINOR;
+ jvmtiCompileTimeMicroVersion = ( JVMTI_VERSION & JVMTI_VERSION_MASK_MICRO )
+ >> JVMTI_VERSION_SHIFT_MICRO;
+ if ( !compatible_versions(jvmtiMajorVersion(), jvmtiMinorVersion(),
+ jvmtiCompileTimeMajorVersion, jvmtiCompileTimeMinorVersion) ) {
+ char buf[256];
+
+ (void)md_snprintf(buf, sizeof(buf),
+ "This " AGENTNAME " native library will not work with this VM's "
+ "version of JVMTI (%d.%d.%d), it needs JVMTI %d.%d[.%d]."
+ ,
+ jvmtiMajorVersion(),
+ jvmtiMinorVersion(),
+ jvmtiMicroVersion(),
+ jvmtiCompileTimeMajorVersion,
+ jvmtiCompileTimeMinorVersion,
+ jvmtiCompileTimeMicroVersion);
+ buf[sizeof(buf)-1] = 0;
+ HPROF_ERROR(JNI_FALSE, buf);
+ error_exit_process(1); /* Kill entire process, no core dump wanted */
+ }
+}