From 0886a4d8a06a609445f04351dc1e899dd59a3678 Mon Sep 17 00:00:00 2001 From: akr Date: Sat, 14 Jul 2007 07:19:59 +0000 Subject: * configure.in: add --enable-valgrind. * gc.h (SET_MACHINE_STACK_END): new macro to replace rb_gc_set_stack_end. it find out accurate stack boundary by asm using gcc on x86. * thread.c (rb_gc_set_stack_end): don't define if asm-version SET_MACHINE_STACK_END is available. * gc.c (mark_current_thread): extracted from garbage_collect. it use SET_MACHINE_STACK_END to not scan out of stack area. it notify conservative GC information to valgrind if --enable-valgrind. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12785 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 16 ++++++++++ configure.in | 4 +++ cont.c | 2 +- gc.c | 103 ++++++++++++++++++++++++++++++++++++++++++++--------------- gc.h | 7 ++++ thread.c | 4 ++- 6 files changed, 108 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index 96d271efb7..60b47c6485 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +Sat Jul 14 16:11:24 2007 Tanaka Akira + + * configure.in: add --enable-valgrind. + + * gc.h (SET_MACHINE_STACK_END): new macro to replace + rb_gc_set_stack_end. it find out accurate stack boundary by + asm using gcc on x86. + + * thread.c (rb_gc_set_stack_end): don't define if asm-version + SET_MACHINE_STACK_END is available. + + * gc.c (mark_current_thread): extracted from garbage_collect. + it use SET_MACHINE_STACK_END to not scan out of stack area. + it notify conservative GC information to valgrind if + --enable-valgrind. + Sat Jul 14 14:04:06 2007 Nobuyoshi Nakada * enum.c (sort_by_cmp): check if reentered. [ruby-dev:24291] diff --git a/configure.in b/configure.in index 741bfd9222..95daff2379 100644 --- a/configure.in +++ b/configure.in @@ -873,6 +873,10 @@ fi AC_CHECK_FUNCS(backtrace) +AC_ARG_ENABLE(valgrind, + [ --enable-valgrind enable valgrind memcheck support.], + [AC_CHECK_HEADERS(valgrind/memcheck.h)]) + dnl default value for $KANJI DEFAULT_KCODE="KCODE_NONE" diff --git a/cont.c b/cont.c index 2924810b53..8d0d201540 100644 --- a/cont.c +++ b/cont.c @@ -97,7 +97,7 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont) int size; rb_thread_t *sth = &cont->saved_thread; - rb_gc_set_stack_end(&th->machine_stack_end); + SET_MACHINE_STACK_END(&th->machine_stack_end); #ifdef __ia64 th->machine_register_stack_end = rb_ia64_bsp(); #endif diff --git a/gc.c b/gc.c index b4240c0229..65f1a4f9bb 100644 --- a/gc.c +++ b/gc.c @@ -35,6 +35,15 @@ #include #endif +#ifdef HAVE_VALGRIND_MEMCHECK_H +# include +# ifndef VALGRIND_MAKE_MEM_DEFINED +# define VALGRIND_MAKE_MEM_DEFINED(p, n) VALGRIND_MAKE_READABLE(p, n) +# endif +#else +# define VALGRIND_MAKE_MEM_DEFINED(p, n) /* empty */ +#endif + int rb_io_fptr_finalize(struct rb_io_t*); #if !defined(setjmp) && defined(HAVE__SETJMP) @@ -558,9 +567,9 @@ rb_data_object_alloc(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_F } #ifdef __ia64 -#define SET_STACK_END (rb_gc_set_stack_end(&th->machine_stack_end), th->machine_register_stack_end = rb_ia64_bsp()) +#define SET_STACK_END (SET_MACHINE_STACK_END(&th->machine_stack_end), th->machine_register_stack_end = rb_ia64_bsp()) #else -#define SET_STACK_END rb_gc_set_stack_end(&th->machine_stack_end) +#define SET_STACK_END SET_MACHINE_STACK_END(&th->machine_stack_end) #endif #define STACK_START (th->machine_stack_start) @@ -733,6 +742,7 @@ mark_locations_array(register VALUE *x, register long n) VALUE v; while (n--) { v = *x; + VALGRIND_MAKE_MEM_DEFINED(&v, sizeof(v)); if (is_pointer_to_heap((void *)v)) { gc_mark(v, 0); } @@ -1366,11 +1376,74 @@ int rb_setjmp (rb_jmp_buf); void rb_vm_mark(void *ptr); +void +mark_current_thread(rb_thread_t *th) +{ + jmp_buf save_regs_gc_mark; + VALUE *stack_start, *stack_end; + + SET_STACK_END; +#if STACK_GROW_DIRECTION < 0 + stack_start = th->machine_stack_end; + stack_end = th->machine_stack_start; +#elif STACK_GROW_DIRECTION > 0 + stack_start = th->machine_stack_start; + stack_end = th->machine_stack_end + 1; +#else + if (th->machine_stack_end < th->machine_stack_start) { + stack_start = th->machine_stack_end; + stack_end = th->machine_stack_start; + } + else { + stack_start = th->machine_stack_start; + stack_end = th->machine_stack_end + 1; + } +#endif + + FLUSH_REGISTER_WINDOWS; + /* This assumes that all registers are saved into the jmp_buf (and stack) */ + setjmp(save_regs_gc_mark); + + { + struct { VALUE *start; VALUE *end; } regions[] = { + { (VALUE*)save_regs_gc_mark, + (VALUE*)save_regs_gc_mark + + sizeof(save_regs_gc_mark) / sizeof(VALUE *) }, + { stack_start, stack_end } +#ifdef __ia64 + , { th->machine_register_stack_start, + th->machine_register_stack_end } +#endif +#if defined(__human68k__) || defined(__mc68000__) + , { (VALUE*)((char*)STACK_END + 2), + (VALUE*)((char*)STACK_START + 2) } +#endif + }; + int i; + for (i = 0; i < sizeof(regions)/sizeof(*regions); i++) { + /* stack scanning code is inlined here + * because function call grows stack. + * don't call mark_locations_array, + * rb_gc_mark_locations, etc. */ + VALUE *x, n, v; + x = regions[i].start; + n = regions[i].end - x; + while (n--) { + v = *x; + VALGRIND_MAKE_MEM_DEFINED(&v, sizeof(v)); + if (is_pointer_to_heap((void *)v)) { + gc_mark(v, 0); + } + x++; + } + } + } +} + static int garbage_collect(void) { struct gc_list *list; - jmp_buf save_regs_gc_mark; rb_thread_t *th = GET_THREAD(); if (GC_NOTIFY) printf("start garbage_collect()\n"); @@ -1397,30 +1470,8 @@ garbage_collect(void) mark_tbl(finalizer_table, 0); } - FLUSH_REGISTER_WINDOWS; - /* This assumes that all registers are saved into the jmp_buf (and stack) */ - setjmp(save_regs_gc_mark); - mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *)); + mark_current_thread(th); -#if STACK_GROW_DIRECTION < 0 - rb_gc_mark_locations(th->machine_stack_end, th->machine_stack_start); -#elif STACK_GROW_DIRECTION > 0 - rb_gc_mark_locations(th->machine_stack_start, th->machine_stack_end + 1); -#else - if (th->machine_stack_end < th->machine_stack_start) - rb_gc_mark_locations(th->machine_stack_end, th->machine_stack_start); - else - rb_gc_mark_locations(th->machine_stack_start, th->machine_stack_end + 1); -#endif -#ifdef __ia64 - /* mark backing store (flushed register stack) */ - /* the basic idea from guile GC code */ - rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end); -#endif -#if defined(__human68k__) || defined(__mc68000__) - rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2), - (VALUE*)((char*)STACK_START + 2)); -#endif rb_gc_mark_threads(); rb_gc_mark_symbols(); diff --git a/gc.h b/gc.h index b0598131a0..c184409027 100644 --- a/gc.h +++ b/gc.h @@ -2,7 +2,14 @@ #ifndef RUBY_GC_H #define RUBY_GC_H 1 +#if defined(__i386) && defined(__GNUC__) +#define SET_MACHINE_STACK_END(p) __asm__("mov %%esp, %0" : "=r" (*p)) +#else NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p)); +#define SET_MACHINE_STACK_END(p) rb_gc_set_stack_end(p) +#define USE_CONSERVATIVE_STACK_END +#endif + NOINLINE(void rb_gc_save_machine_context(rb_thread_t *)); /* for GC debug */ diff --git a/thread.c b/thread.c index c38130ffff..4a71ced1fe 100644 --- a/thread.c +++ b/thread.c @@ -1811,17 +1811,19 @@ rb_thread_select(int max, fd_set * read, fd_set * write, fd_set * except, * for GC */ +#ifdef USE_CONSERVATIVE_STACK_END void rb_gc_set_stack_end(VALUE **stack_end_p) { VALUE stack_end; *stack_end_p = &stack_end; } +#endif void rb_gc_save_machine_context(rb_thread_t *th) { - rb_gc_set_stack_end(&th->machine_stack_end); + SET_MACHINE_STACK_END(&th->machine_stack_end); #ifdef __ia64 th->machine_register_stack_end = rb_ia64_bsp(); #endif -- cgit v1.2.3