From nobody Mon Sep 17 00:00:00 2001 From: Pavel Afremov Date: Fri, 17 Nov 2006 21:19:34 +0300 Subject: [PATCH] Fix for fake circularity error. This error can happen during compilation, by interaction of JIT, ClassLoader, GC and reference enqueue system. Fix contains following changes: - added preload of InternalError class. - reference enqueue system switched to finalizer scheme. - Work balance subsystem turned off for GC in JIT compilation frame (FRAME_COMPILATION). --- vm/vmcore/include/environment.h | 5 - vm/vmcore/include/finalize.h | 2 vm/vmcore/src/class_support/Environment.cpp | 3 vm/vmcore/src/gc/stop_the_world_root_set_enum.cpp | 4 - vm/vmcore/src/init/finalize.cpp | 136 +++++++++++++++++--- vm/vmcore/src/init/vm_init.cpp | 29 ++-- .../native/java_lang_FinalizerThread.cpp | 4 + 7 files changed, 139 insertions(+), 44 deletions(-) mode change 100644 => 100755 vm/vmcore/src/init/finalize.cpp mode change 100644 => 100755 vm/vmcore/src/init/vm_init.cpp e1a91c304bfdaa2cc64b16c1c43a8ca67498a431 diff --git a/vm/vmcore/include/environment.h b/vm/vmcore/include/environment.h index 983ffbb..4b3d719 100644 --- a/vm/vmcore/include/environment.h +++ b/vm/vmcore/include/environment.h @@ -167,6 +167,7 @@ struct Global_Env { Class* java_lang_ArithmeticException_Class; Class* java_lang_ClassCastException_Class; Class* java_lang_OutOfMemoryError_Class; + Class* java_lang_InternalError_Class; ObjectHandle java_lang_OutOfMemoryError; ObjectHandle java_lang_ThreadDeathError; // object of java.lang.Error class used for JVMTI JIT PopFrame support @@ -184,10 +185,8 @@ struct Global_Env { Class* java_lang_reflect_Field_Class; Class* java_lang_reflect_Method_Class; - Class* finalizer_thread; + Class* java_lang_FinalizerThread_Class; // pointers to 2 static fields in FinalizerThread class. - jboolean* finalizer_shutdown; - jboolean* finalizer_on_exit; Class* java_lang_EMThreadSupport_Class; // VTable for the java_lang_String class diff --git a/vm/vmcore/include/finalize.h b/vm/vmcore/include/finalize.h index e1a3a1a..af94211 100644 --- a/vm/vmcore/include/finalize.h +++ b/vm/vmcore/include/finalize.h @@ -41,12 +41,14 @@ #endif void vm_run_pending_finalizers(); int vm_do_finalization(int quantity); int vm_get_finalizable_objects_quantity(); +void vm_obtain_finalizer_fields(); #ifndef USE_GC_STATIC VMEXPORT #endif void vm_enumerate_objects_to_be_finalized(); void vm_enumerate_references_to_enqueue(); +int vm_get_references_quantity(); void vm_enqueue_references(); diff --git a/vm/vmcore/src/class_support/Environment.cpp b/vm/vmcore/src/class_support/Environment.cpp index 443617b..24b8ee2 100644 --- a/vm/vmcore/src/class_support/Environment.cpp +++ b/vm/vmcore/src/class_support/Environment.cpp @@ -148,10 +148,13 @@ #endif // !_IPF_ java_lang_ArithmeticException_Class = NULL; java_lang_ClassCastException_Class = NULL; java_lang_OutOfMemoryError_Class = NULL; + java_lang_InternalError_Class = NULL; java_lang_OutOfMemoryError = NULL; popFrameException = NULL; + java_lang_FinalizerThread_Class = NULL; + java_io_Serializable_Class = NULL; java_lang_Cloneable_Class = NULL; java_lang_Thread_Class = NULL; diff --git a/vm/vmcore/src/gc/stop_the_world_root_set_enum.cpp b/vm/vmcore/src/gc/stop_the_world_root_set_enum.cpp index d16fa4d..f377818 100644 --- a/vm/vmcore/src/gc/stop_the_world_root_set_enum.cpp +++ b/vm/vmcore/src/gc/stop_the_world_root_set_enum.cpp @@ -192,8 +192,8 @@ void vm_hint_finalize() { // *after* it releases global GC lock. // Several Reference Queues may need to be notified because the GC added References to them. Do that now. - LOG2("ref", "Enqueueing references"); - vm_enqueue_references(); + //LOG2("ref", "Enqueueing references"); + //vm_enqueue_references(); // For now we run the finalizers immediately in the context of the thread which requested GC. // Eventually we may have a different scheme, e.g., a dedicated finalize thread. diff --git a/vm/vmcore/src/init/finalize.cpp b/vm/vmcore/src/init/finalize.cpp old mode 100644 new mode 100755 index ed29405..d062e8c --- a/vm/vmcore/src/init/finalize.cpp +++ b/vm/vmcore/src/init/finalize.cpp @@ -27,10 +27,12 @@ #include #include "lock_manager.h" #include "object_layout.h" #include "open/types.h" +#include #include "Class.h" #include "open/vm_util.h" #include "environment.h" #include "ini.h" +#include "m2n.h" #include "exceptions.h" #include "compile.h" #include "nogc.h" @@ -112,15 +114,30 @@ class Objects_To_Finalize: public Object Class* CharsetEncoder; Class* FileDescriptor; Class* FileOutputStream; + + //jobject get_work_lock(); + //jboolean* get_work_lock(); + //jboolean* get_work_lock(); + bool fields_obtained; + void check_fields_obtained(); + Lock_Manager obtain_fields_lock; + jobject work_lock; + jboolean* shutdown; + jboolean* on_exit; public: Objects_To_Finalize() : Object_Queue("finalize") { classes_cached = false; + fields_obtained = false; + work_lock = NULL; + work_lock = NULL; + on_exit = NULL; }; // redefine of add method void add_object(ManagedObject *p_obj); void run_finalizers(); int do_finalization(int quantity); + void obtain_fields(); }; //Objects_To_Finalize class References_To_Enqueue: public Object_Queue @@ -251,7 +268,8 @@ void Object_Queue::enumerate_for_gc() void Objects_To_Finalize::add_object(ManagedObject *p_obj) { - Class* finalizer_thread = VM_Global_State::loader_env->finalizer_thread; + Class* finalizer_thread = + VM_Global_State::loader_env->java_lang_FinalizerThread_Class; if (!finalizer_thread) { return; @@ -299,40 +317,106 @@ bool Objects_To_Finalize::is_class_ignor || (test==FileOutputStream)); } +void Objects_To_Finalize::check_fields_obtained() { + if (!fields_obtained) { + obtain_fields(); + } +} + +void Objects_To_Finalize::obtain_fields() { + obtain_fields_lock._lock(); + + if (!fields_obtained) { + Class* finalizer_thread = + VM_Global_State::loader_env->java_lang_FinalizerThread_Class; + + if (!finalizer_thread) { + obtain_fields_lock._unlock(); + return; + } + + Field* work_lock_field = class_lookup_field_recursive( + finalizer_thread, + "workLock", "Ljava/lang/Object;"); + Field* shutdown_field = class_lookup_field_recursive( + finalizer_thread, + "shutdown", "Z"); + Field* on_exit_field = class_lookup_field_recursive( + finalizer_thread, + "onExit", "Z"); + + assert(work_lock_field); + assert(shutdown_field); + assert(on_exit_field); + + tmn_suspend_disable(); + ManagedObject* work_lock_addr = get_raw_reference_pointer( + (ManagedObject **)work_lock_field->get_address()); + assert(work_lock_addr); + work_lock = oh_allocate_global_handle(); + work_lock->object = work_lock_addr; + assert(work_lock); + tmn_suspend_enable(); + + shutdown = (jboolean*) shutdown_field->get_address(); + on_exit = (jboolean*) on_exit_field->get_address(); + assert(shutdown); + assert(on_exit); + + fields_obtained = true; + } + obtain_fields_lock._unlock(); +} + void Objects_To_Finalize::run_finalizers() { assert(hythread_is_suspend_enabled()); - Class* finalizer_thread = VM_Global_State::loader_env->finalizer_thread; + Class* finalizer_thread = + VM_Global_State::loader_env->java_lang_FinalizerThread_Class; if (!finalizer_thread) { return; } - int num_objects = getLength(); + check_fields_obtained(); + + int num_objects = getLength() + vm_get_references_quantity(); if (num_objects == 0) { - return; + //return; } if ((p_TLS_vmthread->finalize_thread_flags & (FINALIZER_STARTER | FINALIZER_THREAD)) != 0) { TRACE2("finalize", "recursive finalization prevented"); - return; + //return; } p_TLS_vmthread->finalize_thread_flags |= FINALIZER_STARTER; TRACE2("finalize", "run_finalizers() started"); - jvalue args[1]; - args[0].z = false; + if (FRAME_COMPILATION == + (FRAME_COMPILATION | m2n_get_frame_type(m2n_get_last_frame()))) { + assert(work_lock); - Method* finalize_meth = class_lookup_method_recursive(finalizer_thread, - "startFinalization", "(Z)V"); - assert(finalize_meth); + IDATA r = jthread_monitor_try_enter(work_lock); - tmn_suspend_disable(); - vm_execute_java_method_array((jmethodID) finalize_meth, 0, args); - tmn_suspend_enable(); + if (r == TM_ERROR_NONE) { + jthread_monitor_notify_all(work_lock); + jthread_monitor_exit(work_lock); + } + } else { + Method* finalize_meth = class_lookup_method_recursive(finalizer_thread, + "startFinalization", "(Z)V"); + assert(finalize_meth); + + jvalue args[1]; + args[0].z = false; + + tmn_suspend_disable(); + vm_execute_java_method_array((jmethodID) finalize_meth, 0, args); + tmn_suspend_enable(); + } if (exn_raised()) { INFO2("finalize", "Uncaught exception " @@ -354,16 +438,15 @@ int Objects_To_Finalize::do_finalization jvalue args[1]; args[0].l = (jobject) handle; - assert(VM_Global_State::loader_env->finalizer_thread); - jboolean* finalizer_shutdown = VM_Global_State::loader_env->finalizer_shutdown; - assert(finalizer_shutdown); - jboolean* finalizer_on_exit = VM_Global_State::loader_env->finalizer_on_exit; - assert(finalizer_on_exit); + assert(VM_Global_State::loader_env->java_lang_FinalizerThread_Class); + check_fields_obtained(); + assert(shutdown); + assert(on_exit); for (i=0; ((iobject->vt()->clss; assert(clss); - if ((*finalizer_on_exit) && is_class_ignored(clss)) { + if ((*on_exit) && is_class_ignored(clss)) { tmn_suspend_enable(); continue; } @@ -492,6 +575,11 @@ int vm_get_finalizable_objects_quantity( { return objects_to_finalize.getLength(); } + +void vm_obtain_finalizer_fields() { + objects_to_finalize.obtain_fields(); +} + // -- Code to deal with Reference Queues that need to be notified. static References_To_Enqueue references_to_enqueue; @@ -510,6 +598,12 @@ void vm_enqueue_reference(Managed_Object } // vm_enqueue_reference void vm_enqueue_references() -{ +{ references_to_enqueue.enqueue_references(); } //vm_enqueue_references + +int vm_get_references_quantity() +{ + return references_to_enqueue.getLength(); +} + diff --git a/vm/vmcore/src/init/vm_init.cpp b/vm/vmcore/src/init/vm_init.cpp old mode 100644 new mode 100755 index 91f0d23..c767b3f --- a/vm/vmcore/src/init/vm_init.cpp +++ b/vm/vmcore/src/init/vm_init.cpp @@ -45,6 +45,7 @@ #include "verify_stack_enumeration.h" #include "nogc.h" #include "vm_strings.h" #include "slot.h" +#include "finalize.h" #ifdef PLATFORM_NT // 20040427 Used to turn on heap checking on every allocation @@ -405,6 +406,8 @@ static jint preload_classes(Global_Env * preload_class(vm_env, "java/lang/ClassCastException"); vm_env->java_lang_OutOfMemoryError_Class = preload_class(vm_env, "java/lang/OutOfMemoryError"); + vm_env->java_lang_InternalError_Class = + preload_class(vm_env, "java/lang/InternalError"); vm_env->java_lang_Cloneable_Class = preload_class(vm_env, vm_env->Clonable_String); @@ -725,7 +728,9 @@ int vm_init1(JavaVM_Internal * java_vm, class_alloc_new_object_and_run_default_constructor(vm_env->java_lang_StackOverflowError_Class); // Precompile ThreadDeathError. class_alloc_new_object_and_run_default_constructor(vm_env->java_lang_ThreadDeathError_Class); - + // Precompile InternalError. + class_alloc_new_object_and_run_default_constructor(vm_env->java_lang_InternalError_Class); + hythread_suspend_enable(); // Mark j.l.Throwable() constructor as a side effects free. @@ -794,22 +799,12 @@ jint vm_init2(JNIEnv * jni_env) { if (vm_get_boolean_property_value_with_default("vm.finalize")) { // Load and initialize finalizer thread. - vm_env->finalizer_thread = preload_class(vm_env, "java/lang/FinalizerThread"); - assert(vm_env->finalizer_thread); - - Field * finalizer_shutdown_field = - class_lookup_field_recursive(vm_env->finalizer_thread, "shutdown", "Z"); - Field* finalizer_on_exit_field = - class_lookup_field_recursive(vm_env->finalizer_thread, "onExit", "Z"); - assert(finalizer_shutdown_field); - assert(finalizer_on_exit_field); - vm_env->finalizer_shutdown = (jboolean*) finalizer_shutdown_field->get_address(); - vm_env->finalizer_on_exit = (jboolean*) finalizer_on_exit_field->get_address(); - assert(vm_env->finalizer_shutdown); - assert(vm_env->finalizer_on_exit); - class_initialize_from_jni(vm_env->finalizer_thread); - } else { - vm_env->finalizer_thread = NULL; + vm_env->java_lang_FinalizerThread_Class = + preload_class(vm_env, "java/lang/FinalizerThread"); + assert(vm_env->java_lang_FinalizerThread_Class); + + class_initialize_from_jni(vm_env->java_lang_FinalizerThread_Class); + vm_obtain_finalizer_fields(); } TRACE("initialization of system classes completed"); diff --git a/vm/vmcore/src/kernel_classes/native/java_lang_FinalizerThread.cpp b/vm/vmcore/src/kernel_classes/native/java_lang_FinalizerThread.cpp index f345964..d13515f 100644 --- a/vm/vmcore/src/kernel_classes/native/java_lang_FinalizerThread.cpp +++ b/vm/vmcore/src/kernel_classes/native/java_lang_FinalizerThread.cpp @@ -59,6 +59,7 @@ JNIEXPORT jint JNICALL Java_java_lang_Fi JNIEXPORT jint JNICALL Java_java_lang_FinalizerThread_doFinalization (JNIEnv *, jclass, jint quantity) { + vm_enqueue_references(); return (jint) vm_do_finalization(quantity); } /** @@ -72,7 +73,8 @@ JNIEXPORT jint JNICALL Java_java_lang_Fi JNIEXPORT jint JNICALL Java_java_lang_FinalizerThread_getFinalizersQuantity (JNIEnv *, jclass) { - return (jint) vm_get_finalizable_objects_quantity(); + return (jint) vm_get_finalizable_objects_quantity() + + vm_get_references_quantity(); } /** -- 1.3.3