X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=libjava%2Fjvmti.cc;h=3ac6365b2cc1d3bf245881d22de70ddeb8ae5936;hp=b9646b7d1018e3165642afd5bfa484a3a39923e7;hb=3c267741be087581d72f7d61404b4c8c1b7de738;hpb=34b0e09cd2ed4f463f7168b8ca0fb8f15443d455 diff --git a/libjava/jvmti.cc b/libjava/jvmti.cc index b9646b7d101..3ac6365b2cc 100644 --- a/libjava/jvmti.cc +++ b/libjava/jvmti.cc @@ -1,6 +1,6 @@ // jvmti.cc - JVMTI implementation -/* Copyright (C) 2006 Free Software Foundation +/* Copyright (C) 2006, 2007 Free Software Foundation This file is part of libgcj. @@ -27,16 +27,18 @@ details. */ #include #include -#include #include #include #include +#include #include #include #include #include #include #include +#include +#include #include static void check_enabled_events (void); @@ -44,6 +46,10 @@ static void check_enabled_event (jvmtiEvent); namespace JVMTI { + // Is JVMTI enabled? (i.e., any jvmtiEnv created?) + bool enabled; + + // Event notifications bool VMInit = false; bool VMDeath = false; bool ThreadStart = false; @@ -99,7 +105,8 @@ struct jvmti_env_list struct jvmti_env_list *next; }; static struct jvmti_env_list *_jvmtiEnvironments = NULL; -static java::lang::Object *_envListLock = NULL; +static java::util::concurrent::locks:: +ReentrantReadWriteLock *_envListLock = NULL; #define FOREACH_ENVIRONMENT(Ele) \ for (Ele = _jvmtiEnvironments; Ele != NULL; Ele = Ele->next) @@ -149,18 +156,28 @@ static java::lang::Object *_envListLock = NULL; } \ while (0) +#define CHECK_FOR_NATIVE_METHOD(AjmethodID) \ + do \ + { \ + jboolean is_native; \ + jvmtiError jerr = env->IsMethodNative (AjmethodID, &is_native); \ + if (jerr != JVMTI_ERROR_NONE) \ + return jerr; \ + if (is_native) \ + return JVMTI_ERROR_NATIVE_METHOD; \ + } \ + while (0) + static jvmtiError JNICALL _Jv_JVMTI_SuspendThread (MAYBE_UNUSED jvmtiEnv *env, jthread thread) { using namespace java::lang; THREAD_DEFAULT_TO_CURRENT (thread); - - Thread *t = reinterpret_cast (thread); - THREAD_CHECK_VALID (t); - THREAD_CHECK_IS_ALIVE (t); + THREAD_CHECK_VALID (thread); + THREAD_CHECK_IS_ALIVE (thread); - _Jv_Thread_t *data = _Jv_ThreadGetData (t); + _Jv_Thread_t *data = _Jv_ThreadGetData (thread); _Jv_SuspendThread (data); return JVMTI_ERROR_NONE; } @@ -171,12 +188,10 @@ _Jv_JVMTI_ResumeThread (MAYBE_UNUSED jvmtiEnv *env, jthread thread) using namespace java::lang; THREAD_DEFAULT_TO_CURRENT (thread); + THREAD_CHECK_VALID (thread); + THREAD_CHECK_IS_ALIVE (thread); - Thread *t = reinterpret_cast (thread); - THREAD_CHECK_VALID (t); - THREAD_CHECK_IS_ALIVE (t); - - _Jv_Thread_t *data = _Jv_ThreadGetData (t); + _Jv_Thread_t *data = _Jv_ThreadGetData (thread); _Jv_ResumeThread (data); return JVMTI_ERROR_NONE; } @@ -191,14 +206,260 @@ _Jv_JVMTI_InterruptThread (MAYBE_UNUSED jvmtiEnv *env, jthread thread) if (thread == NULL) return JVMTI_ERROR_INVALID_THREAD; - Thread *real_thread = reinterpret_cast (thread); - THREAD_CHECK_VALID (real_thread); - THREAD_CHECK_IS_ALIVE (real_thread); - real_thread->interrupt(); + THREAD_CHECK_VALID (thread); + THREAD_CHECK_IS_ALIVE (thread); + thread->interrupt(); + return JVMTI_ERROR_NONE; +} + +// This method performs the common tasks to get and set variables of all types. +// It is called by the _Jv_JVMTI_Get/SetLocalInt/Object/.... methods. +static jvmtiError +getLocalFrame (jvmtiEnv *env, jthread thread, jint depth, jint slot, char type, + _Jv_InterpFrame **iframe) +{ + using namespace java::lang; + + REQUIRE_PHASE (env, JVMTI_PHASE_LIVE); + + ILLEGAL_ARGUMENT (depth < 0); + + THREAD_DEFAULT_TO_CURRENT (thread); + THREAD_CHECK_VALID (thread); + THREAD_CHECK_IS_ALIVE (thread); + + _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame); + + for (int i = 0; i < depth; i++) + { + frame = frame->next; + + if (frame == NULL) + return JVMTI_ERROR_NO_MORE_FRAMES; + } + + if (frame->frame_type == frame_native) + return JVMTI_ERROR_OPAQUE_FRAME; + + jint max_locals; + jvmtiError jerr = env->GetMaxLocals (reinterpret_cast + (frame->self->get_method ()), + &max_locals); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + _Jv_InterpFrame *tmp_iframe = reinterpret_cast<_Jv_InterpFrame *> (frame); + + // The second slot taken up by a long type is marked as type 'x' meaning it + // is not valid for access since it holds only the 4 low bytes of the value. + if (tmp_iframe->locals_type[slot] == 'x') + return JVMTI_ERROR_INVALID_SLOT; + + if (tmp_iframe->locals_type[slot] != type) + return JVMTI_ERROR_TYPE_MISMATCH; + + // Check for invalid slots, if the type is a long type, we must check that + // the next slot is valid as well. + if (slot < 0 || slot >= max_locals + || ((type == 'l' || type == 'd') && slot + 1 >= max_locals)) + return JVMTI_ERROR_INVALID_SLOT; + + *iframe = tmp_iframe; + return JVMTI_ERROR_NONE; } -jvmtiError +static jvmtiError JNICALL +_Jv_JVMTI_GetLocalObject (jvmtiEnv *env, jthread thread, jint depth, jint slot, + jobject *value) +{ + NULL_CHECK (value); + + _Jv_InterpFrame *frame; + jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'o', &frame); + + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + *value = frame->locals[slot].o; + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL +_Jv_JVMTI_SetLocalObject (jvmtiEnv *env, jthread thread, jint depth, jint slot, + jobject value) +{ + _Jv_InterpFrame *frame; + jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'o', &frame); + + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + frame->locals[slot].o = value; + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL +_Jv_JVMTI_GetLocalInt (jvmtiEnv *env, jthread thread, jint depth, jint slot, + jint *value) +{ + NULL_CHECK (value); + + _Jv_InterpFrame *frame; + jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'i', &frame); + + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + *value = frame->locals[slot].i; + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL +_Jv_JVMTI_SetLocalInt (jvmtiEnv *env, jthread thread, jint depth, jint slot, + jint value) +{ + _Jv_InterpFrame *frame; + jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'i', &frame); + + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + frame->locals[slot].i = value; + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL +_Jv_JVMTI_GetLocalLong (jvmtiEnv *env, jthread thread, jint depth, jint slot, + jlong *value) +{ + NULL_CHECK (value); + + _Jv_InterpFrame *frame; + jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'l', &frame); + + if (jerr != JVMTI_ERROR_NONE) + return jerr; + +#if SIZEOF_VOID_P==8 + *value = frame->locals[slot].l; +#else + _Jv_word2 val; + val.ia[0] = frame->locals[slot].ia[0]; + val.ia[1] = frame->locals[slot + 1].ia[0]; + *value = val.l; +#endif + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL +_Jv_JVMTI_SetLocalLong (jvmtiEnv *env, jthread thread, jint depth, jint slot, + jlong value) +{ + _Jv_InterpFrame *frame; + jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'l', &frame); + + if (jerr != JVMTI_ERROR_NONE) + return jerr; + +#if SIZEOF_VOID_P==8 + frame->locals[slot].l = value; +#else + _Jv_word2 val; + val.l = value; + frame->locals[slot].ia[0] = val.ia[0]; + frame->locals[slot + 1].ia[0] = val.ia[1]; +#endif + + return JVMTI_ERROR_NONE; +} + + +static jvmtiError JNICALL +_Jv_JVMTI_GetLocalFloat (jvmtiEnv *env, jthread thread, jint depth, jint slot, + jfloat *value) +{ + NULL_CHECK (value); + + _Jv_InterpFrame *frame; + jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'f', &frame); + + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + *value = frame->locals[slot].f; + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL +_Jv_JVMTI_SetLocalFloat (jvmtiEnv *env, jthread thread, jint depth, jint slot, + jfloat value) +{ + _Jv_InterpFrame *frame; + jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'f', &frame); + + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + frame->locals[slot].f = value; + + return JVMTI_ERROR_NONE; +} + + +static jvmtiError JNICALL +_Jv_JVMTI_GetLocalDouble (jvmtiEnv *env, jthread thread, jint depth, jint slot, + jdouble *value) +{ + NULL_CHECK (value); + + _Jv_InterpFrame *frame; + jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'd', &frame); + + if (jerr != JVMTI_ERROR_NONE) + return jerr; + +#if SIZEOF_VOID_P==8 + *value = frame->locals[slot].d; +#else + _Jv_word2 val; + val.ia[0] = frame->locals[slot].ia[0]; + val.ia[1] = frame->locals[slot + 1].ia[0]; + *value = val.d; +#endif + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL +_Jv_JVMTI_SetLocalDouble (jvmtiEnv *env, jthread thread, jint depth, jint slot, + jdouble value) +{ + _Jv_InterpFrame *frame; + jvmtiError jerr = getLocalFrame (env, thread, depth, slot, 'd', &frame); + + if (jerr != JVMTI_ERROR_NONE) + return jerr; + +#if SIZEOF_VOID_P==8 + frame->locals[slot].d = value; +#else + _Jv_word2 val; + val.d = value; + frame->locals[slot].ia[0] = val.ia[0]; + frame->locals[slot + 1].ia[0] = val.ia[1]; +#endif + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL _Jv_JVMTI_GetAllThreads(MAYBE_UNUSED jvmtiEnv *env, jint *thread_cnt, jthread **threads) { @@ -207,7 +468,6 @@ _Jv_JVMTI_GetAllThreads(MAYBE_UNUSED jvmtiEnv *env, jint *thread_cnt, NULL_CHECK (threads); using namespace java::lang; - Thread *thr = Thread::currentThread (); ThreadGroup *root_grp = ThreadGroup::root; jint estimate = root_grp->activeCount (); @@ -217,10 +477,9 @@ _Jv_JVMTI_GetAllThreads(MAYBE_UNUSED jvmtiEnv *env, jint *thread_cnt, // Allocate some extra space since threads can be created between calls try { - thr_arr - = reinterpret_cast *> (JvNewObjectArray - ((estimate * 2), - &Thread::class$, NULL)); + thr_arr = reinterpret_cast *> (JvNewObjectArray + ((estimate * 2), + &Thread::class$, NULL)); } catch (java::lang::OutOfMemoryError *err) { @@ -244,6 +503,85 @@ _Jv_JVMTI_GetAllThreads(MAYBE_UNUSED jvmtiEnv *env, jint *thread_cnt, } static jvmtiError JNICALL +_Jv_JVMTI_GetFrameCount (MAYBE_UNUSED jvmtiEnv *env, jthread thread, + jint *frame_count) +{ + REQUIRE_PHASE (env, JVMTI_PHASE_LIVE); + + NULL_CHECK (frame_count); + + using namespace java::lang; + + THREAD_DEFAULT_TO_CURRENT (thread); + THREAD_CHECK_VALID (thread); + THREAD_CHECK_IS_ALIVE (thread); + + _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame); + (*frame_count) = frame->depth (); + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL +_Jv_JVMTI_GetThreadState (MAYBE_UNUSED jvmtiEnv *env, jthread thread, + jint *thread_state_ptr) +{ + REQUIRE_PHASE (env, JVMTI_PHASE_LIVE); + + THREAD_DEFAULT_TO_CURRENT (thread); + THREAD_CHECK_VALID (thread); + NULL_CHECK (thread_state_ptr); + + jint state = 0; + if (thread->isAlive ()) + { + state |= JVMTI_THREAD_STATE_ALIVE; + + _Jv_Thread_t *data = _Jv_ThreadGetData (thread); + if (_Jv_IsThreadSuspended (data)) + state |= JVMTI_THREAD_STATE_SUSPENDED; + + if (thread->isInterrupted ()) + state |= JVMTI_THREAD_STATE_INTERRUPTED; + + _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame); + if (frame != NULL && frame->frame_type == frame_native) + state |= JVMTI_THREAD_STATE_IN_NATIVE; + + using namespace java::lang; + Thread$State *ts = thread->getState (); + if (ts == Thread$State::RUNNABLE) + state |= JVMTI_THREAD_STATE_RUNNABLE; + else if (ts == Thread$State::BLOCKED) + state |= JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER; + else if (ts == Thread$State::TIMED_WAITING + || ts == Thread$State::WAITING) + { + state |= JVMTI_THREAD_STATE_WAITING; + state |= ((ts == Thread$State::WAITING) + ? JVMTI_THREAD_STATE_WAITING_INDEFINITELY + : JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT); + + /* FIXME: We don't have a way to tell + the caller why the thread is suspended, + i.e., JVMTI_THREAD_STATE_SLEEPING, + JVMTI_THREAD_STATE_PARKED, and + JVMTI_THREAD_STATE_IN_OBJECT_WAIT + are never set. */ + } + } + else + { + using namespace java::lang; + Thread$State *ts = thread->getState (); + if (ts == Thread$State::TERMINATED) + state |= JVMTI_THREAD_STATE_TERMINATED; + } + + *thread_state_ptr = state; + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL _Jv_JVMTI_CreateRawMonitor (MAYBE_UNUSED jvmtiEnv *env, const char *name, jrawMonitorID *result) { @@ -422,6 +760,36 @@ _Jv_JVMTI_Deallocate (MAYBE_UNUSED jvmtiEnv *env, unsigned char *mem) } static jvmtiError JNICALL +_Jv_JVMTI_GetClassStatus (MAYBE_UNUSED jvmtiEnv *env, jclass klass, + jint *status_ptr) +{ + REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE); + NULL_CHECK (status_ptr); + if (klass == NULL) + return JVMTI_ERROR_INVALID_CLASS; + + if (klass->isArray ()) + *status_ptr = JVMTI_CLASS_STATUS_ARRAY; + else if (klass->isPrimitive ()) + *status_ptr = JVMTI_CLASS_STATUS_PRIMITIVE; + else + { + jbyte state = _Jv_GetClassState (klass); + *status_ptr = 0; + if (state >= JV_STATE_LINKED) + (*status_ptr) |= JVMTI_CLASS_STATUS_VERIFIED; + if (state >= JV_STATE_PREPARED) + (*status_ptr) |= JVMTI_CLASS_STATUS_PREPARED; + if (state == JV_STATE_ERROR || state == JV_STATE_PHANTOM) + (*status_ptr) |= JVMTI_CLASS_STATUS_ERROR; + else if (state == JV_STATE_DONE) + (*status_ptr) |= JVMTI_CLASS_STATUS_INITIALIZED; + } + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL _Jv_JVMTI_GetClassModifiers (MAYBE_UNUSED jvmtiEnv *env, jclass klass, jint *mods) { @@ -540,6 +908,48 @@ _Jv_JVMTI_IsFieldSynthetic (MAYBE_UNUSED jvmtiEnv *env, jclass klass, } static jvmtiError JNICALL +_Jv_JVMTI_GetMethodName (MAYBE_UNUSED jvmtiEnv *env, jmethodID method, + char **name_ptr, char **signature_ptr, + char **generic_ptr) +{ + REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE); + + if (method == NULL) + return JVMTI_ERROR_INVALID_METHODID; + + if (name_ptr != NULL) + { + int len = static_cast (method->name->len ()); + *name_ptr = (char *) _Jv_MallocUnchecked (len + 1); + if (*name_ptr == NULL) + return JVMTI_ERROR_OUT_OF_MEMORY; + strncpy (*name_ptr, method->name->chars (), len); + (*name_ptr)[len] = '\0'; + } + + if (signature_ptr != NULL) + { + int len = static_cast (method->signature->len ()); + *signature_ptr = (char *) _Jv_MallocUnchecked (len + 1); + if (*signature_ptr == NULL) + { + if (name_ptr != NULL) + _Jv_Free (*name_ptr); + return JVMTI_ERROR_OUT_OF_MEMORY; + } + strncpy (*signature_ptr, method->signature->chars (), len); + (*signature_ptr)[len] = '\0'; + } + + if (generic_ptr != NULL) + { + *generic_ptr = NULL; + } + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL _Jv_JVMTI_GetMethodModifiers (MAYBE_UNUSED jvmtiEnv *env, jmethodID method, jint *result) { @@ -602,6 +1012,88 @@ _Jv_JVMTI_GetLineNumberTable (jvmtiEnv *env, jmethodID method, } static jvmtiError JNICALL +_Jv_JVMTI_GetLocalVariableTable (MAYBE_UNUSED jvmtiEnv *env, jmethodID method, + jint *num_locals, + jvmtiLocalVariableEntry **locals) +{ + REQUIRE_PHASE (env, JVMTI_PHASE_LIVE); + NULL_CHECK (num_locals); + NULL_CHECK (locals); + + CHECK_FOR_NATIVE_METHOD(method); + + jclass klass; + jvmtiError jerr = env->GetMethodDeclaringClass (method, &klass); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + _Jv_InterpMethod *imeth = reinterpret_cast<_Jv_InterpMethod *> + (_Jv_FindInterpreterMethod (klass, method)); + + if (imeth == NULL) + return JVMTI_ERROR_INVALID_METHODID; + + jerr = env->GetMaxLocals (method, num_locals); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + jerr = env->Allocate (static_cast + ((*num_locals) * sizeof (jvmtiLocalVariableEntry)), + reinterpret_cast (locals)); + + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + //the slot in the methods local_var_table to get + int table_slot = 0; + char *name; + char *sig; + char *generic_sig; + + while (table_slot < *num_locals + && imeth->get_local_var_table (&name, &sig, &generic_sig, + &((((*locals)[table_slot].start_location))), + &((*locals)[table_slot].length), + &((*locals)[table_slot].slot), + table_slot) + >= 0) + { + char **str_ptr = &(*locals)[table_slot].name; + jerr = env->Allocate (static_cast (strlen (name) + 1), + reinterpret_cast (str_ptr)); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + strcpy ((*locals)[table_slot].name, name); + + str_ptr = &(*locals)[table_slot].signature; + jerr = env->Allocate (static_cast (strlen (sig) + 1), + reinterpret_cast (str_ptr)); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + strcpy ((*locals)[table_slot].signature, sig); + + str_ptr = &(*locals)[table_slot].generic_signature; + jerr = env->Allocate (static_cast (strlen (generic_sig) + 1), + reinterpret_cast (str_ptr)); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + strcpy ((*locals)[table_slot].generic_signature, generic_sig); + + table_slot++; + } + + if (table_slot == 0) + return JVMTI_ERROR_ABSENT_INFORMATION; + + // If there are double or long variables in the table, the the table will be + // smaller than the max number of slots, so correct for this here. + if ((table_slot) < *num_locals) + *num_locals = table_slot; + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL _Jv_JVMTI_IsMethodNative (MAYBE_UNUSED jvmtiEnv *env, jmethodID method, jboolean *result) { @@ -631,6 +1123,75 @@ _Jv_JVMTI_IsMethodSynthetic (MAYBE_UNUSED jvmtiEnv *env, jmethodID method, } static jvmtiError JNICALL +_Jv_JVMTI_GetMaxLocals (jvmtiEnv *env, jmethodID method, jint *max_locals) +{ + REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE); + NULL_CHECK (max_locals); + + CHECK_FOR_NATIVE_METHOD (method); + + jclass klass; + jvmtiError jerr = env->GetMethodDeclaringClass (method, &klass); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + _Jv_InterpMethod *imeth = reinterpret_cast<_Jv_InterpMethod *> + (_Jv_FindInterpreterMethod (klass, method)); + + if (imeth == NULL) + return JVMTI_ERROR_INVALID_METHODID; + + *max_locals = imeth->get_max_locals (); + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL +_Jv_JVMTI_GetArgumentsSize (jvmtiEnv *env, jmethodID method, jint *size) +{ + REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE); + NULL_CHECK (size); + + CHECK_FOR_NATIVE_METHOD (method); + + jvmtiError jerr; + char *sig; + jint num_slots = 0; + + jerr = env->GetMethodName (method, NULL, &sig, NULL); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + // If the method is non-static add a slot for the "this" pointer. + if ((method->accflags & java::lang::reflect::Modifier::STATIC) == 0) + num_slots++; + + for (int i = 0; sig[i] != ')'; i++) + { + if (sig[i] == 'Z' || sig[i] == 'B' || sig[i] == 'C' || sig[i] == 'S' + || sig[i] == 'I' || sig[i] == 'F') + num_slots++; + else if (sig[i] == 'J' || sig[i] == 'D') + { + // If this is an array of wide types it uses a single slot + if (i > 0 && sig[i - 1] == '[') + num_slots++; + else + num_slots += 2; + } + else if (sig[i] == 'L') + { + num_slots++; + while (sig[i] != ';') + i++; + } + } + + *size = num_slots; + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL _Jv_JVMTI_GetMethodDeclaringClass (MAYBE_UNUSED jvmtiEnv *env, jmethodID method, jclass *declaring_class_ptr) @@ -683,6 +1244,80 @@ _Jv_JVMTI_GetClassLoaderClasses (MAYBE_UNUSED jvmtiEnv *env, } static jvmtiError JNICALL +_Jv_JVMTI_GetStackTrace (MAYBE_UNUSED jvmtiEnv *env, jthread thread, + jint start_depth, jint max_frames, + jvmtiFrameInfo *frames, jint *frame_count) +{ + REQUIRE_PHASE (env, JVMTI_PHASE_LIVE); + + ILLEGAL_ARGUMENT (max_frames < 0); + + NULL_CHECK (frames); + NULL_CHECK (frame_count); + + using namespace java::lang; + + THREAD_DEFAULT_TO_CURRENT (thread); + THREAD_CHECK_VALID (thread); + THREAD_CHECK_IS_ALIVE (thread); + + jvmtiError jerr = env->GetFrameCount (thread, frame_count); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + // start_depth can be either a positive number, indicating the depth of the + // stack at which to begin the trace, or a negative number indicating the + // number of frames at the bottom of the stack to exclude. These checks + // ensure that it is a valid value in either case + + ILLEGAL_ARGUMENT (start_depth >= (*frame_count)); + ILLEGAL_ARGUMENT (start_depth < (-(*frame_count))); + + _Jv_Frame *frame = reinterpret_cast<_Jv_Frame *> (thread->frame); + + // If start_depth is negative use this to determine at what depth to start + // the trace by adding it to the length of the call stack. This allows the + // use of the same frame "discarding" mechanism as for a positive start_depth + if (start_depth < 0) + start_depth = *frame_count + start_depth; + + // If start_depth > 0 "remove" start_depth frames from the beginning + // of the stack before beginning the trace by moving along the frame list. + while (start_depth > 0) + { + frame = frame->next; + start_depth--; + (*frame_count)--; + } + + // Now check to see if the array supplied by the agent is large enough to + // hold frame_count frames, after adjustment for start_depth. + if ((*frame_count) > max_frames) + (*frame_count) = max_frames; + + for (int i = 0; i < (*frame_count); i++) + { + frames[i].method = frame->self->get_method (); + + // Set the location in the frame, native frames have location = -1 + if (frame->frame_type == frame_interpreter) + { + _Jv_InterpMethod *imeth + = static_cast<_Jv_InterpMethod *> (frame->self); + _Jv_InterpFrame *interp_frame + = static_cast<_Jv_InterpFrame *> (frame); + frames[i].location = imeth->insn_index (interp_frame->get_pc ()); + } + else + frames[i].location = -1; + + frame = frame->next; + } + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL _Jv_JVMTI_ForceGarbageCollection (MAYBE_UNUSED jvmtiEnv *env) { REQUIRE_PHASE (env, JVMTI_PHASE_LIVE); @@ -723,7 +1358,7 @@ _Jv_JVMTI_DisposeEnvironment (jvmtiEnv *env) return JVMTI_ERROR_INVALID_ENVIRONMENT; else { - JvSynchronize dummy (_envListLock); + _envListLock->writeLock ()->lock (); if (_jvmtiEnvironments->env == env) { struct jvmti_env_list *next = _jvmtiEnvironments->next; @@ -736,12 +1371,16 @@ _Jv_JVMTI_DisposeEnvironment (jvmtiEnv *env) while (e->next != NULL && e->next->env != env) e = e->next; if (e->next == NULL) - return JVMTI_ERROR_INVALID_ENVIRONMENT; + { + _envListLock->writeLock ()->unlock (); + return JVMTI_ERROR_INVALID_ENVIRONMENT; + } struct jvmti_env_list *next = e->next->next; _Jv_Free (e->next); e->next = next; } + _envListLock->writeLock ()->unlock (); } _Jv_Free (env); @@ -1042,18 +1681,24 @@ check_enabled_event (jvmtiEvent type) int index = EVENT_INDEX (type); // safe since caller checks this - JvSynchronize dummy (_envListLock); - struct jvmti_env_list *e; - FOREACH_ENVIRONMENT (e) + if (_jvmtiEnvironments != NULL) { - char *addr - = reinterpret_cast (&e->env->callbacks) + offset; - void **callback = reinterpret_cast (addr); - if (e->env->enabled[index] && *callback != NULL) + _envListLock->readLock ()->lock (); + struct jvmti_env_list *e; + FOREACH_ENVIRONMENT (e) { - *enabled = true; - return; + char *addr + = reinterpret_cast (&e->env->callbacks) + offset; + void **callback = reinterpret_cast (addr); + if (e->env->enabled[index] && *callback != NULL) + { + *enabled = true; + _envListLock->readLock ()->unlock (); + return; + } } + + _envListLock->readLock ()->unlock (); } *enabled = false; @@ -1102,10 +1747,8 @@ _Jv_JVMTI_SetEventNotificationMode (jvmtiEnv *env, jvmtiEventMode mode, if (event_thread != NULL) { - using namespace java::lang; - Thread *t = reinterpret_cast (event_thread); - THREAD_CHECK_VALID (t); - THREAD_CHECK_IS_ALIVE (t); + THREAD_CHECK_VALID (event_thread); + THREAD_CHECK_IS_ALIVE (event_thread); } bool enabled; @@ -1421,21 +2064,21 @@ struct _Jv_jvmtiEnv _Jv_JVMTI_Interface = UNIMPLEMENTED, // GetTopThreadGroups UNIMPLEMENTED, // GetThreadGroupInfo UNIMPLEMENTED, // GetThreadGroupChildren - UNIMPLEMENTED, // GetFrameCount - UNIMPLEMENTED, // GetThreadState + _Jv_JVMTI_GetFrameCount, // GetFrameCount + _Jv_JVMTI_GetThreadState, // GetThreadState RESERVED, // reserved18 UNIMPLEMENTED, // GetFrameLocation UNIMPLEMENTED, // NotifyPopFrame - UNIMPLEMENTED, // GetLocalObject - UNIMPLEMENTED, // GetLocalInt - UNIMPLEMENTED, // GetLocalLong - UNIMPLEMENTED, // GetLocalFloat - UNIMPLEMENTED, // GetLocalDouble - UNIMPLEMENTED, // SetLocalObject - UNIMPLEMENTED, // SetLocalInt - UNIMPLEMENTED, // SetLocalLong - UNIMPLEMENTED, // SetLocalFloat - UNIMPLEMENTED, // SetLocalDouble + _Jv_JVMTI_GetLocalObject, // GetLocalObject + _Jv_JVMTI_GetLocalInt, // GetLocalInt + _Jv_JVMTI_GetLocalLong, // GetLocalLong + _Jv_JVMTI_GetLocalFloat, // GetLocalFloat + _Jv_JVMTI_GetLocalDouble, // GetLocalDouble + _Jv_JVMTI_SetLocalObject, // SetLocalObject + _Jv_JVMTI_SetLocalInt, // SetLocalInt + _Jv_JVMTI_SetLocalLong, // SetLocalLong + _Jv_JVMTI_SetLocalFloat, // SetLocalFloat + _Jv_JVMTI_SetLocalDouble, // SetLocalDouble _Jv_JVMTI_CreateRawMonitor, // CreateRawMonitor _Jv_JVMTI_DestroyRawMonitor, // DestroyRawMonitor _Jv_JVMTI_RawMonitorEnter, // RawMonitorEnter @@ -1454,7 +2097,7 @@ struct _Jv_jvmtiEnv _Jv_JVMTI_Interface = _Jv_JVMTI_Allocate, // Allocate _Jv_JVMTI_Deallocate, // Deallocate UNIMPLEMENTED, // GetClassSignature - UNIMPLEMENTED, // GetClassStatus + _Jv_JVMTI_GetClassStatus, // GetClassStatus UNIMPLEMENTED, // GetSourceFileName _Jv_JVMTI_GetClassModifiers, // GetClassModifiers _Jv_JVMTI_GetClassMethods, // GetClassMethods @@ -1469,15 +2112,15 @@ struct _Jv_jvmtiEnv _Jv_JVMTI_Interface = UNIMPLEMENTED, // GetFieldDeclaringClass _Jv_JVMTI_GetFieldModifiers, // GetFieldModifiers _Jv_JVMTI_IsFieldSynthetic, // IsFieldSynthetic - UNIMPLEMENTED, // GetMethodName + _Jv_JVMTI_GetMethodName, // GetMethodName _Jv_JVMTI_GetMethodDeclaringClass, // GetMethodDeclaringClass _Jv_JVMTI_GetMethodModifiers, // GetMethodModifers RESERVED, // reserved67 - UNIMPLEMENTED, // GetMaxLocals - UNIMPLEMENTED, // GetArgumentsSize + _Jv_JVMTI_GetMaxLocals, // GetMaxLocals + _Jv_JVMTI_GetArgumentsSize, // GetArgumentsSize _Jv_JVMTI_GetLineNumberTable, // GetLineNumberTable UNIMPLEMENTED, // GetMethodLocation - UNIMPLEMENTED, // GetLocalVariableTable + _Jv_JVMTI_GetLocalVariableTable, // GetLocalVariableTable RESERVED, // reserved73 RESERVED, // reserved74 UNIMPLEMENTED, // GetBytecodes @@ -1509,7 +2152,7 @@ struct _Jv_jvmtiEnv _Jv_JVMTI_Interface = UNIMPLEMENTED, // GetThreadListStackTraces UNIMPLEMENTED, // GetThreadLocalStorage UNIMPLEMENTED, // SetThreadLocalStorage - UNIMPLEMENTED, // GetStackTrace + _Jv_JVMTI_GetStackTrace, // GetStackTrace RESERVED, // reserved105 UNIMPLEMENTED, // GetTag UNIMPLEMENTED, // SetTag @@ -1567,26 +2210,29 @@ _Jv_GetJVMTIEnv (void) { _Jv_JVMTIEnv *env = (_Jv_JVMTIEnv *) _Jv_MallocUnchecked (sizeof (_Jv_JVMTIEnv)); + memset (env, 0, sizeof (_Jv_JVMTIEnv)); env->p = &_Jv_JVMTI_Interface; + struct jvmti_env_list *element + = (struct jvmti_env_list *) _Jv_MallocUnchecked (sizeof (struct jvmti_env_list)); + element->env = env; + element->next = NULL; - { - JvSynchronize dummy (_envListLock); - struct jvmti_env_list *element - = (struct jvmti_env_list *) _Jv_MallocUnchecked (sizeof (struct jvmti_env_list)); - element->env = env; - element->next = NULL; - - if (_jvmtiEnvironments == NULL) - _jvmtiEnvironments = element; - else - { - struct jvmti_env_list *e; - for (e = _jvmtiEnvironments; e->next != NULL; e = e->next) - ; - e->next = element; - } - } + _envListLock->writeLock ()->lock (); + if (_jvmtiEnvironments == NULL) + _jvmtiEnvironments = element; + else + { + struct jvmti_env_list *e; + for (e = _jvmtiEnvironments; e->next != NULL; e = e->next) + ; + e->next = element; + } + _envListLock->writeLock ()->unlock (); + /* Mark JVMTI active. This is used to force the interpreter + to use either debugging or non-debugging code. Once JVMTI + has been enabled, the non-debug interpreter cannot be used. */ + JVMTI::enabled = true; return env; } @@ -1594,7 +2240,8 @@ void _Jv_JVMTI_Init () { _jvmtiEnvironments = NULL; - _envListLock = new java::lang::Object (); + _envListLock + = new java::util::concurrent::locks::ReentrantReadWriteLock (); // No environments, so this should set all JVMTI:: members to false check_enabled_events (); @@ -1958,7 +2605,7 @@ _Jv_JVMTI_PostEvent (jvmtiEvent type, jthread event_thread, ...) va_list args; va_start (args, event_thread); - JvSynchronize dummy (_envListLock); + _envListLock->readLock ()->lock (); struct jvmti_env_list *e; FOREACH_ENVIRONMENT (e) { @@ -1974,6 +2621,6 @@ _Jv_JVMTI_PostEvent (jvmtiEvent type, jthread event_thread, ...) post_event (e->env, type, event_thread, args); } } - + _envListLock->readLock ()->unlock (); va_end (args); }