From nobody Mon Sep 17 00:00:00 2001 From: Vera Volynets Date: Wed, 19 Jul 2006 19:25:34 +0400 Subject: [PATCH] Checks correctness of write barriers work. Run with option -Dvm.verify.wb=true and with enabled interpreter: -Dvm.use_interpreter=true. --- 9df7bfcf24b8d4f9b9b340abe2c6ccf346b3ac5f vm/vmcore/include/environment.h | 2 vm/vmcore/include/gc_debug.h | 2 vm/vmcore/src/gc/gc_debug.cpp | 109 +++++++++++++++++++++ vm/vmcore/src/gc/stop_the_world_root_set_enum.cpp | 10 ++ vm/vmcore/src/init/vm.cpp | 2 vm/vmcore/src/init/vm_main.cpp | 9 ++ 6 files changed, 129 insertions(+), 5 deletions(-) mode change 100644 => 100755 vm/vmcore/src/gc/stop_the_world_root_set_enum.cpp mode change 100644 => 100755 vm/vmcore/src/init/vm.cpp mode change 100644 => 100755 vm/vmcore/src/init/vm_main.cpp 9df7bfcf24b8d4f9b9b340abe2c6ccf346b3ac5f diff --git a/vm/vmcore/include/environment.h b/vm/vmcore/include/environment.h index a77efe1..ef6aae1 100755 --- a/vm/vmcore/include/environment.h +++ b/vm/vmcore/include/environment.h @@ -53,7 +53,7 @@ struct Global_Env { bool verify_all; // psrebriy 20050815 Verify all classes including loaded by bootstrap class loader bool pin_interned_strings; // if true, interned strings are never moved bool debug_gc; // if true, trace the heap before and after stop-the-world phases - + bool debug_gc_wb; // if true, check correctness of write barriers work // // preloaded strings // diff --git a/vm/vmcore/include/gc_debug.h b/vm/vmcore/include/gc_debug.h index abb46f5..f96447c 100755 --- a/vm/vmcore/include/gc_debug.h +++ b/vm/vmcore/include/gc_debug.h @@ -20,5 +20,7 @@ #define _DEBUG_GC_H void debug_gc_setup(); void debug_gc_trace_heap(bool); void debug_gc_enumerate_roots(void); +void debug_check_wb(bool); +void debug_gc_write_barriers_init(); #endif // _DEBUG_GC_H diff --git a/vm/vmcore/src/gc/gc_debug.cpp b/vm/vmcore/src/gc/gc_debug.cpp index e34f42c..90d46a1 100755 --- a/vm/vmcore/src/gc/gc_debug.cpp +++ b/vm/vmcore/src/gc/gc_debug.cpp @@ -44,6 +44,9 @@ static bool debug_gc_verify; byte *mark_bits; unsigned mark_bits_size; unsigned gc_number = 0; +int *heap_mirror; +bool debug_wb = false; +bool check_wb = false; #define OBJECT_ALIGNMENT_DOUBLE 8 #define ALIGN(x, alignment) ((((pint)(x)) + alignment - 1) & (~(alignment-1))) @@ -76,6 +79,9 @@ struct Object_Print { static void (*real_gc_add_root_set_entry)(Managed_Object_Handle* root, Boolean pinned); static void (*real_gc_add_finalizable_root_set_entry)(Managed_Object_Handle* root, Boolean pinned); static void (*real_gc_class_prepared)(Class_Handle, VTable_Handle); +static void (*real_gc_write_barrier)(Managed_Object_Handle); +static void (*real_gc_heap_write_ref)(Managed_Object_Handle, unsigned, Managed_Object_Handle); +static void (*real_gc_heap_slot_write_ref)(Managed_Object_Handle, Managed_Object_Handle *, Managed_Object_Handle); static std::map infomap; static std::vector debug_root_set; @@ -247,6 +253,27 @@ void initialize_global_variables() { live_finalizable_bytes = 0; } +static int *get_mirror(Object **slot) { + TRACE2("debug.wb" , "number of mirror is: " << slot - (Object **)gc_heap_base_address() ); + return (int *)(heap_mirror + (slot - (Object **)gc_heap_base_address())); +} + +static void mirror_slot(Object *base, Object **slot, bool check) { + int *mirror =get_mirror(slot); + assert(base != NULL); + TRACE2("debug.wb","slot: " << slot << " value: " << (void *)*slot << " slot from heap_mirror: " << (void *)*mirror); + if (check) { + Object *obj = base; + Object_Info *oi = obj_oi(obj); + assert(oi != NULL); + if (*mirror != (int)*slot) { + DIE2("debug.wb", "write barrier for class: "<< oi->name<< " base: " << base << " *slot: "<< *slot << " worked incorrectly!"); + }else {} + }else { + *mirror = (int)*slot; + } +} + static void trace(Object *obj) { TRACE2("debug.obj", "object to trace: " << obj); @@ -259,6 +286,9 @@ trace(Object *obj) { int i; byte** elem = (byte**)((byte*)obj + 12); for (i = 0; i < len; i++, elem += 1){ + if(debug_wb) { + mirror_slot(obj, (Object **)elem, check_wb); + } if (NULL == *elem) continue; if(mark_object(*elem)) { TRACE2("debug.obj", "object " << (void*)obj << " points to " << (void*)*elem); @@ -269,6 +299,9 @@ trace(Object *obj) { int* poff; for (poff = oi->offsets; *poff; poff++) { byte** field = (byte**) ((byte*)obj + *poff); + if(debug_wb) { + mirror_slot(obj, (Object **)field, check_wb); + } if (NULL == *field) continue; TRACE2("debug.obj", "poff " << poff << " *poff " << *poff); TRACE2("debug.obj", "field " << (void*)field << " points to " << (void*)*field); @@ -415,3 +449,76 @@ void debug_gc_enumerate_roots() { INFO2("gc.debug", fin_root_number << " finalizable roots passed down to real GC"); } + +static void +wb(Object *obj) { + Object_Info * oi= obj_oi(obj); + if (!oi->has_slots) return; + if(oi->is_array) { + int length = array_length(obj); + byte** elem = (byte**)((byte*)obj + 12); + for (int i = 0; i < length; i++, elem += 1) { + mirror_slot(obj, (Object **)elem, false); + } + return; + } + //obj is not array, run through object fields + int* poff; + for (poff = oi->offsets; *poff; poff++) { + byte** field = (byte**) ((byte*)obj + *poff); + mirror_slot(obj,(Object **) field, false); + } +} + +static void +wb(Object **slot, Object *obj) { + int *mirror = get_mirror(slot); + TRACE2("debug.wb", "slot: " << slot << " obj value: " << obj << " from heap_mirror before init: " << (void *)*mirror); + *mirror = (int) obj; +} + +static void +subs_gc_write_barrier(Managed_Object_Handle p) { + TRACE2("debug.wb", "*subs_gc_write_barrier*"); + Object *obj = (Object *)p; + wb(obj); + real_gc_write_barrier(p); +} + +static void +subs_gc_heap_write_ref(Managed_Object_Handle p_base, unsigned offset, Managed_Object_Handle value) { + TRACE2("debug.wb", "*subs_gc_heap_write_ref*"); + assert(p_base != NULL); + Managed_Object_Handle *p_slot = (Managed_Object_Handle *)(((char *)p_base) + offset); + *p_slot = value; + wb((Object **)p_slot, (Object *) value); + real_gc_heap_write_ref(p_base, offset, value); +} + +static void +subs_gc_heap_slot_write_ref(Managed_Object_Handle p_base, Managed_Object_Handle *p_slot, Managed_Object_Handle value) { + TRACE2("debug.wb", "*subs_gc_heap_slot_write_ref*"); + assert (p_base != NULL); + *p_slot = value; + wb((Object **)p_slot, (Object *)value); + real_gc_heap_slot_write_ref(p_base, p_slot, value); +} + +void debug_check_wb(bool check) { + check_wb = check; +} + +void debug_gc_write_barriers_init(){ + //free(heap_mirror); + heap_mirror = (int *)malloc((pint)gc_heap_ceiling_address() - (pint)gc_heap_base_address()); + memset(heap_mirror, 0, (pint)gc_heap_ceiling_address() - (pint)gc_heap_base_address()); + debug_wb = true; + + // substitute gc functions + real_gc_write_barrier = gc_write_barrier; + gc_write_barrier = subs_gc_write_barrier; + real_gc_heap_write_ref = gc_heap_write_ref; + gc_heap_write_ref = subs_gc_heap_write_ref; + real_gc_heap_slot_write_ref = gc_heap_slot_write_ref; + gc_heap_slot_write_ref = subs_gc_heap_slot_write_ref; +} 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 old mode 100644 new mode 100755 index 65d287a..0504b6e --- a/vm/vmcore/src/gc/stop_the_world_root_set_enum.cpp +++ b/vm/vmcore/src/gc/stop_the_world_root_set_enum.cpp @@ -146,7 +146,10 @@ vm_enumerate_root_set_all_threads() assert(!tmn_is_suspend_enabled()); // vm_gc_unlock_enum expects suspend enabled, enable it here - if (VM_Global_State::loader_env->debug_gc ) { + if (VM_Global_State::loader_env->debug_gc || VM_Global_State::loader_env->debug_gc_wb) { + if (VM_Global_State::loader_env->debug_gc_wb) { + debug_check_wb(true); + } debug_gc_trace_heap(false); debug_gc_enumerate_roots(); } @@ -158,7 +161,10 @@ void vm_resume_threads_after() { TRACE2("vm.gc", "vm_resume_threads_after()"); // Check that we are still enumerating the universe and formally mark the end of it. - if (VM_Global_State::loader_env->debug_gc ) { + if (VM_Global_State::loader_env->debug_gc || VM_Global_State::loader_env->debug_gc_wb ) { + if (VM_Global_State::loader_env->debug_gc_wb) { + debug_check_wb(false); + } debug_gc_trace_heap(true); } assert(get_global_safepoint_status() == enumerate_the_universe); diff --git a/vm/vmcore/src/init/vm.cpp b/vm/vmcore/src/init/vm.cpp old mode 100644 new mode 100755 index 049f541..399a165 --- a/vm/vmcore/src/init/vm.cpp +++ b/vm/vmcore/src/init/vm.cpp @@ -253,6 +253,8 @@ #endif // PLATFORM_POSIX true, FALSE}, {"vm.verify.gc", "Turn on gc_debug.", true, FALSE}, + {"vm.verify.wb", "Turn on write barriers debugging.", + true, FALSE}, // Non-boolean properties below. (sorted for convenience) {"vm.boot.library.path", "List of directories which contain additional dynamic libraries to load into VM"}, {"vm.boot.class.path", "Virtual machine bootclasspath"}, diff --git a/vm/vmcore/src/init/vm_main.cpp b/vm/vmcore/src/init/vm_main.cpp old mode 100644 new mode 100755 index b057f4b..427f1bd --- a/vm/vmcore/src/init/vm_main.cpp +++ b/vm/vmcore/src/init/vm_main.cpp @@ -357,6 +357,8 @@ #endif (bool)vm_get_property_value_boolean("vm.pin_interned_strings", FALSE); VM_Global_State::loader_env->debug_gc = (bool)vm_get_property_value_boolean("vm.verify.gc", FALSE); + VM_Global_State::loader_env->debug_gc_wb = + (bool)vm_get_property_value_boolean("vm.verify.wb", FALSE); initialize_verify_stack_enumeration(); @@ -385,9 +387,14 @@ #endif // _WINDOWS // Initialize memory allocation vm_init_mem_alloc(); gc_init(); - if (VM_Global_State::loader_env->debug_gc) { + + if (VM_Global_State::loader_env->debug_gc || VM_Global_State::loader_env->debug_gc_wb) { debug_gc_setup(); } + if (VM_Global_State::loader_env->debug_gc_wb) { + debug_gc_write_barriers_init(); + debug_check_wb(false); + } gc_thread_init(&p_TLS_vmthread->_gc_private_information); -- 1.3.GIT