summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-07-14 07:19:59 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-07-14 07:19:59 +0000
commit0886a4d8a06a609445f04351dc1e899dd59a3678 (patch)
treefa5e3212221e0ba4d8b8641d7f122e3660541b22
parenta5941516685eac751193ea88424be5588698b2c7 (diff)
* 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
-rw-r--r--ChangeLog16
-rw-r--r--configure.in4
-rw-r--r--cont.c2
-rw-r--r--gc.c103
-rw-r--r--gc.h7
-rw-r--r--thread.c4
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 <akr@fsij.org>
+
+ * 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 <nobu@ruby-lang.org>
* 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 <windows.h>
#endif
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+# include <valgrind/memcheck.h>
+# 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