whoami7 - Manager
:
/
proc
/
self
/
root
/
usr
/
local
/
rvm
/
patches
/
ruby
/
1.8.7
/
p72
/
Upload File:
files >> //proc/self/root/usr/local/rvm/patches/ruby/1.8.7/p72/mbari7.patch
diff -ru ruby-1.8.7-p72/ChangeLog ruby-1.8.7-mbari/ChangeLog --- ruby-1.8.7-p72/ChangeLog 2009-02-09 21:21:30.000000000 -0800 +++ ruby-1.8.7-mbari/ChangeLog 2009-02-09 20:24:44.000000000 -0800 @@ -1,3 +1,126 @@ +Mon Feb 09 00:01:19 2009 Brent Roman <brent@mbari.org> + + * rubysig.h: default values for STACK_WIPE_SITES if x86_64 + cast builtin_alloca result to (VALUE *) + + * gc.c: don't use builtin-frame-address at all + + * version.h: bumped date + +Sun Feb 08 00:01:19 2009 Brent Roman <brent@mbari.org> + + * rubysig.h: changed default values for STACK_WIPE_SITES + + * gc.c: don't trust config's USE_BUILTIN_FRAME_ADDRESS + + * version.h: bumped date + + +Thu Jan 23 00:01:19 2009 Brent Roman <brent@mbari.org> + + * rubysig.h: remapped wipe methods to avoid values > 9 + added cases for __ppc64__ and __x86_64__ + + * missing/alloca.c: made 64-bit clean + + * version.h: bumped date + + +Sun Jan 18 20:15:36 2009 Brent Roman <brent@mbari.org> + + * rubysig.h: added support for STACK_WIPE_METHOD==5 (x86 asm) + + * gc.c: allow another STACK_WIPE_METHOD + + * version.h: bumped date + + +Sat Jan 17 20:15:36 2009 Brent Roman <brent@mbari.org> + + * gc.c: use separate gc stack so it never need be wiped + + * version.h: bumped date + + +Fri Jan 16 20:15:36 2009 Brent Roman <brent@mbari.org> + + * gc.c: added GC_STACK_PAD, renamed stack_gc_limit->gc_stack_limit + optionally wipe the entire GC stack after each gc pass + + * rubysig.h: default STACK_WIPE_SITES changed to 0x4770 + + * version.h: bumped date + + +Wed Jan 14 20:15:36 2009 Brent Roman <brent@mbari.org> + + * eval.c: declare wipe_after with gnu always_inline attribute + + * rubysig.h: use alloca(0) to get sp for all CPU except PowerPC + (less likely to trash stack when clearing it) + + * version.h: bumped date + + +Sun Jan 13 20:15:36 2009 Brent Roman <brent@mbari.org> + + * rubysig.h: moved #defs to configure alloca here from gc.c + added missing # to #else + + * gc.c: removed #defs to configurure alloca + set_stack_size must handle signed rlim_t for Darwin & BSD Unix + + * version.h: bumped date + + +Sun Jan 11 20:15:36 2009 Brent Roman <brent@mbari.org> + + * rubysig.h: added support for multiple STACK_WIPE_METHODs + added __stack_depth() + added 2nd param to stack_past() + __sp() returns stack pointer in an efficent, portable way + + * gc.c: STACK_END uses __sp() + STACK_UPPER now takes only two parameters + added rb_gc_wipe_stack() + rb_mark_tbl() and mark_hash() implemented as #define macros + added STACK_END parameters to __stack_past() invocations + exploited missed opportunities for tail recursion in markchilren + + * version.h: bumped date + + +Mon Jan 5 20:15:36 2009 Brent Roman <brent@mbari.org> + + * common.mk: added dependency on rubysig.h to version.h + + * eval.c: added wipeAfter and STACK_WIPE_SITES cofiguration options + + * gc.c: added STACK_WIPE_SITES cofiguration options + added GC.exorcise method + + * rubysig.h: added STACK_WIPE_SITES cofiguration options + when available, use gcc asm to optimize wipe_stack + + * version.h: include STACK_WIPE_SITES options in MBARI release string + + +Sun Jan 4 20:15:36 2009 Brent Roman <brent@mbari.org> + + * eval.c: eliminated up_stk_extent(), wipe_stack in rb_thread_switch + + * gc.c: removed lev counter args, check stack pointer instead + streamlined SET_STACK_END and STACK_END, stack_length(), etc. + added TOP_FRAME to use gcc's builtin frame_address + optimized is_heap_pointer() + gc_mark_rest() does not need to copy entire mark_stack! + added set_stack_size() to properly hande RLIM_INFINITY + + * rubysig.h: repaired broken pseudo preemptive thread switching + removed rb_gc_malloc_increase & limit + replaced buggy __stack_grown* with __stack_past* macros + + Tue Dec 19 20:15:36 2008 Brent Roman <brent@mbari.org> * eval.c: added (Method|Proc)#(__line__|__file__) methods diff -ru ruby-1.8.7-p72/common.mk ruby-1.8.7-mbari/common.mk --- ruby-1.8.7-p72/common.mk 2008-08-03 22:05:38.000000000 -0700 +++ ruby-1.8.7-mbari/common.mk 2009-01-05 01:18:37.000000000 -0800 @@ -462,7 +462,7 @@ {$(VPATH)}env.h {$(VPATH)}node.h {$(VPATH)}st.h {$(VPATH)}util.h version.$(OBJEXT): {$(VPATH)}version.c {$(VPATH)}ruby.h config.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ - {$(VPATH)}version.h + {$(VPATH)}rubysig.h {$(VPATH)}version.h dist: $(PROGRAM) $(RUNRUBY) $(srcdir)/distruby.rb diff -ru ruby-1.8.7-p72/eval.c ruby-1.8.7-mbari/eval.c --- ruby-1.8.7-p72/eval.c 2009-02-09 21:21:30.000000000 -0800 +++ ruby-1.8.7-mbari/eval.c 2009-01-22 02:54:08.000000000 -0800 @@ -3,7 +3,7 @@ eval.c - $Author: brent $ - $Date: 2008/12/20 07:47:22 $ + $Date: 2009/01/15 07:41:46 $ created at: Thu Jun 10 14:22:17 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto @@ -1028,14 +1028,26 @@ #define PROT_LAMBDA INT2FIX(2) /* 5 */ #define PROT_YIELD INT2FIX(3) /* 7 */ -#define EXEC_TAG() ruby_setjmp(((void)0), prot_tag->buf) - -static inline -int up_stk_extent(int status) +#if STACK_WIPE_SITES & 0x42 +#ifdef __GNUC__ +static inline int wipeAfter(int) __attribute__((always_inline)); +#endif +static inline int wipeAfter(int status) { - rb_gc_update_stack_extent(); + rb_gc_wipe_stack(); return status; } +#else +#define wipeAfter(status) status +#endif +#if STACK_WIPE_SITES & 2 +#define wipeAfterTag(status) wipeAfter(status) +#else +#define wipeAfterTag(status) status +#endif + +#define EXEC_TAG_0() ruby_setjmp(((void)0), prot_tag->buf) +#define EXEC_TAG() wipeAfterTag(EXEC_TAG_0()) #define JUMP_TAG(st) do { \ ruby_frame = prot_tag->frame; \ @@ -1116,6 +1128,12 @@ static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int, int)); +#if STACK_WIPE_SITES & 0x20 +#define wipeBeforeYield() rb_gc_wipe_stack() +#else +#define wipeBeforeYield() (void)0 +#endif + #define YIELD_LAMBDA_CALL 1 #define YIELD_PROC_CALL 2 #define YIELD_PUBLIC_DEF 4 @@ -3079,6 +3097,9 @@ goto while_out; do { while_redo: +#if STACK_WIPE_SITES & 0x10 + rb_gc_wipe_stack(); +#endif rb_eval(self, node->nd_body); while_next: ; @@ -3121,6 +3142,9 @@ goto until_out; do { until_redo: +#if STACK_WIPE_SITES & 0x10 + rb_gc_wipe_stack(); +#endif rb_eval(self, node->nd_body); until_next: ; @@ -5347,6 +5371,7 @@ rb_yield(val) VALUE val; { + wipeBeforeYield(); return rb_yield_0(val, 0, 0, 0, Qfalse); } @@ -5395,6 +5420,7 @@ loop_i() { for (;;) { + wipeBeforeYield(); rb_yield_0(Qundef, 0, 0, 0, Qfalse); CHECK_INTS; } @@ -10949,6 +10975,9 @@ rb_thread_switch(n) int n; { +#if STACK_WIPE_SITES & 1 + rb_gc_wipe_stack(); +#endif rb_trap_immediate = (curr_thread->flags&0x100)?1:0; switch (n) { case 0: @@ -10985,7 +11014,7 @@ return 1; } -#define THREAD_SAVE_CONTEXT(th) (rb_thread_switch(up_stk_extent( \ +#define THREAD_SAVE_CONTEXT(th) (rb_thread_switch( wipeAfter(\ ruby_setjmp(rb_thread_save_context(th), (th)->context)))) NORETURN(static void rb_thread_restore_context _((rb_thread_t,int))); @@ -13911,7 +13940,7 @@ tag = ID2SYM(rb_to_id(tag)); PUSH_TAG(tag); - if ((state = EXEC_TAG()) == 0) { + if ((state = wipeAfter(EXEC_TAG_0())) == 0) { val = rb_yield_0(tag, 0, 0, 0, Qfalse); } else if (state == TAG_THROW && tag == prot_tag->dst) { @@ -13979,6 +14008,9 @@ if (!tt) { rb_name_error(SYM2ID(tag), "uncaught throw `%s'", rb_id2name(SYM2ID(tag))); } +#if STACK_WIPE_SITES & 0x800 + rb_gc_update_stack_extent(); +#endif rb_trap_restore_mask(); JUMP_TAG(TAG_THROW); #ifndef __GNUC__ diff -ru ruby-1.8.7-p72/gc.c ruby-1.8.7-mbari/gc.c --- ruby-1.8.7-p72/gc.c 2009-02-09 21:21:30.000000000 -0800 +++ ruby-1.8.7-mbari/gc.c 2009-02-09 20:24:44.000000000 -0800 @@ -3,7 +3,7 @@ gc.c - $Author: brent $ - $Date: 2008/12/18 07:43:46 $ + $Date: 2009/02/09 20:45:03 $ created at: Tue Oct 5 09:44:46 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto @@ -22,10 +22,6 @@ #include <setjmp.h> #include <sys/types.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif - #ifdef HAVE_SYS_RESOURCE_H #include <sys/resource.h> #endif @@ -43,25 +39,6 @@ int _setjmp(), _longjmp(); #endif -/* Make alloca work the best possible way. */ -#ifdef __GNUC__ -# ifndef atarist -# ifndef alloca -# define alloca __builtin_alloca -# endif -# endif /* atarist */ -#else -# ifdef HAVE_ALLOCA_H -# include <alloca.h> -# else -# ifndef _AIX -# ifndef alloca /* predefined by HP cc +Olibcalls */ -void *alloca (); -# endif -# endif /* AIX */ -# endif /* HAVE_ALLOCA_H */ -#endif /* __GNUC__ */ - #ifndef GC_MALLOC_LIMIT #if defined(MSDOS) || defined(__human68k__) #define GC_MALLOC_LIMIT 200000 @@ -70,11 +47,18 @@ #endif #endif +#ifndef GC_LEVEL_MAX /*maximum # of VALUEs on 'C' stack during GC*/ +#define GC_LEVEL_MAX 8000 +#endif +#ifndef GC_STACK_PAD +#define GC_STACK_PAD 200 /* extra padding VALUEs for GC stack */ +#endif +#define GC_STACK_MAX (GC_LEVEL_MAX+GC_STACK_PAD) -size_t rb_gc_malloc_increase = 0; -#define malloc_increase rb_gc_malloc_increase -static unsigned long malloc_limit = GC_MALLOC_LIMIT; -size_t rb_gc_malloc_limit = GC_MALLOC_LIMIT-GC_MALLOC_LIMIT/8; +static VALUE *stack_limit, *gc_stack_limit; + +static size_t malloc_increase = 0; +static size_t malloc_limit = GC_MALLOC_LIMIT; /* * call-seq: @@ -108,7 +92,6 @@ long limit = NUM2LONG(newLimit); if (limit < 0) return gc_getlimit(mod); malloc_limit = limit; - rb_gc_malloc_limit = malloc_limit - malloc_limit/8; return newLimit; } @@ -126,6 +109,20 @@ } +/* + * call-seq: + * GC.exorcise + * + * Purge ghost references from recently freed stack space + * + */ +static VALUE gc_exorcise(VALUE mod) +{ + rb_gc_wipe_stack(); + return Qnil; +} + + static void run_final(); static VALUE nomem_error; static void garbage_collect(); @@ -174,7 +171,9 @@ rb_memerror(); } } +#if STACK_WIPE_SITES & 0x100 rb_gc_update_stack_extent(); +#endif return mem; } @@ -214,7 +213,9 @@ rb_memerror(); } } +#if STACK_WIPE_SITES & 0x200 rb_gc_update_stack_extent(); +#endif return mem; } @@ -509,38 +510,32 @@ # define STACK_LEVEL_MAX 655300 #endif -#ifdef C_ALLOCA -# define SET_STACK_END VALUE stack_end; alloca(0); +#ifndef nativeAllocA + /* portable way to return an approximate stack pointer */ +VALUE *__sp(void) { + VALUE tos; + return &tos; +} +# define SET_STACK_END VALUE stack_end # define STACK_END (&stack_end) #else -# if defined(__GNUC__) && defined(USE_BUILTIN_FRAME_ADDRESS) && !defined(__ia64) -# if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3 -__attribute__ ((noinline)) -# endif -static void -stack_end_address(VALUE **stack_end_p) -{ - VALUE stack_end; - *stack_end_p = &stack_end; -} -# define SET_STACK_END VALUE *stack_end; stack_end_address(&stack_end) -# else -# define SET_STACK_END VALUE *stack_end = alloca(1) -# endif -# define STACK_END (stack_end) +# define SET_STACK_END ((void)0) +# define STACK_END __sp() #endif + #if STACK_GROW_DIRECTION < 0 # define STACK_LENGTH(start) ((start) - STACK_END) #elif STACK_GROW_DIRECTION > 0 # define STACK_LENGTH(start) (STACK_END - (start) + 1) #else -# define STACK_LENGTH(start) ((STACK_END < (start)) ? (start) - STACK_END\ - : STACK_END - (start) + 1) +# define STACK_LENGTH(start) ((STACK_END < (start)) ? \ + (start) - STACK_END : STACK_END - (start) + 1) #endif + #if STACK_GROW_DIRECTION > 0 -# define STACK_UPPER(x, a, b) a +# define STACK_UPPER(a, b) a #elif STACK_GROW_DIRECTION < 0 -# define STACK_UPPER(x, a, b) b +# define STACK_UPPER(a, b) b #else int rb_gc_stack_grow_direction; static int @@ -550,33 +545,54 @@ SET_STACK_END; return rb_gc_stack_grow_direction = STACK_END > addr ? 1 : -1; } -# define STACK_UPPER(x, a, b) (rb_gc_stack_grow_direction > 0 ? a : b) +# define STACK_UPPER(a, b) (rb_gc_stack_grow_direction > 0 ? a : b) #endif -#define GC_WATER_MARK 512 - -#define CHECK_STACK(ret) do {\ - SET_STACK_END;\ - (ret) = (STACK_LENGTH(rb_gc_stack_start) > STACK_LEVEL_MAX + GC_WATER_MARK);\ -} while (0) - int ruby_stack_length(start, base) VALUE *start, **base; { SET_STACK_END; - if (base) *base = STACK_UPPER(STACK_END, start, STACK_END); + if (base) *base = STACK_UPPER(start, STACK_END); return STACK_LENGTH(start); } int ruby_stack_check() { - int ret; + SET_STACK_END; + return __stack_past(stack_limit, STACK_END); +} - CHECK_STACK(ret); - return ret; +/* + Zero memory that was (recently) part of the stack, but is no longer. + Invoke when stack is deep to mark its extent and when it's shallow to wipe it. +*/ +#if STACK_WIPE_METHOD != 4 +#if STACK_WIPE_METHOD +void rb_gc_wipe_stack(void) +{ + VALUE *stack_end = rb_gc_stack_end; + VALUE *sp = __sp(); + rb_gc_stack_end = sp; +#if STACK_WIPE_METHOD == 1 +#warning clearing of "ghost references" from the call stack has been disabled +#elif STACK_WIPE_METHOD == 2 /* alloca ghost stack before clearing it */ + if (__stack_past(sp, stack_end)) { + size_t bytes = __stack_depth((char *)stack_end, (char *)sp); + STACK_UPPER(sp = nativeAllocA(bytes), stack_end = nativeAllocA(bytes)); + __stack_zero(stack_end, sp); + } +#elif STACK_WIPE_METHOD == 3 /* clear unallocated area past stack pointer */ + __stack_zero(stack_end, sp); /* will crash if compiler pushes a temp. here */ +#else +#error unsupported method of clearing ghost references from the stack +#endif } +#else +#warning clearing of "ghost references" from the call stack completely disabled +#endif +#endif #define MARK_STACK_MAX 1024 static VALUE mark_stack[MARK_STACK_MAX]; @@ -592,6 +608,17 @@ #define MARK_STACK_EMPTY (mark_stack_ptr == mark_stack) +static inline void +push_mark_stack(VALUE ptr) +{ + if (!mark_stack_overflow) { + if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) + *mark_stack_ptr++ = ptr; + else + mark_stack_overflow = 1; + } +} + static st_table *source_filenames; char * @@ -635,22 +662,22 @@ } } -static void gc_mark _((VALUE ptr, int lev)); -static void gc_mark_children _((VALUE ptr, int lev)); +#define gc_mark(ptr) rb_gc_mark(ptr) +static void gc_mark_children _((VALUE ptr)); static void gc_mark_all() { RVALUE *p, *pend; - int i; + struct heaps_slot *heap = heaps+heaps_used; init_mark_stack(); - for (i = 0; i < heaps_used; i++) { - p = heaps[i].slot; pend = p + heaps[i].limit; + while (--heap >= heaps) { + p = heap->slot; pend = p + heap->limit; while (p < pend) { if ((p->as.basic.flags & FL_MARK) && (p->as.basic.flags != FL_MARK)) { - gc_mark_children((VALUE)p, 0); + gc_mark_children((VALUE)p); } p++; } @@ -660,169 +687,129 @@ static void gc_mark_rest() { + size_t stackLen = mark_stack_ptr - mark_stack; +#ifdef nativeAllocA + VALUE *tmp_arry = nativeAllocA(stackLen*sizeof(VALUE)); +#else VALUE tmp_arry[MARK_STACK_MAX]; - VALUE *p; - - p = (mark_stack_ptr - mark_stack) + tmp_arry; - MEMCPY(tmp_arry, mark_stack, VALUE, MARK_STACK_MAX); +#endif + VALUE *p = tmp_arry + stackLen; + + MEMCPY(tmp_arry, mark_stack, VALUE, stackLen); init_mark_stack(); - while(p != tmp_arry){ - p--; - gc_mark_children(*p, 0); - } + while(--p >= tmp_arry) gc_mark_children(*p); } static inline int is_pointer_to_heap(ptr) void *ptr; { - register RVALUE *p = RANY(ptr); - register RVALUE *heap_org; - register long i; + RVALUE *p = RANY(ptr); + struct heaps_slot *heap; - if (p < lomem || p > himem) return Qfalse; - if ((VALUE)p % sizeof(RVALUE) != 0) return Qfalse; + if (p < lomem || p > himem || (VALUE)p % sizeof(RVALUE)) return Qfalse; /* check if p looks like a pointer */ - for (i=0; i < heaps_used; i++) { - heap_org = heaps[i].slot; - if (heap_org <= p && p < heap_org + heaps[i].limit) - return Qtrue; - } + heap = heaps+heaps_used; + while (--heap >= heaps) + if (p >= heap->slot && p < heap->slot + heap->limit) + return Qtrue; return Qfalse; } static void mark_locations_array(x, n) - register VALUE *x; - register long n; + VALUE *x; + size_t n; { VALUE v; while (n--) { v = *x; if (is_pointer_to_heap((void *)v)) { - gc_mark(v, 0); + gc_mark(v); } x++; } } -void +void inline rb_gc_mark_locations(start, end) VALUE *start, *end; { - long n; - - n = end - start; - mark_locations_array(start,n); + mark_locations_array(start,end - start); } static int -mark_entry(key, value, lev) +mark_entry(key, value) ID key; VALUE value; - int lev; { - gc_mark(value, lev); + gc_mark(value); return ST_CONTINUE; } -static void -mark_tbl(tbl, lev) - st_table *tbl; - int lev; -{ - if (!tbl) return; - st_foreach(tbl, mark_entry, lev); -} - void rb_mark_tbl(tbl) st_table *tbl; { - mark_tbl(tbl, 0); + if (!tbl) return; + st_foreach(tbl, mark_entry, 0); } +#define mark_tbl(tbl) rb_mark_tbl(tbl) static int -mark_keyvalue(key, value, lev) +mark_keyvalue(key, value) VALUE key; VALUE value; - int lev; { - gc_mark(key, lev); - gc_mark(value, lev); + gc_mark(key); + gc_mark(value); return ST_CONTINUE; } -static void -mark_hash(tbl, lev) - st_table *tbl; - int lev; -{ - if (!tbl) return; - st_foreach(tbl, mark_keyvalue, lev); -} - void rb_mark_hash(tbl) st_table *tbl; { - mark_hash(tbl, 0); + if (!tbl) return; + st_foreach(tbl, mark_keyvalue, 0); } +#define mark_hash(tbl) rb_mark_hash(tbl) void rb_gc_mark_maybe(obj) VALUE obj; { if (is_pointer_to_heap((void *)obj)) { - gc_mark(obj, 0); + gc_mark(obj); } } -#define GC_LEVEL_MAX 250 - -static void -gc_mark(ptr, lev) +void +rb_gc_mark(ptr) VALUE ptr; - int lev; { - register RVALUE *obj; - - obj = RANY(ptr); + RVALUE *obj = RANY(ptr); + SET_STACK_END; + if (rb_special_const_p(ptr)) return; /* special const not marked */ if (obj->as.basic.flags == 0) return; /* free cell */ if (obj->as.basic.flags & FL_MARK) return; /* already marked */ obj->as.basic.flags |= FL_MARK; - if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) { - if (!mark_stack_overflow) { - if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) { - *mark_stack_ptr = ptr; - mark_stack_ptr++; - } - else { - mark_stack_overflow = 1; - } - } - return; + if (__stack_past(gc_stack_limit, STACK_END)) + push_mark_stack(ptr); + else{ + gc_mark_children(ptr); } - gc_mark_children(ptr, lev+1); -} - -void -rb_gc_mark(ptr) - VALUE ptr; -{ - gc_mark(ptr, 0); } static void -gc_mark_children(ptr, lev) +gc_mark_children(ptr) VALUE ptr; - int lev; { - register RVALUE *obj = RANY(ptr); + RVALUE *obj = RANY(ptr); goto marking; /* skip */ @@ -856,7 +843,7 @@ case NODE_RESCUE: case NODE_RESBODY: case NODE_CLASS: - gc_mark((VALUE)obj->as.node.u2.node, lev); + gc_mark((VALUE)obj->as.node.u2.node); /* fall through */ case NODE_BLOCK: /* 1,3 */ case NODE_ARRAY: @@ -869,7 +856,7 @@ case NODE_CALL: case NODE_DEFS: case NODE_OP_ASGN1: - gc_mark((VALUE)obj->as.node.u1.node, lev); + gc_mark((VALUE)obj->as.node.u1.node); /* fall through */ case NODE_SUPER: /* 3 */ case NODE_FCALL: @@ -896,7 +883,7 @@ case NODE_ALIAS: case NODE_VALIAS: case NODE_ARGS: - gc_mark((VALUE)obj->as.node.u1.node, lev); + gc_mark((VALUE)obj->as.node.u1.node); /* fall through */ case NODE_METHOD: /* 2 */ case NODE_NOT: @@ -934,7 +921,7 @@ case NODE_SCOPE: /* 2,3 */ case NODE_BLOCK_PASS: case NODE_CDECL: - gc_mark((VALUE)obj->as.node.u3.node, lev); + gc_mark((VALUE)obj->as.node.u3.node); ptr = (VALUE)obj->as.node.u2.node; goto again; @@ -967,25 +954,26 @@ default: /* unlisted NODE */ if (is_pointer_to_heap(obj->as.node.u1.node)) { - gc_mark((VALUE)obj->as.node.u1.node, lev); + gc_mark((VALUE)obj->as.node.u1.node); } if (is_pointer_to_heap(obj->as.node.u2.node)) { - gc_mark((VALUE)obj->as.node.u2.node, lev); + gc_mark((VALUE)obj->as.node.u2.node); } if (is_pointer_to_heap(obj->as.node.u3.node)) { - gc_mark((VALUE)obj->as.node.u3.node, lev); + ptr = (VALUE)obj->as.node.u3.node; + goto again; } } - return; /* no need to mark class. */ + return; /* no need to mark class. */ } - gc_mark(obj->as.basic.klass, lev); + gc_mark(obj->as.basic.klass); switch (obj->as.basic.flags & T_MASK) { case T_ICLASS: case T_CLASS: case T_MODULE: - mark_tbl(obj->as.klass.m_tbl, lev); - mark_tbl(obj->as.klass.iv_tbl, lev); + mark_tbl(obj->as.klass.m_tbl); + mark_tbl(obj->as.klass.iv_tbl); ptr = obj->as.klass.super; goto again; @@ -995,17 +983,16 @@ goto again; } else { - long i, len = obj->as.array.len; VALUE *ptr = obj->as.array.ptr; - - for (i=0; i < len; i++) { - gc_mark(*ptr++, lev); + VALUE *pend = ptr + obj->as.array.len; + while (ptr < pend) { + gc_mark(*ptr++); } } break; case T_HASH: - mark_hash(obj->as.hash.tbl, lev); + mark_hash(obj->as.hash.tbl); ptr = obj->as.hash.ifnone; goto again; @@ -1022,7 +1009,7 @@ break; case T_OBJECT: - mark_tbl(obj->as.object.iv_tbl, lev); + mark_tbl(obj->as.object.iv_tbl); break; case T_FILE: @@ -1040,7 +1027,7 @@ break; case T_VARMAP: - gc_mark(obj->as.varmap.val, lev); + gc_mark(obj->as.varmap.val); ptr = (VALUE)obj->as.varmap.next; goto again; @@ -1050,19 +1037,17 @@ VALUE *vars = &obj->as.scope.local_vars[-1]; while (n--) { - gc_mark(*vars++, lev); + gc_mark(*vars++); } } break; case T_STRUCT: { - long len = obj->as.rstruct.len; VALUE *ptr = obj->as.rstruct.ptr; - - while (len--) { - gc_mark(*ptr++, lev); - } + VALUE *pend = ptr + obj->as.rstruct.len; + while (ptr < pend) + gc_mark(*ptr++); } break; @@ -1134,7 +1119,7 @@ p = heaps[i].slot; pend = p + heaps[i].limit; while (p < pend) { if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE) - gc_mark((VALUE)p, 0); + gc_mark((VALUE)p); p++; } } @@ -1346,7 +1331,7 @@ rb_gc_mark_frame(frame) struct FRAME *frame; { - gc_mark((VALUE)frame->node, 0); + gc_mark((VALUE)frame->node); } #ifdef __GNUC__ @@ -1384,8 +1369,10 @@ #endif /* __human68k__ or DJGPP */ #endif /* __GNUC__ */ + + static void -garbage_collect() +garbage_collect_0(VALUE *top_frame) { struct gc_list *list; struct FRAME * frame; @@ -1406,9 +1393,10 @@ if (during_gc) return; during_gc++; + gc_stack_limit = __stack_grow(STACK_END, GC_LEVEL_MAX); init_mark_stack(); - gc_mark((VALUE)ruby_current_node, 0); + gc_mark((VALUE)ruby_current_node); /* mark frame stack */ for (frame = ruby_frame; frame; frame = frame->prev) { @@ -1421,10 +1409,10 @@ } } } - gc_mark((VALUE)ruby_scope, 0); - gc_mark((VALUE)ruby_dyna_vars, 0); + gc_mark((VALUE)ruby_scope); + gc_mark((VALUE)ruby_dyna_vars); if (finalizer_table) { - mark_tbl(finalizer_table, 0); + mark_tbl(finalizer_table); } FLUSH_REGISTER_WINDOWS; @@ -1432,14 +1420,14 @@ rb_setjmp(save_regs_gc_mark); mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *)); #if STACK_GROW_DIRECTION < 0 - rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start); + rb_gc_mark_locations(top_frame, rb_gc_stack_start); #elif STACK_GROW_DIRECTION > 0 - rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1); + rb_gc_mark_locations(rb_gc_stack_start, top_frame + 1); #else if (rb_gc_stack_grow_direction < 0) - rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start); + rb_gc_mark_locations(top_frame, rb_gc_stack_start); else - rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1); + rb_gc_mark_locations(rb_gc_stack_start, top_frame + 1); #endif #ifdef __ia64 /* mark backing store (flushed register window on the stack) */ @@ -1479,10 +1467,35 @@ } rb_gc_abort_threads(); } while (!MARK_STACK_EMPTY); - gc_sweep(); } +static void +garbage_collect() +{ + VALUE *top = __sp(); +#if STACK_WIPE_SITES & 0x400 +# ifdef nativeAllocA + if (__stack_past (top, stack_limit)) { + /* allocate a large frame to ensure app stack cannot grow into GC stack */ + volatile char *spacer = + nativeAllocA(__stack_depth((void*)stack_limit,(void*)top)); + } + garbage_collect_0(top); +# else /* no native alloca() available */ + garbage_collect_0(top); + { + VALUE *paddedLimit = __stack_grow(gc_stack_limit, GC_STACK_PAD); + if (__stack_past(rb_gc_stack_end, paddedLimit)) + rb_gc_stack_end = paddedLimit; + } + rb_gc_wipe_stack(); /* wipe the whole stack area reserved for this gc */ +# endif +#else + garbage_collect_0(top); +#endif +} + void rb_gc() { @@ -1507,6 +1520,7 @@ return Qnil; } + void ruby_set_stack_size(size) size_t size; @@ -1514,6 +1528,29 @@ #ifndef STACK_LEVEL_MAX STACK_LEVEL_MAX = size / sizeof(VALUE); #endif + stack_limit = __stack_grow(rb_gc_stack_start, STACK_LEVEL_MAX-GC_STACK_MAX); +} + +static void +set_stack_size(void) +{ +#ifdef HAVE_GETRLIMIT + struct rlimit rlim; + if (getrlimit(RLIMIT_STACK, &rlim) == 0) { + if (rlim.rlim_cur > 0 && rlim.rlim_cur != RLIM_INFINITY) { + size_t maxStackBytes = rlim.rlim_cur; + if (rlim.rlim_cur != maxStackBytes) + maxStackBytes = -1; + { + size_t space = maxStackBytes/5; + if (space > 1024*1024) space = 1024*1024; + ruby_set_stack_size(maxStackBytes - space); + return; + } + } + } +#endif + ruby_set_stack_size(STACK_LEVEL_MAX*sizeof(VALUE)); } void @@ -1547,7 +1584,7 @@ memset(&m, 0, sizeof(m)); VirtualQuery(&m, &m, sizeof(m)); rb_gc_stack_start = - STACK_UPPER((VALUE *)&m, (VALUE *)m.BaseAddress, + STACK_UPPER((VALUE *)m.BaseAddress, (VALUE *)((char *)m.BaseAddress + m.RegionSize) - 1); #elif defined(STACK_END_ADDRESS) { @@ -1556,28 +1593,16 @@ } #else if (!addr) addr = (void *)&addr; - STACK_UPPER(&addr, addr, ++addr); + STACK_UPPER(addr, ++addr); if (rb_gc_stack_start) { - if (STACK_UPPER(&addr, - rb_gc_stack_start > addr, + if (STACK_UPPER(rb_gc_stack_start > addr, rb_gc_stack_start < addr)) rb_gc_stack_start = addr; return; } rb_gc_stack_start = addr; #endif -#ifdef HAVE_GETRLIMIT - { - struct rlimit rlim; - - if (getrlimit(RLIMIT_STACK, &rlim) == 0) { - unsigned int space = rlim.rlim_cur/5; - - if (space > 1024*1024) space = 1024*1024; - STACK_LEVEL_MAX = (rlim.rlim_cur - space) / sizeof(VALUE); - } - } -#endif + set_stack_size(); } void ruby_init_stack(VALUE *addr @@ -1587,8 +1612,7 @@ ) { if (!rb_gc_stack_start || - STACK_UPPER(&addr, - rb_gc_stack_start > addr, + STACK_UPPER(rb_gc_stack_start > addr, rb_gc_stack_start < addr)) { rb_gc_stack_start = addr; } @@ -1599,16 +1623,7 @@ } #endif #ifdef HAVE_GETRLIMIT - { - struct rlimit rlim; - - if (getrlimit(RLIMIT_STACK, &rlim) == 0) { - unsigned int space = rlim.rlim_cur/5; - - if (space > 1024*1024) space = 1024*1024; - STACK_LEVEL_MAX = (rlim.rlim_cur - space) / sizeof(VALUE); - } - } + set_stack_size(); #elif defined _WIN32 { MEMORY_BASIC_INFORMATION mi; @@ -1619,7 +1634,7 @@ size = (char *)mi.BaseAddress - (char *)mi.AllocationBase; space = size / 5; if (space > 1024*1024) space = 1024*1024; - STACK_LEVEL_MAX = (size - space) / sizeof(VALUE); + ruby_set_stack_size(size - space); } } #endif @@ -2111,6 +2126,7 @@ rb_define_singleton_method(rb_mGC, "limit", gc_getlimit, 0); rb_define_singleton_method(rb_mGC, "limit=", gc_setlimit, 1); rb_define_singleton_method(rb_mGC, "increase", gc_increase, 0); + rb_define_singleton_method(rb_mGC, "exorcise", gc_exorcise, 0); rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0); rb_mObSpace = rb_define_module("ObjectSpace"); diff -ru ruby-1.8.7-p72/intern.h ruby-1.8.7-mbari/intern.h --- ruby-1.8.7-p72/intern.h 2009-02-09 21:21:30.000000000 -0800 +++ ruby-1.8.7-mbari/intern.h 2008-12-23 21:54:37.000000000 -0800 @@ -2,8 +2,8 @@ intern.h - - $Author: shyouhei $ - $Date: 2008-07-07 12:29:28 +0900 (Mon, 07 Jul 2008) $ + $Author: brent $ + $Date: 2008/12/24 05:54:37 $ created at: Thu Jun 10 14:22:17 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto diff -ru ruby-1.8.7-p72/missing/alloca.c ruby-1.8.7-mbari/missing/alloca.c --- ruby-1.8.7-p72/missing/alloca.c 2007-02-12 15:01:19.000000000 -0800 +++ ruby-1.8.7-mbari/missing/alloca.c 2009-01-23 00:01:03.000000000 -0800 @@ -29,6 +29,7 @@ static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ #endif +#include <sys/types.h> #include "config.h" #ifdef emacs #ifdef static @@ -44,11 +45,7 @@ #endif /* static */ #endif /* emacs */ -#ifdef X3J11 typedef void *pointer; /* generic pointer type */ -#else -typedef char *pointer; /* generic pointer type */ -#endif /* X3J11 */ #define NULL 0 /* null pointer constant */ @@ -140,8 +137,7 @@ static header *last_alloca_header = NULL; /* -> last alloca header */ pointer -alloca (size) /* returns pointer to storage */ - unsigned size; /* # bytes to allocate */ +alloca (size_t size) /* returns pointer to storage */ { auto char probe; /* probes stack depth: */ register char *depth = &probe; diff -ru ruby-1.8.7-p72/rubysig.h ruby-1.8.7-mbari/rubysig.h --- ruby-1.8.7-p72/rubysig.h 2009-02-09 21:21:30.000000000 -0800 +++ ruby-1.8.7-mbari/rubysig.h 2009-02-09 20:55:50.000000000 -0800 @@ -3,7 +3,7 @@ rubysig.h - $Author: brent $ - $Date: 2008/12/14 07:24:10 $ + $Date: 2009/02/09 20:45:48 $ created at: Wed Aug 16 01:15:38 JST 1995 Copyright (C) 1993-2003 Yukihiro Matsumoto @@ -12,8 +12,75 @@ #ifndef SIG_H #define SIG_H + #include <errno.h> +/* STACK_WIPE_SITES determines where attempts are made to exorcise + "ghost object refereces" from the stack and how the stack is cleared: + + 0x*001 --> wipe stack just after every thread_switch + 0x*002 --> wipe stack just after every EXEC_TAG() + 0x*004 --> wipe stack in CHECK_INTS + 0x*010 --> wipe stack in while & until loops + 0x*020 --> wipe stack before yield() in iterators and outside eval.c + 0x*040 --> wipe stack on catch and thread save context + 0x*100 --> update stack extent on each object allocation + 0x*200 --> update stack extent on each object reallocation + 0x*400 --> update stack extent during GC marking passes + 0x*800 --> update stack extent on each throw (use with 0x040) + 0x1000 --> use inline assembly code for x86, PowerPC, or ARM CPUs + + 0x0*** --> do not even call rb_wipe_stack() + 0x2*** --> call dummy rb_wipe_stack() (for debugging and profiling) + 0x4*** --> safe, portable stack clearing in memory allocated with alloca + 0x6*** --> use faster, but less safe stack clearing in unallocated stack + 0x8*** --> use faster, but less safe stack clearing (with inline code) + + for most effective gc use 0x*707 + for fastest micro-benchmarking use 0x0000 + 0x*770 prevents almost all memory leaks caused by ghost references + without adding much overhead for stack clearing. + Other good trade offs are 0x*270, 0x*703, 0x*303 or even 0x*03 + + In general, you may lessen the default -mpreferred-stack-boundary + only if using less safe stack clearing (0x6***). Lessening the + stack alignment with portable stack clearing (0x4***) may fail to clear + all ghost references off the stack. + + When using 0x6*** or 0x8***, the compiler could insert + stack push(s) between reading the stack pointer and clearing + the ghost references. The register(s) pushed will be + cleared by the rb_gc_stack_wipe(), typically resulting in a segfault + or an interpreter hang. + + STACK_WIPE_SITES of 0x8770 works well compiled with gcc on most machines + using the recommended CFLAGS="-O2 -fno-stack-protector". However... + If it hangs or crashes for you, try changing STACK_WIPE_SITES to 0x4770 + and please report your details. i.e. CFLAGS, compiler, version, CPU + + Note that it is redundant to wipe_stack in looping constructs if + also doing so in CHECK_INTS. It is also redundant to wipe_stack on + each thread_switch if wiping after every thread save context. +*/ +#ifndef STACK_WIPE_SITES +# ifdef __x86_64__ /* deal with "red zone" by not inlining stack clearing */ +# define STACK_WIPE_SITES 0x6770 +# elif defined __ppc__ || defined __ppc64__ /* On any PowerPC, deal with... */ +# define STACK_WIPE_SITES 0x7764 /* red zone & alloc(0) doesn't return sp */ +# else +# define STACK_WIPE_SITES 0x8770 /*normal case, use 0x4770 if problems arise*/ +# endif +#endif + +#if (STACK_WIPE_SITES & 0x14) == 0x14 +#warning wiping stack in CHECK_INTS makes wiping in loops redundant +#endif +#if (STACK_WIPE_SITES & 0x41) == 0x41 +#warning wiping stack after thread save makes wiping on thread_switch redundant +#endif + +#define STACK_WIPE_METHOD (STACK_WIPE_SITES>>13) + #ifdef _WIN32 typedef LONG rb_atomic_t; @@ -79,52 +146,151 @@ RUBY_EXTERN int rb_thread_critical; void rb_thread_schedule _((void)); -#if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE) -RUBY_EXTERN int rb_thread_pending; -EXTERN size_t rb_gc_malloc_increase; -EXTERN size_t rb_gc_malloc_limit; -EXTERN VALUE *rb_gc_stack_end; -EXTERN int *rb_gc_stack_grow_direction; /* -1 for down or 1 for up */ -#define __stack_zero_up(end,sp) while (end >= ++sp) *sp=0 -#define __stack_grown_up (rb_gc_stack_end > (VALUE *)alloca(0)) -#define __stack_zero_down(end,sp) while (end <= --sp) *sp=0 -#define __stack_grown_down (rb_gc_stack_end < (VALUE *)alloca(0)) +RUBY_EXTERN VALUE *rb_gc_stack_end; +RUBY_EXTERN int rb_gc_stack_grow_direction; /* -1 for down or 1 for up */ #if STACK_GROW_DIRECTION > 0 + +/* clear stack space between end and sp (not including *sp) */ #define __stack_zero(end,sp) __stack_zero_up(end,sp) -#define __stack_grown __stack_grown_up + +/* true if top has grown past limit, i.e. top deeper than limit */ +#define __stack_past(limit,top) __stack_past_up(limit,top) + +/* depth of mid below stack top */ +#define __stack_depth(top,mid) __stack_depth_up(top,mid) + +/* stack pointer top adjusted to include depth more items */ +#define __stack_grow(top,depth) __stack_grow_up(top,depth) + + #elif STACK_GROW_DIRECTION < 0 #define __stack_zero(end,sp) __stack_zero_down(end,sp) -#define __stack_grown __stack_grown_down +#define __stack_past(limit,top) __stack_past_down(limit,top) +#define __stack_depth(top,mid) __stack_depth_down(top,mid) +#define __stack_grow(top,depth) __stack_grow_down(top,depth) + #else /* limp along if stack direction can't be determined at compile time */ #define __stack_zero(end,sp) if (rb_gc_stack_grow_direction<0) \ __stack_zero_down(end,sp); else __stack_zero_up(end,sp); -#define __stack_grown \ - (rb_gc_stack_grow_direction<0 ? __stack_grown_down : __stack_grown_up) +#define __stack_past(limit,top) (rb_gc_stack_grow_direction<0 ? \ + __stack_past_down(limit,top) : __stack_past_up(limit,top)) +#define __stack_depth(top,mid) (rb_gc_stack_grow_direction<0 ? \ + __stack_depth_down(top,mid) : __stack_depth_up(top,mid)) +#define __stack_grow(top,depth) (rb_gc_stack_grow_direction<0 ? \ + __stack_grow_down(top,depth) : __stack_grow_up(top,depth)) #endif +#define __stack_zero_up(end,sp) while (end >= ++sp) *sp=0 +#define __stack_past_up(limit,top) ((limit) < (top)) +#define __stack_depth_up(top,mid) ((top) - (mid)) +#define __stack_grow_up(top,depth) ((top)+(depth)) + +#define __stack_zero_down(end,sp) while (end <= --sp) *sp=0 +#define __stack_past_down(limit,top) ((limit) > (top)) +#define __stack_depth_down(top,mid) ((mid) - (top)) +#define __stack_grow_down(top,depth) ((top)-(depth)) + +/* Make alloca work the best possible way. */ +#ifdef __GNUC__ +# ifndef atarist +# ifndef alloca +# define alloca __builtin_alloca +# endif +# endif /* atarist */ + +# define nativeAllocA __builtin_alloca + +/* use assembly to get stack pointer quickly */ +# if STACK_WIPE_SITES & 0x1000 +# define __defspfn(asmb) \ +static inline VALUE *__sp(void) __attribute__((always_inline)); \ +static inline VALUE *__sp(void) \ +{ \ + VALUE *sp; asm(asmb); \ + return sp; \ +} +# if defined __ppc__ || defined __ppc64__ +__defspfn("addi %0, r1, 0": "=r"(sp)) +# elif defined __i386__ +__defspfn("movl %%esp, %0": "=r"(sp)) +# elif defined __x86_64__ +__defspfn("movq %%rsp, %0": "=r"(sp)) +# elif __arm__ +__defspfn("mov %0, sp": "=r"(sp)) +# else +# define __sp() ((VALUE *)__builtin_alloca(0)) +# warning No assembly version of __sp() defined for this CPU. +# endif +# else +# define __sp() ((VALUE *)__builtin_alloca(0)) +# endif + +#else // not GNUC + +# ifdef HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifndef _AIX +# ifndef alloca /* predefined by HP cc +Olibcalls */ +void *alloca (); +# endif +# endif /* AIX */ +# endif /* HAVE_ALLOCA_H */ + +# if STACK_WIPE_SITES & 0x1000 +# warning No assembly versions of __sp() defined for this compiler. +# endif +# if HAVE_ALLOCA +# define __sp() ((VALUE *)alloca(0)) +# define nativeAllocA alloca +# else +RUBY_EXTERN VALUE *__sp(void); +# if STACK_WIPE_SITES +# define STACK_WIPE_SITES 0 +# warning Disabled Stack Wiping because there is no native alloca() +# endif +# endif +#endif /* __GNUC__ */ + + /* - zero the memory that was (recently) part of the stack - but is no longer. Invoke when stack is deep to mark its extent - and when it is shallow to wipe it + Zero memory that was (recently) part of the stack, but is no longer. + Invoke when stack is deep to mark its extent and when it's shallow to wipe it. */ +#if STACK_WIPE_METHOD == 0 +#define rb_gc_wipe_stack() ((void)0) +#elif STACK_WIPE_METHOD == 4 #define rb_gc_wipe_stack() { \ - VALUE *sp = alloca(0); \ VALUE *end = rb_gc_stack_end; \ + VALUE *sp = __sp(); \ rb_gc_stack_end = sp; \ __stack_zero(end, sp); \ } +#else +RUBY_EXTERN void rb_gc_wipe_stack(void); +#endif /* Update our record of maximum stack extent without zeroing unused stack */ -#define rb_gc_update_stack_extent() \ - if __stack_grown rb_gc_stack_end = alloca(0); +#define rb_gc_update_stack_extent() do { \ + VALUE *sp = __sp(); \ + if __stack_past(rb_gc_stack_end, sp) rb_gc_stack_end = sp; \ +} while(0) + +#if STACK_WIPE_SITES & 4 +# define CHECK_INTS_wipe_stack() rb_gc_wipe_stack() +#else +# define CHECK_INTS_wipe_stack() (void)0 +#endif +#if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE) +RUBY_EXTERN int rb_thread_pending; # define CHECK_INTS do {\ - rb_gc_wipe_stack(); \ + CHECK_INTS_wipe_stack(); \ if (!(rb_prohibit_interrupt || rb_thread_critical)) {\ if (rb_thread_pending) rb_thread_schedule();\ if (rb_trap_pending) rb_trap_exec();\ @@ -135,14 +301,14 @@ RUBY_EXTERN int rb_thread_tick; #define THREAD_TICK 500 #define CHECK_INTS do {\ - rb_gc_wipe_stack(); \ + CHECK_INTS_wipe_stack(); \ if (!(rb_prohibit_interrupt || rb_thread_critical)) {\ if (rb_thread_tick-- <= 0) {\ rb_thread_tick = THREAD_TICK;\ rb_thread_schedule();\ }\ + if (rb_trap_pending) rb_trap_exec();\ }\ - if (rb_trap_pending) rb_trap_exec();\ } while (0) #endif diff -ru ruby-1.8.7-p72/version.h ruby-1.8.7-mbari/version.h --- ruby-1.8.7-p72/version.h 2009-02-09 21:21:30.000000000 -0800 +++ ruby-1.8.7-mbari/version.h 2009-02-09 20:24:44.000000000 -0800 @@ -1,15 +1,15 @@ #define RUBY_VERSION "1.8.7" -#define RUBY_RELEASE_DATE "2008-12-21" +#define RUBY_RELEASE_DATE "2009-2-9" #define RUBY_VERSION_CODE 187 -#define RUBY_RELEASE_CODE 20081221 +#define RUBY_RELEASE_CODE 20090209 #define RUBY_PATCHLEVEL 72 #define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MINOR 8 #define RUBY_VERSION_TEENY 7 -#define RUBY_RELEASE_YEAR 2008 -#define RUBY_RELEASE_MONTH 12 -#define RUBY_RELEASE_DAY 21 +#define RUBY_RELEASE_YEAR 2009 +#define RUBY_RELEASE_MONTH 2 +#define RUBY_RELEASE_DAY 9 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; @@ -25,7 +25,12 @@ #define RUBY_BIRTH_MONTH 2 #define RUBY_BIRTH_DAY 24 -#define RUBY_RELEASE_STR "MBARI 6 on patchlevel" +#include "rubysig.h" + +#define string_arg(s) #s +#define MBARI_RELEASE(wipe_sites) "MBARI 7/" string_arg(wipe_sites) + +#define RUBY_RELEASE_STR MBARI_RELEASE(STACK_WIPE_SITES) " on patchlevel" #define RUBY_RELEASE_NUM RUBY_PATCHLEVEL
Copyright ©2021 || Defacer Indonesia