diff --git a/vm/interpreter/src/interp_native_em64t.cpp b/vm/interpreter/src/interp_native_em64t.cpp index 663db8f..f69aafd 100644 --- a/vm/interpreter/src/interp_native_em64t.cpp +++ b/vm/interpreter/src/interp_native_em64t.cpp @@ -255,12 +255,10 @@ interpreter_execute_native_method( if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_EXIT_EVENT) { - hythread_suspend_enable(); jvalue val; method_exit_callback(method, exn_raised(), resultPtr != 0 ? *resultPtr : (val.j = 0, val)); - hythread_suspend_disable(); } DEBUG_TRACE("interpreter_invoke_native >>>\n"); @@ -409,9 +407,7 @@ #endif if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { - hythread_suspend_enable(); method_entry_callback(method); - hythread_suspend_disable(); } if (method->is_synchronized()) { @@ -692,9 +688,7 @@ #endif if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { - hythread_suspend_enable(); method_entry_callback(method); - hythread_suspend_disable(); } if (method->is_synchronized()) { diff --git a/vm/interpreter/src/interp_native_ia32.cpp b/vm/interpreter/src/interp_native_ia32.cpp index 6a78c01..76e236a 100644 --- a/vm/interpreter/src/interp_native_ia32.cpp +++ b/vm/interpreter/src/interp_native_ia32.cpp @@ -234,12 +234,10 @@ interpreter_execute_native_method( if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_EXIT_EVENT) { - hythread_suspend_enable(); jvalue val; method_exit_callback(method, exn_raised(), resultPtr != 0 ? *resultPtr : (val.j = 0, val)); - hythread_suspend_disable(); } DEBUG_TRACE("interpreter_invoke_native >>>\n"); @@ -339,9 +337,7 @@ #endif if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { - hythread_suspend_enable(); method_entry_callback(method); - hythread_suspend_disable(); } if (method->is_synchronized()) { @@ -578,9 +574,7 @@ #endif if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { - hythread_suspend_enable(); method_entry_callback(method); - hythread_suspend_disable(); } if (method->is_synchronized()) { diff --git a/vm/interpreter/src/interp_native_ipf.cpp b/vm/interpreter/src/interp_native_ipf.cpp index 33dbe0b..9f1f4de 100644 --- a/vm/interpreter/src/interp_native_ipf.cpp +++ b/vm/interpreter/src/interp_native_ipf.cpp @@ -248,12 +248,10 @@ interpreter_execute_native_method( if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_EXIT_EVENT) { - hythread_suspend_enable(); jvalue val; method_exit_callback(method, exn_raised(), resultPtr != 0 ? *resultPtr : (val.j = 0, val)); - hythread_suspend_disable(); } DEBUG_TRACE("interpreter_invoke_native >>>\n"); @@ -375,9 +373,7 @@ #endif if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { - hythread_suspend_enable(); method_entry_callback(method); - hythread_suspend_disable(); } if (method->is_synchronized()) { @@ -652,9 +648,7 @@ #endif if (interpreter_ti_notification_mode & INTERPRETER_TI_METHOD_ENTRY_EVENT) { - hythread_suspend_enable(); method_entry_callback(method); - hythread_suspend_disable(); } if (method->is_synchronized()) { diff --git a/vm/interpreter/src/interpreter.cpp b/vm/interpreter/src/interpreter.cpp index 86b9abf..28a4bd2 100644 --- a/vm/interpreter/src/interpreter.cpp +++ b/vm/interpreter/src/interpreter.cpp @@ -2496,9 +2496,7 @@ method_exit_callback_with_frame(Method * ABORT("Unexpected java type"); } - hythread_suspend_enable(); method_exit_callback(method, false, val); - hythread_suspend_disable(); } void diff --git a/vm/port/include/m2n.h b/vm/port/include/m2n.h index 120e278..465026c 100644 --- a/vm/port/include/m2n.h +++ b/vm/port/include/m2n.h @@ -44,7 +44,11 @@ enum frame_type { FRAME_UNKNOWN = 0x0, FRAME_NON_UNWINDABLE = 0x1000, FRAME_JNI = 0x1 | FRAME_NON_UNWINDABLE, - FRAME_COMPILATION = 0x2 | FRAME_NON_UNWINDABLE + FRAME_COMPILATION = 0x2 | FRAME_NON_UNWINDABLE, + FRAME_UNPOPABLE = 0x0000, + FRAME_POPABLE = 0x0100, + FRAME_POP_NOW = 0x0200, + FRAME_SAFE_POINT = 0x0400 }; // The pushing and popping of native frames is done only by stubs that diff --git a/vm/vmcore/include/environment.h b/vm/vmcore/include/environment.h index ffa91af..0d095f8 100644 --- a/vm/vmcore/include/environment.h +++ b/vm/vmcore/include/environment.h @@ -136,7 +136,10 @@ struct Global_Env { Class* java_lang_ClassCastException_Class; Class* java_lang_OutOfMemoryError_Class; ObjectHandle java_lang_OutOfMemoryError; - + + // object of java.lang.Error class used for JVMTI JIT PopFrame support + ObjectHandle popFrameException; + Class* java_io_Serializable_Class; Class* java_lang_Cloneable_Class; Class* java_lang_Thread_Class; diff --git a/vm/vmcore/include/jvmti_direct.h b/vm/vmcore/include/jvmti_direct.h index 0312b15..2d20a4a 100644 --- a/vm/vmcore/include/jvmti_direct.h +++ b/vm/vmcore/include/jvmti_direct.h @@ -78,6 +78,11 @@ jint get_thread_stack_depth(VM_thread *t void jvmti_set_pending_breakpoints(Method *method); void jvmti_get_compilation_flags(OpenMethodExecutionParams *flags); +// Marks topmost frame of the specified thead to be popped +jvmtiError jvmti_jit_pop_frame(VM_thread *thread); +// On current thread perform popping of topmost frame +void jvmti_jit_do_pop_frame(); + /* Events functions */ #ifdef __cplusplus diff --git a/vm/vmcore/include/jvmti_interface.h b/vm/vmcore/include/jvmti_interface.h index af35e1a..871b75a 100644 --- a/vm/vmcore/include/jvmti_interface.h +++ b/vm/vmcore/include/jvmti_interface.h @@ -45,7 +45,7 @@ void jvmti_method_exit_callback(Method_H /** * Field access callback which is called from JITted code compiled with flag whenever * access of field which has set occures. - * Garbage collector must be enabled. + * Garbage collector must be disabled. * @param field - handle of the field under access * @param method - handle of the method, which accesses field * @param location - location of code which accesses field @@ -60,7 +60,7 @@ void jvmti_field_access_callback(Field_H /** * Field modification callback which is called from JITted code compiled with flag whenever * modification of field which has set occures. - * Garbage collector must be enabled. + * Garbage collector must be disabled. * @param field - handle of the field under modification * @param method - handle of the method, which modifies field * @param location - location of code which modifies field @@ -74,6 +74,11 @@ void jvmti_field_modification_callback(F jobject* object, jvalue* new_value); +/** + * Callback which is called frim JITted code. Serves as a wrapper for + * hythread_safe_point(). + */ +void jvmti_safe_point(); #ifdef __cplusplus } diff --git a/vm/vmcore/src/class_support/Environment.cpp b/vm/vmcore/src/class_support/Environment.cpp index f3b8d93..d72e4a3 100644 --- a/vm/vmcore/src/class_support/Environment.cpp +++ b/vm/vmcore/src/class_support/Environment.cpp @@ -124,7 +124,10 @@ #endif // !_IPF_ java_lang_ArithmeticException_Class = NULL; java_lang_ClassCastException_Class = NULL; java_lang_OutOfMemoryError_Class = NULL; + java_lang_OutOfMemoryError = NULL; + popFrameException = NULL; + java_io_Serializable_Class = NULL; java_lang_Cloneable_Class = NULL; java_lang_Thread_Class = NULL; diff --git a/vm/vmcore/src/exception/exceptions.cpp b/vm/vmcore/src/exception/exceptions.cpp index 9c9fdb1..7195ec6 100644 --- a/vm/vmcore/src/exception/exceptions.cpp +++ b/vm/vmcore/src/exception/exceptions.cpp @@ -314,6 +314,14 @@ void exn_raise_by_name(const char* exc_n exn_raise_by_name_internal(exc_name, exc_message, exc_cause); } +static void check_pop_frame(ManagedObject *exn) { + if (exn == VM_Global_State::loader_env->popFrameException->object) { + frame_type type = m2n_get_frame_type(m2n_get_last_frame()); + + if (FRAME_POP_NOW == (FRAME_POP_NOW & type)) + jvmti_jit_do_pop_frame(); + } +} void exn_rethrow() { @@ -321,11 +329,17 @@ #ifndef VM_LAZY_EXCEPTION ManagedObject *exn = get_exception_object_internal(); assert(exn); clear_exception_internal(); + + check_pop_frame(exn); + exn_throw_for_JIT(exn, NULL, NULL, NULL, NULL); #else if (NULL != p_TLS_vmthread->thread_exception.exc_object) { ManagedObject* exn_mng_object = p_TLS_vmthread->thread_exception.exc_object; clear_exception_internal(); + + check_pop_frame(exn_mng_object); + exn_throw_for_JIT(exn_mng_object, NULL, NULL, NULL, NULL); } else if (NULL != p_TLS_vmthread->thread_exception.exc_class) { Class * exc_class = p_TLS_vmthread->thread_exception.exc_class; diff --git a/vm/vmcore/src/init/vm_init.cpp b/vm/vmcore/src/init/vm_init.cpp index 30ed564..f96c8d1 100644 --- a/vm/vmcore/src/init/vm_init.cpp +++ b/vm/vmcore/src/init/vm_init.cpp @@ -283,13 +283,17 @@ #endif // POINTER64 preload_class(env, "java/lang/ClassCastException"); env->java_lang_OutOfMemoryError_Class = preload_class(env, "java/lang/OutOfMemoryError"); + env->java_lang_OutOfMemoryError = oh_allocate_global_handle(); + env->popFrameException = oh_allocate_global_handle(); tmn_suspend_disable(); // precompile StackOverflowError class_alloc_new_object_and_run_default_constructor(env->java_lang_StackOverflowError_Class); env->java_lang_OutOfMemoryError->object = class_alloc_new_object(env->java_lang_OutOfMemoryError_Class); + env->popFrameException->object = + class_alloc_new_object(env->java_lang_Error_Class); tmn_suspend_enable(); env->java_lang_Cloneable_Class = diff --git a/vm/vmcore/src/jit/jit_runtime_support.cpp b/vm/vmcore/src/jit/jit_runtime_support.cpp index d171d17..7e93ead 100644 --- a/vm/vmcore/src/jit/jit_runtime_support.cpp +++ b/vm/vmcore/src/jit/jit_runtime_support.cpp @@ -1606,7 +1606,7 @@ static NativeCodePtr rth_get_lil_gc_safe if (addr) { return addr; } - void (*hythread_safe_point_ptr)() = hythread_safe_point; + void (*hythread_safe_point_ptr)() = jvmti_safe_point; LilCodeStub* cs = lil_parse_code_stub("entry 0:managed::void;"); assert(cs); if (dyn_count) { @@ -1614,11 +1614,12 @@ static NativeCodePtr rth_get_lil_gc_safe assert(cs); } cs = lil_parse_onto_end(cs, - "push_m2n 0, 0;" + "push_m2n 0, %0i;" "out platform::void;" - "call %0i;" + "call %1i;" "pop_m2n;" "ret;", + (FRAME_POPABLE | FRAME_SAFE_POINT), hythread_safe_point_ptr); assert(cs && lil_is_valid(cs)); addr = LilCodeGenerator::get_platform()->compile(cs); diff --git a/vm/vmcore/src/jvmti/jvmti_capability.cpp b/vm/vmcore/src/jvmti/jvmti_capability.cpp index 81a31c1..d9b19f3 100644 --- a/vm/vmcore/src/jvmti/jvmti_capability.cpp +++ b/vm/vmcore/src/jvmti/jvmti_capability.cpp @@ -75,7 +75,7 @@ static const jvmtiCapabilities jvmti_sup 1, // can_get_owned_monitor_info 1, // can_get_current_contended_monitor 1, // can_get_monitor_info - 0, // can_pop_frame + 1, // can_pop_frame 0, // can_redefine_classes 0, // can_signal_thread 1, // can_get_source_file_name diff --git a/vm/vmcore/src/jvmti/jvmti_event.cpp b/vm/vmcore/src/jvmti/jvmti_event.cpp index dcd7b8c..8f62072 100644 --- a/vm/vmcore/src/jvmti/jvmti_event.cpp +++ b/vm/vmcore/src/jvmti/jvmti_event.cpp @@ -764,7 +764,7 @@ jvmti_process_single_step_event(jmethodI } VMEXPORT void jvmti_process_field_access_event(Field_Handle field, - jmethodID method, jlocation location, jobject* object) + jmethodID method, jlocation location, jobject* p_object) { DebugUtilsTI *ti = VM_Global_State::loader_env->TI; if (!ti->isEnabled() ) @@ -776,6 +776,9 @@ VMEXPORT void jvmti_process_field_access if (!ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_ACCESS_EVENT)) return; + // unreference pointer to object handle + jobject object = (p_object) ? *p_object : NULL ; + // get field class //Type_Info_Handle field_type = field_get_type_info_of_field_value(field); //Class_Handle clss = type_info_get_class(field_type); @@ -816,13 +819,13 @@ VMEXPORT void jvmti_process_field_access if (NULL != ti_env->event_table.FieldAccess) ti_env->event_table.FieldAccess(jvmti_env, jni_env, thread, - method, location, field_klass, *object, (jfieldID) field); + method, location, field_klass, object, (jfieldID) field); ti_env = next_env; } } // jvmti_process_field_access_event VMEXPORT void jvmti_process_field_modification_event(Field_Handle field, - jmethodID method, jlocation location, jobject* object, jvalue new_value) + jmethodID method, jlocation location, jobject* p_object, jvalue new_value) { DebugUtilsTI *ti = VM_Global_State::loader_env->TI; if (!ti->isEnabled() ) @@ -834,6 +837,9 @@ VMEXPORT void jvmti_process_field_modifi if (!ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_MODIFICATION_EVENT)) return; + // unreference pointer to object handle + jobject object = (p_object) ? *p_object : NULL ; + // get field class //Type_Info_Handle field_type = field_get_type_info_of_field_value(field); //Class_Handle clss = type_info_get_class(field_type); @@ -877,7 +883,7 @@ VMEXPORT void jvmti_process_field_modifi if (NULL != ti_env->event_table.FieldModification) ti_env->event_table.FieldModification(jvmti_env, jni_env, thread, - method, location, field_klass, *object, (jfieldID) field, + method, location, field_klass, object, (jfieldID) field, signature_type, new_value); ti_env = next_env; } diff --git a/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp b/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp new file mode 100755 index 0000000..df49ec9 --- /dev/null +++ b/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * JVMTI JIT pop frame support functions. + */ + +#define LOG_DOMAIN "jvmti.stack.popframe" + +#include "jvmti_direct.h" +#include "jvmti_interface.h" +#include "exceptions.h" +#include "environment.h" +#include "vm_threads.h" +#include "m2n.h" +#include "stack_iterator.h" +#include "cxxlog.h" + +jvmtiError jvmti_jit_pop_frame(VM_thread *thread) +{ + assert(hythread_is_suspend_enabled()); + + M2nFrame* top_frame = thread->last_m2n_frame; + frame_type type = m2n_get_frame_type(top_frame); + + if (FRAME_POPABLE != (FRAME_POPABLE & type)) + return JVMTI_ERROR_OPAQUE_FRAME; + + StackIterator *si = si_create_from_native(thread); + + // check that topmost frame is M2n + assert(si_is_native(si)); + + // go to 2-d frame & check it's managed + si_goto_previous(si); + assert(! si_is_native(si)); + + // go to 3-d frame & check its type + si_goto_previous(si); + + if (si_is_native(si)) { + M2nFrame* third_frame = m2n_get_previous_frame(top_frame); + + if (FRAME_POPABLE != (FRAME_POPABLE & m2n_get_frame_type(top_frame))) + return JVMTI_ERROR_OPAQUE_FRAME; + } + + type = (frame_type) (type | FRAME_POP_NOW); + m2n_set_frame_type(top_frame, type); + + return JVMTI_ERROR_NONE; +} + +void jvmti_jit_do_pop_frame() +{ + TRACE("jvmti_jit_do_pop_frame() is called"); +} + +void jvmti_safe_point() +{ +// __asm int 3; + TRACE("entering safe_point"); + hythread_safe_point(); + + TRACE("left safe_point"); + frame_type type = m2n_get_frame_type(m2n_get_last_frame()); + + if (FRAME_POP_NOW == (FRAME_POP_NOW & type)) + jvmti_jit_do_pop_frame(); +} + +void jvmti_pop_frame_callback() +{ + TRACE("suspend_disable post callback..."); + frame_type type = m2n_get_frame_type(p_TLS_vmthread->last_m2n_frame); + + if (FRAME_POP_NOW != (FRAME_POP_NOW & type)) + return; + + if (is_unwindable()) { + jvmti_jit_do_pop_frame(); + } else { + exn_raise_object(VM_Global_State::loader_env->popFrameException); + } +} diff --git a/vm/vmcore/src/jvmti/jvmti_stack.cpp b/vm/vmcore/src/jvmti/jvmti_stack.cpp old mode 100644 new mode 100755 index 4198e02..d7dce26 --- a/vm/vmcore/src/jvmti/jvmti_stack.cpp +++ b/vm/vmcore/src/jvmti/jvmti_stack.cpp @@ -313,45 +313,35 @@ jvmtiGetAllStackTraces(jvmtiEnv* env, // event handler for thread_creating should block creation new threads // at this moment assert(hythread_is_suspend_enabled()); - hythread_global_lock(); + hythread_suspend_all(NULL, NULL); res = jvmtiGetAllThreads(env, &count, &threads); if (res != JVMTI_ERROR_NONE) { - hythread_global_unlock(); + hythread_resume_all(NULL); return res; } jvmtiStackInfo *info; + // FIXME: memory leak in case of error res = _allocate(sizeof(jvmtiStackInfo) * count + sizeof(jvmtiFrameInfo) * max_frame_count * count, (unsigned char **)&info); - if (JVMTI_ERROR_NONE != res) - return res; + if (JVMTI_ERROR_NONE != res) { + hythread_resume_all(NULL); + return res; + } - jthread currentThread = getCurrentThread(); - int i; - // stoping all threads - for(i = 0; i < count; i++) { - // FIXME: thread can be dead at this time - // event handler for thread death should block thread death - // until the function end. + // geting thread states + for(int i = 0; i < count; i++) { info[i].thread = threads[i]; res = jvmtiGetThreadState(env, threads[i], &info[i].state); - if (JVMTI_ERROR_NONE != res) + if (JVMTI_ERROR_NONE != res) { + hythread_resume_all(NULL); return res; - - // FIXME: suspended thread might be resumed in other jvmti thread? - if (info[i].state != JVMTI_THREAD_STATE_SUSPENDED) { - if (IsSameObject(jvmti_test_jenv, currentThread, threads[i])) - continue; - jthread_suspend(threads[i]); } - } - // geting thread states - for(i = 0; i < count; i++) { // Frame_buffer pointer should pointer to the memory right // after the jvmtiStackInfo structures info[i].frame_buffer = ((jvmtiFrameInfo *)&info[count]) + @@ -359,18 +349,15 @@ jvmtiGetAllStackTraces(jvmtiEnv* env, res = jvmtiGetStackTrace(env, info[i].thread, 0, max_frame_count, info[i].frame_buffer, &info[i].frame_count); - if (JVMTI_ERROR_NONE != res) + if (JVMTI_ERROR_NONE != res) { + hythread_resume_all(NULL); return res; + } } - // unsuspend suspended threads. - for(i = 0; i < count; i++) { - if (info[i].state != JVMTI_THREAD_STATE_SUSPENDED) - jthread_resume(threads[i]); - } + hythread_resume_all(NULL); - hythread_global_unlock(); - * thread_count_ptr = count; + *thread_count_ptr = count; *stack_info_ptr = info; return JVMTI_ERROR_NONE; } @@ -423,6 +410,9 @@ jvmtiGetThreadListStackTraces(jvmtiEnv* sizeof(jvmtiFrameInfo) * max_frame_count * count, (unsigned char **)&info); + if (JVMTI_ERROR_NONE != res) + return res; + int i; jthread currentThread = getCurrentThread(); // stoping all threads @@ -453,8 +443,11 @@ jvmtiGetThreadListStackTraces(jvmtiEnv* res = jvmtiGetStackTrace(env, info[i].thread, 0, max_frame_count, info[i].frame_buffer, &info[i].frame_count); - if (JVMTI_ERROR_NONE != res) - return res; + // if thread was terminated before we got it's stack - return null frame_count + if (JVMTI_ERROR_THREAD_NOT_ALIVE == res) + info[i].frame_count = 0; + else if (JVMTI_ERROR_NONE != res) + break; } // unsuspend suspended threads. @@ -463,6 +456,9 @@ jvmtiGetThreadListStackTraces(jvmtiEnv* jthread_resume(threads[i]); } + if (JVMTI_ERROR_NONE != res) + return res; + *stack_info_ptr = info; return JVMTI_ERROR_NONE; } @@ -598,8 +594,13 @@ jvmtiPopFrame(jvmtiEnv* env, return JVMTI_ERROR_THREAD_NOT_SUSPENDED; } - return interpreter.interpreter_ti_pop_frame(env, - get_vm_thread_ptr_safe(jvmti_test_jenv, thread)); + if (interpreter_enabled()) { + return interpreter.interpreter_ti_pop_frame(env, + get_vm_thread_ptr_safe(jvmti_test_jenv, thread)); + } else { + return jvmti_jit_pop_frame( + get_vm_thread_ptr_safe(jvmti_test_jenv, thread)); + } } /* diff --git a/vm/vmcore/src/jvmti/jvmti_watch.cpp b/vm/vmcore/src/jvmti/jvmti_watch.cpp index 67ebd5a..b7230d5 100644 --- a/vm/vmcore/src/jvmti/jvmti_watch.cpp +++ b/vm/vmcore/src/jvmti/jvmti_watch.cpp @@ -311,8 +311,12 @@ void jvmti_field_access_callback(Field_H jlocation location, jobject* object) { + tmn_suspend_enable(); + jvmti_process_field_access_event(field, (jmethodID) method, location, object); + + tmn_suspend_disable(); } void jvmti_field_modification_callback(Field_Handle field, @@ -321,6 +325,10 @@ void jvmti_field_modification_callback(F jobject* object, jvalue* new_value) { + tmn_suspend_enable(); + jvmti_process_field_modification_event(field, (jmethodID) method, location, object, *new_value); + + tmn_suspend_disable(); }