/* * Is Method Obsolete * * Has this method been made obsolete with RedefineClasses? * * REQUIRED Functionality. */ jvmtiError JNICALL jvmtiIsMethodObsolete(jvmtiEnv* env, jmethodID method, jboolean* is_obsolete_ptr) { TRACE("IsMethodObsolete called for " << method); SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_redefine_classes); /** * Check is_obsolete_ptr */ if( !is_obsolete_ptr ) { return JVMTI_ERROR_NULL_POINTER; } /** * Check method */ if( !method ) { return JVMTI_ERROR_INVALID_METHODID; } /** * Since we don't have RedefineClasses yet, always return false */ *is_obsolete_ptr = JNI_FALSE; TRACE("IsMethodObsolete(" << method << ") = " << *is_obsolete_ptr); return JVMTI_ERROR_NONE; } // jvmtiIsMethodObsolete
/* * Get Current Thread CPU Time * * Return the CPU time utilized by the current thread. * * OPTIONAL Functionality. */ jvmtiError JNICALL jvmtiGetCurrentThreadCpuTime(jvmtiEnv* env, jlong* nanos_ptr) { TRACE2("jvmti.timer", "GetCurrentThreadCpuTime called"); IDATA status; SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_get_current_thread_cpu_time); if (NULL == nanos_ptr) return JVMTI_ERROR_NULL_POINTER; status = jthread_get_thread_cpu_time(NULL, nanos_ptr); if (status != TM_ERROR_NONE) return JVMTI_ERROR_INTERNAL; return JVMTI_ERROR_NONE; }
/* * Is Method Synthetic * * For the method indicated by method, return a value indicating * whether the method is synthetic via is_synthetic_ptr. Synthetic * methods are generated by the compiler but not present in the * original source code. * * OPTIONAL Functionality. */ jvmtiError JNICALL jvmtiIsMethodSynthetic(jvmtiEnv* env, jmethodID method, jboolean* is_synthetic_ptr) { TRACE("IsMethodSynthetic called"); SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_get_synthetic_attribute); /** * Check is_synthetic_ptr */ if( !is_synthetic_ptr ) { return JVMTI_ERROR_NULL_POINTER; } /** * Check method */ if( !method ) { return JVMTI_ERROR_INVALID_METHODID; } /** * Get method synthetic */ *is_synthetic_ptr = (jboolean)(reinterpret_cast<Method*>(method)->is_synthetic() ? JNI_TRUE : JNI_FALSE); return JVMTI_ERROR_NONE; } // jvmtiIsMethodSynthetic
/* * Get Bytecodes * * For the method indicated by method, return the byte codes that * implement the method. The number of bytecodes is returned via * bytecode_count_ptr. The byte codes themselves are returned via * bytecodes_ptr. * * OPTIONAL Functionality. */ jvmtiError JNICALL jvmtiGetBytecodes(jvmtiEnv* env, jmethodID method, jint* bytecode_count_ptr, unsigned char** bytecodes_ptr) { TRACE("GetBytecodes called"); SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_get_bytecodes); /** * Check is_native_ptr */ if( !bytecode_count_ptr || !bytecodes_ptr ) { return JVMTI_ERROR_NULL_POINTER; } /** * Check method */ if( !method ) { return JVMTI_ERROR_INVALID_METHODID; } Method* mtd = (Method*)method; if( mtd->is_native() ) return JVMTI_ERROR_NATIVE_METHOD; if( mtd->get_byte_code_addr() == NULL ) return JVMTI_ERROR_OUT_OF_MEMORY; *bytecode_count_ptr = mtd->get_byte_code_size(); jvmtiError err = _allocate( *bytecode_count_ptr, bytecodes_ptr ); if( err != JVMTI_ERROR_NONE ) return err; memcpy( *bytecodes_ptr, mtd->get_byte_code_addr(), *bytecode_count_ptr ); if (interpreter_enabled()) { TIEnv *p_env = (TIEnv *)env; VMBreakPoints* vm_brpt = p_env->vm->vm_env->TI->vm_brpt; LMAutoUnlock lock(vm_brpt->get_lock()); for (VMBreakPoint* bpt = vm_brpt->find_method_breakpoint(method); bpt; bpt = vm_brpt->find_next_method_breakpoint(bpt, method)) { (*bytecodes_ptr)[bpt->location] = (unsigned char)bpt->saved_byte; } } return JVMTI_ERROR_NONE; }
/* * Get Thread CPU Time * * Return the CPU time utilized by the specified thread. * * OPTIONAL Functionality. */ jvmtiError JNICALL jvmtiGetThreadCpuTime(jvmtiEnv* env, jthread thread, jlong* nanos_ptr) { TRACE2("jvmti.timer", "GetThreadCpuTime called"); IDATA status; SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_get_thread_cpu_time); if (NULL == nanos_ptr) return JVMTI_ERROR_NULL_POINTER; if (NULL == thread) { status = jthread_get_thread_cpu_time(NULL, nanos_ptr); } else { if (! is_valid_thread_object(thread)) return JVMTI_ERROR_INVALID_THREAD; // lock thread manager to avoid occasional change of thread state hythread_global_lock(); int state;// =thread_get_thread_state(thread); jvmtiError err = jvmtiGetThreadState(env, thread, &state); if (err != JVMTI_ERROR_NONE){ return err; } switch (state) { case JVMTI_THREAD_STATE_TERMINATED: // thread is terminated case JVMTI_JAVA_LANG_THREAD_STATE_NEW: // thread is new hythread_global_unlock(); return JVMTI_ERROR_THREAD_NOT_ALIVE; default: // thread is alive status = jthread_get_thread_cpu_time(thread, nanos_ptr); break; } hythread_global_unlock(); } if (status != TM_ERROR_NONE) return JVMTI_ERROR_INTERNAL; return JVMTI_ERROR_NONE; }
/* * Get Thread CPU Timer Information * * Get information about the GetThreadCpuTime timer. The fields * of the jvmtiTimerInfo structure are filled in with details * about the timer. * * OPTIONAL Functionality. */ jvmtiError JNICALL jvmtiGetThreadCpuTimerInfo(jvmtiEnv* env, jvmtiTimerInfo* info_ptr) { TRACE2("jvmti.timer", "GetThreadCpuTimerInfo called"); SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_get_thread_cpu_time); if (NULL == info_ptr) return JVMTI_ERROR_NULL_POINTER; fill_timer_info(info_ptr); return JVMTI_ERROR_NONE; }
jvmtiError JNICALL jvmtiGetLocalLong(jvmtiEnv* env, jthread thread, jint depth, jint slot, jlong* value_ptr) { TRACE("GetLocalLong called"); SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_access_local_variables); // check error condition: JVMTI_ERROR_INVALID_THREAD // check error condition: JVMTI_ERROR_THREAD_NOT_ALIVE // check error condition: JVMTI_ERROR_ILLEGAL_ARGUMENT // check error condition: JVMTI_ERROR_NULL_POINTER jvmtiError err = GetLocal_checkArgs(env, &thread, depth, slot, value_ptr); if (err != JVMTI_ERROR_NONE) return err; bool thread_suspended = false; // Suspend thread before getting stacks vm_thread_t vm_thread; if (NULL != thread) { // Check that this thread is not current vm_thread = jthread_get_vm_thread_ptr_safe(thread); if (vm_thread != p_TLS_vmthread) { IDATA UNREF status = hythread_suspend_other((hythread_t)vm_thread); assert(TM_ERROR_NONE == status); thread_suspended = true; } } else vm_thread = p_TLS_vmthread; if (interpreter_enabled()) // check error condition: JVMTI_ERROR_INVALID_SLOT // check error condition: JVMTI_ERROR_OPAQUE_FRAME // check error condition: JVMTI_ERROR_NO_MORE_FRAMES // TODO: check error condition: JVMTI_ERROR_TYPE_MISMATCH err = interpreter.interpreter_ti_getLocal64(env, vm_thread, depth, slot, value_ptr); else { GET_JIT_FRAME_CONTEXT; tmn_suspend_disable(); OpenExeJpdaError result = jit->get_local_var(method, jfc, slot, VM_DATA_TYPE_INT64, value_ptr); si_free(si); tmn_suspend_enable(); err = jvmti_translate_jit_error(result); } if (thread_suspended) hythread_resume((hythread_t)vm_thread); return err; }
/** * General function to set value of local variable. * @param var_type type of the local variable * @param p_value pointer to the new variable value */ static jvmtiError set_local(jvmtiEnv* env, jthread thread, jint depth, jint slot, VM_Data_Type var_type, void* p_value) { SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_access_local_variables); // check error condition: JVMTI_ERROR_INVALID_THREAD // check error condition: JVMTI_ERROR_THREAD_NOT_ALIVE // check error condition: JVMTI_ERROR_ILLEGAL_ARGUMENT jvmtiError err = GetLocal_checkArgs(env, &thread, depth, slot, p_value); if (err != JVMTI_ERROR_NONE) return err; // check error condition: JVMTI_ERROR_INVALID_OBJECT if (VM_DATA_TYPE_CLASS == var_type && ! is_valid_object(env, *(jobject*) p_value)) return JVMTI_ERROR_INVALID_OBJECT; bool thread_suspended = false; // Suspend thread before getting stacks vm_thread_t vm_thread; if (NULL != thread) { // Check that this thread is not current vm_thread = jthread_get_vm_thread_ptr_safe(thread); if (vm_thread != p_TLS_vmthread) { IDATA UNREF status = hythread_suspend_other((hythread_t)vm_thread); assert(TM_ERROR_NONE == status); thread_suspended = true; } } else vm_thread = p_TLS_vmthread; if (interpreter_enabled()) { // TODO: check error condition: JVMTI_ERROR_INVALID_SLOT // TODO: check error condition: JVMTI_ERROR_TYPE_MISMATCH // TODO: check error condition: JVMTI_ERROR_OPAQUE_FRAME // TODO: check error condition: JVMTI_ERROR_NO_MORE_FRAMES switch (var_type) { case VM_DATA_TYPE_CLASS: err = interpreter.interpreter_ti_setObject(env, vm_thread, depth, slot, *(jobject*) p_value); break; case VM_DATA_TYPE_INT32: case VM_DATA_TYPE_F4: err = interpreter.interpreter_ti_setLocal32(env, vm_thread, depth, slot, *(int*) p_value); break; case VM_DATA_TYPE_INT64: case VM_DATA_TYPE_F8: err = interpreter.interpreter_ti_setLocal64(env, vm_thread, depth, slot, *(int64*) p_value); break; default: DIE(("Error: unrecognized local variable type")); } } else { GET_JIT_FRAME_CONTEXT; tmn_suspend_disable(); OpenExeJpdaError result; switch (var_type) { case VM_DATA_TYPE_CLASS: if (NULL != *(jobject*) p_value) result = jit->set_local_var(method, jfc, slot, VM_DATA_TYPE_CLASS, &(*(ObjectHandle*) p_value)->object); else { ManagedObject *n = (ManagedObject *)VM_Global_State::loader_env->managed_null; result = jit->set_local_var(method, jfc, slot, VM_DATA_TYPE_CLASS, &n); } break; case VM_DATA_TYPE_INT32: case VM_DATA_TYPE_F4: case VM_DATA_TYPE_INT64: case VM_DATA_TYPE_F8: result = jit->set_local_var(method, jfc, slot, var_type, p_value); break; default: DIE(("Error: unrecognized local variable type")); } si_free(si); tmn_suspend_enable(); err = jvmti_translate_jit_error(result); } if (thread_suspended) hythread_resume((hythread_t)vm_thread); return err; }
/* * Get Local Variable Table * * Return local variable information. * * OPTIONAL Functionality. */ jvmtiError JNICALL jvmtiGetLocalVariableTable(jvmtiEnv* env, jmethodID method, jint* entry_count_ptr, jvmtiLocalVariableEntry** table_ptr) { TRACE("GetLocalVariableTable called"); SuspendEnabledChecker sec; int len, index, count; char *pointer; Method *method_ptr; jvmtiError result; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_access_local_variables); /** * Check entry_count_ptr and table_ptr */ if( !entry_count_ptr || !table_ptr ) { return JVMTI_ERROR_NULL_POINTER; } /** * Check method */ if( !method ) { return JVMTI_ERROR_INVALID_METHODID; } else if( ((Method*)method)->is_native() ) { return JVMTI_ERROR_NATIVE_METHOD; } /** * Get method local variable table number entries */ method_ptr = (Method*)method; count = method_ptr->get_local_var_table_size(); if( count == 0 ) { return JVMTI_ERROR_ABSENT_INFORMATION; } /** * Allocate memory for local variable table */ *entry_count_ptr = count; result = _allocate( count * sizeof(jvmtiLocalVariableEntry), (unsigned char**)table_ptr ); if( result != JVMTI_ERROR_NONE ) { return result; } /** * Set local variable table */ for( index = 0; index < count; index++) { String *name, *type, *generic_type; jvmtiLocalVariableEntry* entry = *table_ptr + index; method_ptr->get_local_var_entry(index, &(entry->start_location), &(entry->length), &(entry->slot), &name, &type, &generic_type); // allocate memory for name len = get_utf8_length_of_8bit( (const U_8*)name->bytes, name->len); result = _allocate( len + 1, (unsigned char**)&pointer ); if( result != JVMTI_ERROR_NONE ) { return result; } // copy variable name utf8_from_8bit( pointer, (const U_8*)name->bytes, name->len); // set variable name entry->name = pointer; // allocate memory for signature len = get_utf8_length_of_8bit( (const U_8*)type->bytes, type->len); result = _allocate( len + 1, (unsigned char**)&pointer ); if( result != JVMTI_ERROR_NONE ) { return result; } // copy variable signature utf8_from_8bit( pointer, (const U_8*)type->bytes, type->len); // set variable signature entry->signature = pointer; // set variable slot if (generic_type) { // allocate memory for generic_signature len = get_utf8_length_of_8bit( (const U_8*)generic_type->bytes, generic_type->len); result = _allocate( len + 1, (unsigned char**)&pointer ); if( result != JVMTI_ERROR_NONE ) { return result; } // copy variable generic_signature utf8_from_8bit( pointer, (const U_8*)generic_type->bytes, generic_type->len); // set variable generic_signature entry->generic_signature = pointer; } else { entry->generic_signature = NULL; } } return JVMTI_ERROR_NONE; } // jvmtiGetLocalVariableTable
/* * Get Line Number Table * * For the method indicated by method, return a table of source * line number entries. The size of the table is returned via * entry_count_ptr and the table itself is returned via table_ptr. * * OPTIONAL Functionality. */ jvmtiError JNICALL jvmtiGetLineNumberTable(jvmtiEnv* env, jmethodID method, jint* entry_count_ptr, jvmtiLineNumberEntry** table_ptr) { TRACE("GetLineNumberTable called"); SuspendEnabledChecker sec; int index, count; Method *method_ptr; jvmtiError result; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_get_line_numbers); /** * Check entry_count_ptr and table_ptr */ if( !entry_count_ptr || !table_ptr ) { return JVMTI_ERROR_NULL_POINTER; } /** * Check method */ if( !method ) { return JVMTI_ERROR_INVALID_METHODID; } else if( ((Method*)method)->is_native() ) { return JVMTI_ERROR_NATIVE_METHOD; } /** * Get method line number table entries number */ method_ptr = (Method*)method; count = method_ptr->get_line_number_table_size(); if( count == 0 ) { return JVMTI_ERROR_ABSENT_INFORMATION; } /** * Allocate memory for line number table */ *entry_count_ptr = count; result = _allocate( count * sizeof(jvmtiLineNumberEntry), (unsigned char**)table_ptr ); if( result != JVMTI_ERROR_NONE ) { return result; } /** * Set line number table */ for( index = 0; index < count; ++index) { jvmtiLineNumberEntry* entry = *table_ptr + index; method_ptr->get_line_number_entry(index, &(entry->start_location), &(entry->line_number)); } return JVMTI_ERROR_NONE; } // jvmtiGetLineNumberTable