From b02d739b6010ac849349722af2e1e38a74e6ada9 Mon Sep 17 00:00:00 2001 From: Pavel Afremov Date: Wed, 29 Nov 2006 16:38:05 +0300 Subject: [PATCH] Fix of enumeration safety state inconsistence on exceptions call stacks. --- vm/vmcore/src/class_support/Initialize.cpp | 5 ++ vm/vmcore/src/exception/exceptions.cpp | 29 +++++++++--- vm/vmcore/src/exception/exceptions_impl.cpp | 63 +++++++++++++++++++++------ vm/vmcore/src/exception/exceptions_jit.cpp | 12 +++++ 4 files changed, 86 insertions(+), 23 deletions(-) diff --git a/vm/vmcore/src/class_support/Initialize.cpp b/vm/vmcore/src/class_support/Initialize.cpp old mode 100644 new mode 100755 index 9faa13c..cdd80bc --- a/vm/vmcore/src/class_support/Initialize.cpp +++ b/vm/vmcore/src/class_support/Initialize.cpp @@ -131,8 +131,13 @@ void Class::initialize() jthrowable p_error_object; assert(!hythread_is_suspend_enabled()); + // it's a safe poin so enviroment should be protected vm_execute_java_method_array((jmethodID) meth, 0, 0); + + // suspend can be enabeled in safe enviroment + tmn_suspend_enable(); p_error_object = exn_get(); + tmn_suspend_disable(); // --- step 9 ---------------------------------------------------------- TRACE2("class.init", "initializing class " << m_name->bytes << " STEP 9" ); diff --git a/vm/vmcore/src/exception/exceptions.cpp b/vm/vmcore/src/exception/exceptions.cpp old mode 100644 new mode 100755 index 99ee8ed..03bbd0c --- a/vm/vmcore/src/exception/exceptions.cpp +++ b/vm/vmcore/src/exception/exceptions.cpp @@ -49,6 +49,8 @@ bool exn_raised() //Find all usage and change to lazy use jthrowable exn_get() { + assert(hythread_is_suspend_enabled()); + // we can check heap references for equality to NULL // without disabling gc, because GC wouldn't change // null to non-null and vice versa. @@ -62,10 +64,10 @@ jthrowable exn_get() jobject exc; if (NULL != p_TLS_vmthread->thread_exception.exc_object) { - tmn_suspend_disable_recursive(); + tmn_suspend_disable(); exc = oh_allocate_local_handle(); exc->object = (ManagedObject *) p_TLS_vmthread->thread_exception.exc_object; - tmn_suspend_enable_recursive(); + tmn_suspend_enable(); } else if (NULL != p_TLS_vmthread->thread_exception.exc_class) { exc = exn_create((Exception*)&(p_TLS_vmthread->thread_exception)); } else { @@ -144,6 +146,7 @@ bool set_unwindable(bool unwindable) } jthrowable exn_create(Exception* exception) { + assert(hythread_is_suspend_enabled()); return create_exception(exception); } @@ -165,6 +168,7 @@ jthrowable exn_create(Class* exc_class, jthrowable exn_create(Class* exc_class, const char* exc_message, jthrowable exc_cause) { ASSERT_RAISE_AREA; + assert(hythread_is_suspend_enabled()); jthrowable exc_object = create_exception(exc_class, exc_message, exc_cause); if (exc_object == NULL) { @@ -196,6 +200,7 @@ jthrowable exn_create(const char* exc_na jthrowable exn_create(const char *exc_name, const char *exc_message, jthrowable cause) { ASSERT_RAISE_AREA; + assert(hythread_is_suspend_enabled()); Class *exc_class = get_exc_class(exc_name); if (exc_class == NULL) { @@ -206,12 +211,7 @@ jthrowable exn_create(const char *exc_na } // exn_create void exn_throw_object(jthrowable exc_object) { - assert(!hythread_is_suspend_enabled()); assert(is_unwindable()); - // XXX salikh: change to unconditional thread_disable_suspend() - // we use conditional until all of the VM - // is refactored to be definitely gc-safe. - exn_throw_object_internal(exc_object); } @@ -233,7 +233,6 @@ void exn_throw_by_class(Class* exc_class void exn_throw_by_class(Class* exc_class, const char* exc_message, jthrowable exc_cause) { - assert(!hythread_is_suspend_enabled()); assert(is_unwindable()); exn_throw_by_class_internal(exc_class, exc_message, exc_cause); @@ -257,7 +256,6 @@ void exn_throw_by_name(const char* exc_n void exn_throw_by_name(const char* exc_name, const char* exc_message, jthrowable exc_cause) { - assert(!hythread_is_suspend_enabled()); assert(is_unwindable()); exn_throw_by_name_internal(exc_name, exc_message, exc_cause); @@ -311,11 +309,13 @@ void exn_raise_by_name(const char* exc_n void exn_raise_by_name(const char* exc_name, const char* exc_message, jthrowable exc_cause) { + assert(hythread_is_suspend_enabled()); assert(!is_unwindable()); assert(exc_name); exn_raise_by_name_internal(exc_name, exc_message, exc_cause); } +// FIXME moove to exception_impl.cpp static void check_pop_frame(ManagedObject *exn) { if (exn == VM_Global_State::loader_env->popFrameException->object) { exn_clear(); @@ -327,8 +327,16 @@ static void check_pop_frame(ManagedObjec } } +// function can be cold from suspen enabled and disabled mode void exn_rethrow() { + // exception is throwing, so suspend can be disabeled without following enabling + if (hythread_is_suspend_enabled()) { + tmn_suspend_disable(); + } + + assert(!hythread_is_suspend_enabled()); + #ifndef VM_LAZY_EXCEPTION ManagedObject *exn = get_exception_object_internal(); assert(exn); @@ -355,6 +363,7 @@ #else exc_cause->object = p_TLS_vmthread->thread_exception.exc_cause; } clear_exception_internal(); + exn_throw_by_class_internal(exc_class, exc_message, exc_cause); } else { DIE(("There is no exception.")); @@ -377,6 +386,7 @@ #define STF_AS_JLONG 5 // prints stackTrace via java inline void exn_java_print_stack_trace(FILE * UNREF f, jthrowable exc) { + assert(hythread_is_suspend_enabled()); // finds java environment JNIEnv *jenv = p_TLS_vmthread->jni_env; @@ -539,6 +549,7 @@ inline void exn_jni_print_stack_trace(FI inline void exn_native_print_stack_trace(FILE * f, ManagedObject * exn) { //Afremov Pavel 20050119 Should be changed when classpath will raplaced by DRL + assert(hythread_is_suspend_enabled()); assert(gid_throwable_traceinfo); // ? 20030428: This code should be elsewhere! diff --git a/vm/vmcore/src/exception/exceptions_impl.cpp b/vm/vmcore/src/exception/exceptions_impl.cpp old mode 100644 new mode 100755 index a7dc9b2..142333a --- a/vm/vmcore/src/exception/exceptions_impl.cpp +++ b/vm/vmcore/src/exception/exceptions_impl.cpp @@ -72,6 +72,7 @@ static Method* prepare_exc_creating(Clas // cause can be null static Method* prepare_exc_creating(Class* exc_class, jvalue* args) { ASSERT_RAISE_AREA; + assert(hythread_is_suspend_enabled()); // Finds corresponding constructor Method* exc_init = lookup_exc_constructor(exc_class, "()V"); @@ -88,6 +89,7 @@ static Method* prepare_exc_creating(Clas static Method* prepare_exc_creating(Class* exc_class, jvalue* args, jthrowable exc_cause) { ASSERT_RAISE_AREA; + assert(hythread_is_suspend_enabled()); // Checks that it's corresponding method if (NULL == exc_cause) { @@ -112,6 +114,7 @@ static Method* prepare_exc_creating(Clas static Method* prepare_exc_creating(Class* exc_class, jvalue* args, const char* exc_message) { ASSERT_RAISE_AREA; + assert(hythread_is_suspend_enabled()); // Checks that it's corresponding method if (NULL == exc_message) { @@ -127,7 +130,7 @@ static Method* prepare_exc_creating(Clas } // Creates string object - tmn_suspend_disable_recursive(); + tmn_suspend_disable(); ManagedObject *arg_obj = string_create_from_utf8(exc_message, (unsigned) strlen(exc_message)); @@ -139,7 +142,7 @@ static Method* prepare_exc_creating(Clas jobject arg = oh_allocate_local_handle(); arg->object = arg_obj; - tmn_suspend_enable_recursive(); + tmn_suspend_enable(); // Fills arguments for constructor args[1].l = arg; @@ -151,6 +154,7 @@ static Method* prepare_exc_creating(Clas static Method* prepare_exc_creating(Class* exc_class, jvalue* args, const char* exc_message, jthrowable exc_cause) { ASSERT_RAISE_AREA; + assert(hythread_is_suspend_enabled()); // Checks that it's corresponding method if (NULL == exc_message) { @@ -196,12 +200,9 @@ static Method* prepare_exc_creating(Clas void init_cause(jthrowable exc_object, jthrowable exc_cause) { ASSERT_RAISE_AREA; assert(exc_cause); + assert(hythread_is_suspend_enabled()); - bool suspended_enabled = hythread_is_suspend_enabled(); - - if (suspended_enabled) { - tmn_suspend_disable(); - } + tmn_suspend_disable(); Class* exc_class = exc_object->object->vt()->clss; Method *init_cause_method = class_lookup_method_recursive(exc_class, @@ -213,10 +214,7 @@ void init_cause(jthrowable exc_object, j jvalue ret_val; vm_execute_java_method_array((jmethodID) init_cause_method, &ret_val, args); - - if (suspended_enabled) { - tmn_suspend_enable(); - } + tmn_suspend_enable(); if (exn_raised()) { DIE(("Exception constructor has thrown an exception")); @@ -225,6 +223,7 @@ void init_cause(jthrowable exc_object, j jthrowable create_exception(Class* exc_class, Method* exc_init, jvalue* args) { ASSERT_RAISE_AREA; + assert(hythread_is_suspend_enabled()); bool suspended_enabled = hythread_is_suspend_enabled(); @@ -255,6 +254,8 @@ jthrowable create_exception(Class* exc_c jthrowable create_exception(Class* exc_class, const char* exc_message, jthrowable exc_cause) { + ASSERT_RAISE_AREA; + assert(hythread_is_suspend_enabled()); jvalue args[3]; Method *exc_init = prepare_exc_creating(exc_class, args, exc_message, exc_cause); @@ -274,6 +275,8 @@ jthrowable create_exception(Class* exc_c jthrowable create_exception(Exception* exception) { ASSERT_RAISE_AREA; + assert(hythread_is_suspend_enabled()); + if ( NULL != exception->exc_class) { jthrowable exc_cause = NULL; Class* exc_class = exception->exc_class; @@ -286,7 +289,10 @@ jthrowable create_exception(Exception* e tmn_suspend_enable_recursive(); } exn_clear(); - return exn_create(exc_class, exc_message, exc_cause); + + jthrowable exc_exception = NULL; + exc_exception = exn_create(exc_class, exc_message, exc_cause); + return exc_exception; } else { return NULL; } @@ -294,6 +300,11 @@ jthrowable create_exception(Exception* e void exn_throw_object_internal(jthrowable exc_object) { + // functions can be invoked in suspend disabled and enabled state + if (hythread_is_suspend_enabled()) { + tmn_suspend_disable(); + } + assert(!hythread_is_suspend_enabled()); TRACE2("exn", ("%s", "exn_throw_object(), delegating to exn_throw_for_JIT()")); exn_throw_for_JIT(exc_object->object, NULL, NULL, NULL, NULL); } @@ -301,6 +312,12 @@ void exn_throw_object_internal(jthrowabl void exn_throw_by_class_internal(Class* exc_class, const char* exc_message, jthrowable exc_cause) { + // functions can be invoked in suspend disabled and enabled state + if (!hythread_is_suspend_enabled()) { + // exception is throwing, so suspend can be enabled safely + tmn_suspend_enable(); + } + assert(hythread_is_suspend_enabled()); #ifdef VM_LAZY_EXCEPTION set_unwindable(false); @@ -318,7 +335,11 @@ #ifdef VM_LAZY_EXCEPTION } else { TRACE2("exn", ("%s", "exn_throw_by_class(), lazy delegating to exn_throw_for_JIT()")); set_unwindable(true); + + // no return, so enable isn't required + tmn_suspend_disable(); exn_throw_for_JIT(NULL, exc_class, exc_init, NULL, args); + //tmn_suspend_enable(); } #else set_unwindable(false); @@ -328,9 +349,15 @@ #else exn_throw_object_internal(exc_object); #endif } + void exn_throw_by_name_internal(const char* exc_name, const char* exc_message, jthrowable exc_cause) { + // functions can be invoked in suspend disabled and enabled state + if (!hythread_is_suspend_enabled()) { + // exception is throwing, so suspend can be enabled safely + tmn_suspend_enable(); + } assert(hythread_is_suspend_enabled()); set_unwindable(false); Class *exc_class = get_exc_class(exc_name); @@ -393,27 +420,37 @@ void exn_raise_by_name_internal(const ch exn_raise_by_class_internal(exc_class, exc_message, exc_cause); } +// function should be called in disable mode void __stdcall clear_exception_internal() { + assert(!hythread_is_suspend_enabled()); p_TLS_vmthread->thread_exception.exc_object = NULL; p_TLS_vmthread->thread_exception.exc_class = NULL; p_TLS_vmthread->thread_exception.exc_cause = NULL; p_TLS_vmthread->thread_exception.exc_message = NULL; -} +} // clear_exception_internal +// function should be called in disable mode void __stdcall set_exception_object_internal(ManagedObject * exc) { assert(!hythread_is_suspend_enabled()); p_TLS_vmthread->thread_exception.exc_object = exc; } // set_exc_object_internal +// function is safe point & should be called in disable mode in safe enviroment ManagedObject* __stdcall get_exception_object_internal() { + assert(!hythread_is_suspend_enabled()); if (NULL != p_TLS_vmthread->thread_exception.exc_object) { return p_TLS_vmthread->thread_exception.exc_object; } else if (NULL != p_TLS_vmthread->thread_exception.exc_class) { Exception* exception = (Exception*)&(p_TLS_vmthread->thread_exception); + + // suspend can be enabeled in safe enviroment + tmn_suspend_enable(); jthrowable exc_object = create_exception(exception); + tmn_suspend_disable(); + return exc_object->object; } else { return NULL; diff --git a/vm/vmcore/src/exception/exceptions_jit.cpp b/vm/vmcore/src/exception/exceptions_jit.cpp old mode 100644 new mode 100755 index 9058e51..22ff04a --- a/vm/vmcore/src/exception/exceptions_jit.cpp +++ b/vm/vmcore/src/exception/exceptions_jit.cpp @@ -135,7 +135,8 @@ update_handler_address(NativeCodePtr new ////////////////////////////////////////////////////////////////////////// // Lazy Exception Utilities -// Note: Function runs from unwindable area +// Note: Function runs from unwindable area before exception throwing +// function can be safe point & should be called with disable reqursion = 1 static ManagedObject *create_lazy_exception( Class_Handle exn_class, Method_Handle exn_constr, @@ -150,9 +151,12 @@ static ManagedObject *create_lazy_except result = class_alloc_new_object_and_run_constructor( (Class*) exn_class, (Method*) exn_constr, exn_constr_args); } else { + // exception is throwing, so suspend can be enabled safely + tmn_suspend_enable(); jthrowable exc_object = create_exception( (Class*) exn_class, (Method*) exn_constr, vm_exn_constr_args); result = exc_object->object; + tmn_suspend_disable(); } set_unwindable(unwindable); exn_rethrow_if_pending(); @@ -174,6 +178,7 @@ static ManagedObject *create_lazy_except // The client should either use si_transfer_control to resume it, or use an OS context mechanism // copied from the final stack iterator. +// function can be safe point & should be called with disable reqursion = 1 static void exn_propagate_exception( StackIterator * si, ManagedObject ** exn_obj, @@ -383,6 +388,7 @@ static bool UNUSED is_gc_frame_before_m2 } #endif // _IPF_ +// function can be safe point & should be called with disable reqursion = 1 void exn_throw_for_JIT(ManagedObject* exn_obj, Class_Handle exn_class, Method_Handle exn_constr, uint8* jit_exn_constr_args, jvalue* vm_exn_constr_args) { @@ -433,9 +439,11 @@ #endif // _IPF_ // Exception defined as in previous function. // Does not return. +// function can be safe point & should be called with disable reqursion = 1 void exn_athrow(ManagedObject* exn_obj, Class_Handle exn_class, Method_Handle exn_constr, uint8* exn_constr_args) { + assert(!hythread_is_suspend_enabled()); exn_throw_for_JIT(exn_obj, exn_class, exn_constr, exn_constr_args, NULL); } @@ -445,8 +453,10 @@ void exn_athrow(ManagedObject* exn_obj, // Exception defined as in previous two functions. // Mutates the regs value, which should be used to "resume" the managed code. +// function can be safe point & should be called with disable reqursion = 1 void exn_athrow_regs(Registers * regs, Class_Handle exn_class, bool java_code) { + assert(!hythread_is_suspend_enabled()); assert(exn_class); #ifndef _IPF_ M2nFrame *m2nf; -- 1.4.1