blob: 2948483b0f59135a74b970d02175b6f7967aace7 [file] [log] [blame]
/*
* Copyright (c) 2003, 2008, 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.
*/
/* 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 */
}
}