Skip to content

Commit

Permalink
backporting MBARI patches from 1.8.7-p72. missing mods to eval and gc…
Browse files Browse the repository at this point in the history
…, but passes test/runner.rb suite
  • Loading branch information
brentr committed Feb 16, 2009
1 parent 922d4b7 commit 0657b9e
Show file tree
Hide file tree
Showing 7 changed files with 273 additions and 24 deletions.
2 changes: 1 addition & 1 deletion common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ variable.$(OBJEXT): {$(VPATH)}variable.c {$(VPATH)}ruby.h config.h \
{$(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
8 changes: 2 additions & 6 deletions missing/alloca.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -44,11 +45,7 @@ lose
#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 */

Expand Down Expand Up @@ -140,8 +137,7 @@ typedef union hdr
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;
Expand Down
6 changes: 2 additions & 4 deletions node.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,10 +409,8 @@ struct rb_thread {

VALUE result;

long stk_len;
long stk_max;
VALUE *stk_ptr;
VALUE *stk_pos;
long stk_len, stk_max;
VALUE *stk_ptr, *stk_pos, *stk_start;
#ifdef __ia64
long bstr_len;
long bstr_max;
Expand Down
212 changes: 211 additions & 1 deletion rubysig.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -79,9 +146,151 @@ void rb_trap_restore_mask _((void));

RUBY_EXTERN int rb_thread_critical;
void rb_thread_schedule _((void));

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)

/* 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_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_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 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 *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() 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 {\
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();\
Expand All @@ -92,13 +301,14 @@ RUBY_EXTERN int rb_thread_pending;
RUBY_EXTERN int rb_thread_tick;
#define THREAD_TICK 500
#define CHECK_INTS do {\
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

Expand Down
6 changes: 4 additions & 2 deletions test/runner.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
require 'test/unit'

rcsid = %w$Id$
Version = rcsid[2].scan(/\d+/).collect!(&method(:Integer)).freeze
Release = rcsid[3].freeze
if rcsid[3]
Version = rcsid[2].scan(/\d+/).collect!(&method(:Integer)).freeze
Release = rcsid[3].freeze
end

exit Test::Unit::AutoRunner.run(true, File.dirname($0))
31 changes: 26 additions & 5 deletions version.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,44 @@
#include "version.h"
#include <stdio.h>

#define PRINT(type) puts(ruby_##type)
#define MKSTR(type) rb_obj_freeze(rb_str_new(ruby_##type, sizeof(ruby_##type)-1))

const char ruby_version[] = RUBY_VERSION;
const char ruby_release_date[] = RUBY_RELEASE_DATE;
const char ruby_platform[] = RUBY_PLATFORM;
const int ruby_patchlevel = RUBY_PATCHLEVEL;
const char *ruby_description;
const char *ruby_copyright;

void
Init_version()
{
VALUE v = rb_obj_freeze(rb_str_new2(ruby_version));
VALUE d = rb_obj_freeze(rb_str_new2(ruby_release_date));
VALUE p = rb_obj_freeze(rb_str_new2(ruby_platform));
static char description[128];
static char copyright[128];
VALUE v = MKSTR(version);
VALUE d = MKSTR(release_date);
VALUE p = MKSTR(platform);
VALUE tmp;

rb_define_global_const("RUBY_VERSION", v);
rb_define_global_const("RUBY_RELEASE_DATE", d);
rb_define_global_const("RUBY_PLATFORM", p);
rb_define_global_const("RUBY_PATCHLEVEL", INT2FIX(RUBY_PATCHLEVEL));

snprintf(description, sizeof(description), "ruby %s (%s %s %d) [%s]",
RUBY_VERSION, RUBY_RELEASE_DATE, RUBY_RELEASE_STR,
RUBY_RELEASE_NUM, RUBY_PLATFORM);
ruby_description = description;
tmp = rb_obj_freeze(rb_str_new2(description));
rb_define_global_const("RUBY_DESCRIPTION", tmp);

snprintf(copyright, sizeof(copyright), "ruby - Copyright (C) %d-%d %s",
RUBY_BIRTH_YEAR, RUBY_RELEASE_YEAR, RUBY_AUTHOR);
ruby_copyright = copyright;
tmp = rb_obj_freeze(rb_str_new2(copyright));
rb_define_global_const("RUBY_COPYRIGHT", tmp);

/* obsolete constants */
rb_define_global_const("VERSION", v);
rb_define_global_const("RELEASE_DATE", d);
Expand All @@ -40,13 +61,13 @@ Init_version()
void
ruby_show_version()
{
printf("ruby %s (%s patchlevel %d) [%s]\n", RUBY_VERSION, RUBY_RELEASE_DATE, RUBY_PATCHLEVEL, RUBY_PLATFORM);
PRINT(description);
fflush(stdout);
}

void
ruby_show_copyright()
{
printf("ruby - Copyright (C) 1993-%d Yukihiro Matsumoto\n", RUBY_RELEASE_YEAR);
PRINT(copyright);
exit(0);
}
Loading

0 comments on commit 0657b9e

Please sign in to comment.