TestDrive で IA64 上の Intel C++ Compiler and HP aC++/ANSI C をいろいろ試しているのですが、-O0 でなら Intel C++ Compiler Linux) で動くようにできました。 * インラインアセンブラがないのでアセンブラが必要な部分は ia64.s に分離 rb_ia64_flushrs で flushrs を呼んで、rb_ia64_bsp で bsp を 得る * ia64.s を使えば libunwind は不要なので使わない * HP aC++/ANSI C は __ia64__ を定義してくれないので configure の結果を使う * configure で __libc_ia64_register_backing_store_base の存 在をテスト * register stack の底は (ほかに手段がなければ) プログラム起 動初期の bsp から得る * rb_thread_save_context, stack_extend で stack pointer < &v < th->stk_pos < frame pointer な状態で 再帰が終了して current stack frame が memcpy で破壊される ことがあったので current stack frame 中の変数じゃなくて呼 出元の変数のアドレスを使用する (*1) * register stack も普通のスタックと同様に重ならないように伸 ばす * スタックの底を変数のアドレスから得る場合に、ruby_init から 呼んでいる Init_stack では浅すぎることがあったので main で 設定する (*1) (*1) 原理的には IA64 以外で起きてもおかしくない なお、HP aC++/ANSI C でも -O0 で make all install test まで はいきますが、test-all はまだうまく動きません。 -O0 でしか動かない原因はわかっていて、gcc での getcontext の 話と同じです。悪いことに Intel C++ Compiler も HP aC++/ANSI C も setjmp にしても避けられなくて、gcc でのごまかしが効かない 感じです。gcc 4.0.3 みたいにコンパイラ側で対処してくれるとい いんですが。 どうでしょう? Index: common.mk =================================================================== RCS file: /src/ruby/common.mk,v retrieving revision 1.21 diff -u -p -r1.21 common.mk --- common.mk 16 Nov 2005 14:25:06 -0000 1.21 +++ common.mk 27 Dec 2005 03:31:15 -0000 @@ -196,6 +196,7 @@ nt.$(OBJEXT): {$(VPATH)}nt.c x68.$(OBJEXT): {$(VPATH)}x68.c os2.$(OBJEXT): {$(VPATH)}os2.c dl_os2.$(OBJEXT): {$(VPATH)}dl_os2.c +ia64.$(OBJEXT): {$(VPATH)}ia64.s # when I use -I., there is confliction at "OpenFile" # so, set . into environment varible "include" Index: configure.in =================================================================== RCS file: /src/ruby/configure.in,v retrieving revision 1.292 diff -u -p -r1.292 configure.in --- configure.in 11 Nov 2005 23:37:32 -0000 1.292 +++ configure.in 27 Dec 2005 03:31:15 -0000 @@ -451,7 +451,7 @@ AC_CHECK_HEADERS(stdlib.h string.h unist fcntl.h sys/fcntl.h sys/select.h sys/time.h sys/times.h sys/param.h\ syscall.h pwd.h grp.h a.out.h utime.h memory.h direct.h sys/resource.h \ sys/mkdev.h sys/utime.h netinet/in_systm.h float.h ieeefp.h pthread.h \ - ucontext.h intrinsics.h unwind.h) + ucontext.h intrinsics.h) dnl Check additional types. AC_CHECK_SIZEOF(rlim_t, 0, [ @@ -612,18 +612,16 @@ AC_C_INLINE AC_C_VOLATILE if test x"$target_cpu" = xia64; then - if test x"$ac_cv_header_unwind_h" = xyes -a x"$ac_cv_func__UNW_createContextForSelf" = xyes; then - LIBS="-lunwind $LIBS" - else - AC_CACHE_CHECK(IA64 backing store member in mcontext_t, rb_cv_ia64_bspstore, - [rb_cv_ia64_bspstore=no; - for mem in mc_special.bspstore sc_ar_bsp; do - AC_TRY_COMPILE([#include <ucontext.h> -],[ucontext_t ctx; ctx.uc_mcontext.$mem = 0;], [rb_cv_ia64_bspstore=$mem; break]) - done]) - if test "$rb_cv_ia64_bspstore" != no; then - AC_DEFINE_UNQUOTED(IA64_BSPSTORE, $rb_cv_ia64_bspstore) - fi + AC_LIBOBJ([ia64]) + # use IA64 instead of __ia64__ because + # HP aC++ doesn't define it. (HP aC++ define __ia64.) + AC_DEFINE(IA64) + AC_TRY_LINK( + [extern unsigned long __libc_ia64_register_backing_store_base;], + [unsigned long p = __libc_ia64_register_backing_store_base;], + [rb_cv___libc_ia64_register_backing_store_base=yes; break]) + if test $rb_cv___libc_ia64_register_backing_store_base = yes; then + AC_DEFINE(HAVE___LIBC_IA64_REGISTER_BACKING_STORE_BASE) fi fi Index: defines.h =================================================================== RCS file: /src/ruby/defines.h,v retrieving revision 1.47 diff -u -p -r1.47 defines.h --- defines.h 6 Dec 2005 07:52:18 -0000 1.47 +++ defines.h 27 Dec 2005 03:31:15 -0000 @@ -230,9 +230,10 @@ flush_register_windows(void) ; } # define FLUSH_REGISTER_WINDOWS flush_register_windows() -#elif defined(__ia64__) -NOINLINE(void flush_register_windows(void)); -# define FLUSH_REGISTER_WINDOWS flush_register_windows() +#elif defined(IA64) +void *rb_ia64_bsp(void); +void rb_ia64_flushrs(void); +# define FLUSH_REGISTER_WINDOWS rb_ia64_flushrs() #else # define FLUSH_REGISTER_WINDOWS ((void)0) #endif Index: eval.c =================================================================== RCS file: /src/ruby/eval.c,v retrieving revision 1.857 diff -u -p -r1.857 eval.c --- eval.c 20 Dec 2005 13:41:29 -0000 1.857 +++ eval.c 27 Dec 2005 03:31:15 -0000 @@ -144,7 +144,7 @@ rb_jump_context(env, val) "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o7", \ "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", \ "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%i7"); }) -#elif defined(__ia64__) +#elif defined(IA64) static jmp_buf function_call_may_return_twice_jmp_buf; int function_call_may_return_twice_false = 0; #define FUNCTION_CALL_MAY_RETURN_TWICE \ @@ -9482,23 +9482,6 @@ Init_Binding(void) rb_define_global_function("binding", rb_f_binding, 0); } -#ifdef __ia64__ -#if defined(__FreeBSD__) -/* - * FreeBSD/ia64 currently does not have a way for a process to get the - * base address for the RSE backing store, so hardcode it. - */ -#define __libc_ia64_register_backing_store_base (4ULL<<61) -#else -#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF) -#include <unwind.h> -#else -#pragma weak __libc_ia64_register_backing_store_base -extern unsigned long __libc_ia64_register_backing_store_base; -#endif -#endif -#endif - /* Windows SEH refers data on the stack. */ #undef SAVE_WIN32_EXCEPTION_LIST #if defined _WIN32 || defined __CYGWIN__ @@ -9713,7 +9696,8 @@ struct thread { long stk_max; VALUE *stk_ptr; VALUE *stk_pos; -#ifdef __ia64__ +#ifdef IA64 + VALUE *bstr_pos; VALUE *bstr_ptr; long bstr_len; #endif @@ -9965,7 +9949,7 @@ thread_mark(rb_thread_t th) #if defined(THINK_C) || defined(__human68k__) rb_gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2); #endif -#ifdef __ia64__ +#ifdef IA64 if (th->bstr_ptr) { rb_gc_mark_locations(th->bstr_ptr, th->bstr_ptr+th->bstr_len); } @@ -10023,7 +10007,7 @@ thread_free(rb_thread_t th) { if (th->stk_ptr) free(th->stk_ptr); th->stk_ptr = 0; -#ifdef __ia64__ +#ifdef IA64 if (th->bstr_ptr) free(th->bstr_ptr); th->bstr_ptr = 0; #endif @@ -10065,6 +10049,9 @@ static const char *th_signm; #define RESTORE_EXIT 7 extern VALUE *rb_gc_stack_start; +#ifdef IA64 +extern VALUE *rb_gc_register_stack_start; +#endif static void rb_thread_save_context(rb_thread_t th) @@ -10085,27 +10072,11 @@ rb_thread_save_context(rb_thread_t th) th->stk_len = len; FLUSH_REGISTER_WINDOWS; MEMCPY(th->stk_ptr, th->stk_pos, VALUE, th->stk_len); -#ifdef __ia64__ - { - VALUE *top, *bot; -#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF) - _Unwind_Context *unwctx = _UNW_createContextForSelf(); - - _UNW_currentContext(unwctx); - bot = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSP); - top = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSPSTORE); - _UNW_destroyContext(unwctx); -#else - ucontext_t ctx; - - getcontext(&ctx); - bot = (VALUE*)__libc_ia64_register_backing_store_base; - top = (VALUE*)ctx.uc_mcontext.IA64_BSPSTORE; -#endif - th->bstr_len = top - bot; - REALLOC_N(th->bstr_ptr, VALUE, th->bstr_len); - MEMCPY(th->bstr_ptr, bot, VALUE, th->bstr_len); - } +#ifdef IA64 + th->bstr_pos = rb_gc_register_stack_start; + th->bstr_len = (VALUE*)rb_ia64_bsp() - th->bstr_pos; + REALLOC_N(th->bstr_ptr, VALUE, th->bstr_len); + MEMCPY(th->bstr_ptr, th->bstr_pos, VALUE, th->bstr_len); #endif #ifdef SAVE_WIN32_EXCEPTION_LIST th->win32_exception_list = win32_get_exception_list(); @@ -10181,42 +10152,17 @@ rb_thread_switch(int n) rb_thread_switch((FLUSH_REGISTER_WINDOWS, ruby_setjmp((th)->context)))) NORETURN(static void rb_thread_restore_context(rb_thread_t,int)); -NOINLINE(static void stack_extend(rb_thread_t, int)); +NORETURN(NOINLINE(static void rb_thread_restore_context_0(rb_thread_t,int,void*))); +NORETURN(NOINLINE(static void stack_extend(rb_thread_t, int, VALUE *))); static void -stack_extend(rb_thread_t th, int exit) +rb_thread_restore_context_0(rb_thread_t th, int exit, void *vp) { - VALUE space[1024]; - - memset(space, 0, 1); /* prevent array from optimization */ - rb_thread_restore_context(th, exit); -} - -static void -rb_thread_restore_context(rb_thread_t th, int exit) -{ - VALUE v; + /* vp prevents tail call */ static rb_thread_t tmp; static int ex; static VALUE tval; - if (!th->stk_ptr) rb_bug("unsaved context"); - -#if STACK_GROW_DIRECTION < 0 - if (&v > th->stk_pos) stack_extend(th, exit); -#elif STACK_GROW_DIRECTION > 0 - if (&v < th->stk_pos + th->stk_len) stack_extend(th, exit); -#else - if (&v < rb_gc_stack_start) { - /* Stack grows downward */ - if (&v > th->stk_pos) stack_extend(th, exit); - } - else { - /* Stack grows upward */ - if (&v < th->stk_pos + th->stk_len) stack_extend(th, exit); - } -#endif - rb_trap_immediate = 0; /* inhibit interrupts from here */ ruby_frame = th->frame; ruby_scope = th->scope; @@ -10242,20 +10188,8 @@ rb_thread_restore_context(rb_thread_t th ex = exit; FLUSH_REGISTER_WINDOWS; MEMCPY(tmp->stk_pos, tmp->stk_ptr, VALUE, tmp->stk_len); -#ifdef __ia64__ - { - VALUE *base; -#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF) - _Unwind_Context *unwctx = _UNW_createContextForSelf(); - - _UNW_currentContext(unwctx); - base = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSP); - _UNW_destroyContext(unwctx); -#else - base = (VALUE*)__libc_ia64_register_backing_store_base; -#endif - MEMCPY(base, tmp->bstr_ptr, VALUE, tmp->bstr_len); - } +#ifdef IA64 + MEMCPY(tmp->bstr_pos, tmp->bstr_ptr, VALUE, tmp->bstr_len); #endif tval = rb_lastline_get(); @@ -10268,6 +10202,73 @@ rb_thread_restore_context(rb_thread_t th ruby_longjmp(tmp->context, ex); } +#ifdef IA64 +#define C(a) rse_##a##0, rse_##a##1, rse_##a##2, rse_##a##3, rse_##a##4 +#define E(a) rse_##a##0= rse_##a##1= rse_##a##2= rse_##a##3= rse_##a##4 +static volatile int C(a), C(b), C(c), C(d), C(e); +static volatile int C(f), C(g), C(h), C(i), C(j); +static volatile int C(k), C(l), C(m), C(n), C(o); +static volatile int C(p), C(q), C(r), C(s), C(t); +int rb_dummy_false = 0; +NORETURN(NOINLINE(static void register_stack_extend(rb_thread_t, int, void *, VALUE *))); +static void +register_stack_extend(rb_thread_t th, int exit, void *vp, VALUE *curr_bsp) +{ + if (rb_dummy_false) { + /* use registers as much as possible */ + E(a) = E(b) = E(c) = E(d) = E(e) = + E(f) = E(g) = E(h) = E(i) = E(j) = + E(k) = E(l) = E(m) = E(n) = E(o) = + E(p) = E(q) = E(r) = E(s) = E(t) = 0; + E(a) = E(b) = E(c) = E(d) = E(e) = + E(f) = E(g) = E(h) = E(i) = E(j) = + E(k) = E(l) = E(m) = E(n) = E(o) = + E(p) = E(q) = E(r) = E(s) = E(t) = 0; + } + if (curr_bsp < th->bstr_pos+th->bstr_len) { + register_stack_extend(th, exit, &exit, (VALUE*)rb_ia64_bsp()); + } + rb_thread_restore_context_0(th, exit, &exit); +} +#undef C +#undef E +#endif + +static void +stack_extend(rb_thread_t th, int exit, VALUE *addr_in_prev_frame) +{ +#define STACK_PAD_SIZE 1024 + VALUE space[STACK_PAD_SIZE]; + +#if STACK_GROW_DIRECTION < 0 + if (addr_in_prev_frame > th->stk_pos) stack_extend(th, exit, &space[0]); +#elif STACK_GROW_DIRECTION > 0 + if (addr_in_prev_frame < th->stk_pos + th->stk_len) stack_extend(th, exit, &space[STACK_PAD_SIZE-1]); +#else + if (addr_in_prev_frame < rb_gc_stack_start) { + /* Stack grows downward */ + if (addr_in_prev_frame > th->stk_pos) stack_extend(th, exit, &space[0]); + } + else { + /* Stack grows upward */ + if (addr_in_prev_frame < th->stk_pos + th->stk_len) stack_extend(th, exit, &space[STACK_PAD_SIZE-1]); + } +#endif +#ifdef IA64 + register_stack_extend(th, exit, space, (VALUE*)rb_ia64_bsp()); +#else + rb_thread_restore_context_0(th, exit, space); +#endif +} + +static void +rb_thread_restore_context(rb_thread_t th, int exit) +{ + VALUE v; + if (!th->stk_ptr) rb_bug("unsaved context"); + stack_extend(th, exit, &v); +} + static void rb_thread_ready(rb_thread_t th) { @@ -11453,7 +11454,7 @@ rb_thread_group(VALUE thread) return group; } -#ifdef __ia64__ +#ifdef IA64 # define IA64_INIT(x) x #else # define IA64_INIT(x) @@ -13048,13 +13049,3 @@ rb_exec_recursive(VALUE (*func)(VALUE, V return result; } } - -/* flush_register_windows must not be inlined because flushrs doesn't flush - * current frame in register stack. */ -#ifdef __ia64__ -void flush_register_windows(void) -{ - __asm__ ("flushrs"); -} -#endif - Index: gc.c =================================================================== RCS file: /src/ruby/gc.c,v retrieving revision 1.223 diff -u -p -r1.223 gc.c --- gc.c 16 Dec 2005 04:58:47 -0000 1.223 +++ gc.c 27 Dec 2005 03:31:15 -0000 @@ -30,24 +30,6 @@ #include <sys/resource.h> #endif -#ifdef __ia64__ -#include <ucontext.h> -#if defined(__FreeBSD__) -/* - * FreeBSD/ia64 currently does not have a way for a process to get the - * base address for the RSE backing store, so hardcode it. - */ -#define __libc_ia64_register_backing_store_base (4ULL<<61) -#else -#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF) -#include <unwind.h> -#else -#pragma weak __libc_ia64_register_backing_store_base -extern unsigned long __libc_ia64_register_backing_store_base; -#endif -#endif -#endif - #if defined _WIN32 || defined __CYGWIN__ #include <windows.h> #endif @@ -429,6 +411,10 @@ rb_data_object_alloc(VALUE klass, void * extern st_table *rb_class_tbl; VALUE *rb_gc_stack_start = 0; +#ifdef IA64 +VALUE *rb_gc_register_stack_start = 0; +#endif + #ifdef DJGPP /* set stack size (http://www.delorie.com/djgpp/v2faq/faq15_9.html) */ @@ -1327,30 +1313,10 @@ garbage_collect(void) else rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1); #endif -#ifdef __ia64__ - /* mark backing store (flushed register window on the stack) */ +#ifdef IA64 + /* mark backing store (flushed register stack) */ /* the basic idea from guile GC code */ - { - ucontext_t ctx; - VALUE *top, *bot; -#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF) - _Unwind_Context *unwctx = _UNW_createContextForSelf(); -#endif - - getcontext(&ctx); - mark_locations_array((VALUE*)&ctx.uc_mcontext, - ((size_t)(sizeof(VALUE)-1 + sizeof ctx.uc_mcontext)/sizeof(VALUE))); -#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF) - _UNW_currentContext(unwctx); - bot = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSP); - top = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSPSTORE); - _UNW_destroyContext(unwctx); -#else - bot = (VALUE*)__libc_ia64_register_backing_store_base; - top = (VALUE*)ctx.uc_mcontext.IA64_BSPSTORE; -#endif - rb_gc_mark_locations(bot, top); - } + rb_gc_mark_locations(rb_gc_register_stack_start, (VALUE*)rb_ia64_bsp()); #endif #if defined(__human68k__) || defined(__mc68000__) rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2), @@ -1422,6 +1388,28 @@ ruby_set_stack_size(size_t size) void Init_stack(VALUE *addr) { +#ifdef IA64 + if (rb_gc_register_stack_start == 0) { +# if defined(__FreeBSD__) + /* + * FreeBSD/ia64 currently does not have a way for a process to get the + * base address for the RSE backing store, so hardcode it. + */ + rb_gc_register_stack_start = (4ULL<<61); +# elif defined(HAVE___LIBC_IA64_REGISTER_BACKING_STORE_BASE) +# pragma weak __libc_ia64_register_backing_store_base + extern unsigned long __libc_ia64_register_backing_store_base; + rb_gc_register_stack_start = (VALUE*)__libc_ia64_register_backing_store_base; +# endif + } + { + VALUE *bsp = (VALUE*)rb_ia64_bsp(); + if (rb_gc_register_stack_start == 0 || + bsp < rb_gc_register_stack_start) { + rb_gc_register_stack_start = bsp; + } + } +#endif #if defined(_WIN32) || defined(__CYGWIN__) MEMORY_BASIC_INFORMATION m; memset(&m, 0, sizeof(m)); @@ -1430,8 +1418,10 @@ Init_stack(VALUE *addr) STACK_UPPER((VALUE *)&m, (VALUE *)m.BaseAddress, (VALUE *)((char *)m.BaseAddress + m.RegionSize) - 1); #elif defined(STACK_END_ADDRESS) - extern void *STACK_END_ADDRESS; - rb_gc_stack_start = STACK_END_ADDRESS; + { + extern void *STACK_END_ADDRESS; + rb_gc_stack_start = STACK_END_ADDRESS; + } #else if (!addr) addr = (VALUE *)&addr; STACK_UPPER(&addr, addr, ++addr); @@ -1458,6 +1448,37 @@ Init_stack(VALUE *addr) #endif } +void ruby_init_stack(VALUE *addr +#ifdef IA64 + , void *bsp +#endif + ) +{ + if (!rb_gc_stack_start || + STACK_UPPER(&addr, + rb_gc_stack_start > addr, + rb_gc_stack_start < addr)) { + rb_gc_stack_start = addr; + } +#ifdef IA64 + if (!rb_gc_register_stack_start || + (VALUE*)bsp < rb_gc_register_stack_start) { + rb_gc_register_stack_start = (VALUE*)bsp; + } +#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 +} /* * Document-class: ObjectSpace Index: main.c =================================================================== RCS file: /src/ruby/main.c,v retrieving revision 1.16 diff -u -p -r1.16 main.c --- main.c 19 Dec 2005 14:31:09 -0000 1.16 +++ main.c 27 Dec 2005 03:31:15 -0000 @@ -36,8 +36,11 @@ main(int argc, char **argv, char **envp) argc = ccommand(&argv); #endif - ruby_init(); - ruby_options(argc, argv); - ruby_run(); + { + RUBY_INIT_STACK + ruby_init(); + ruby_options(argc, argv); + ruby_run(); + } return 0; } Index: numeric.c =================================================================== RCS file: /src/ruby/numeric.c,v retrieving revision 1.132 diff -u -p -r1.132 numeric.c --- numeric.c 7 Dec 2005 08:41:59 -0000 1.132 +++ numeric.c 27 Dec 2005 03:31:15 -0000 @@ -1975,6 +1975,10 @@ static VALUE fix_mul(VALUE x, VALUE y) { if (FIXNUM_P(y)) { +#ifdef __HP_cc +/* avoids an optimization bug of HP aC++/ANSI C B3910B A.06.05 [Jul 25 2005] */ + volatile +#endif long a, b, c; VALUE r; Index: ruby.h =================================================================== RCS file: /src/ruby/ruby.h,v retrieving revision 1.127 diff -u -p -r1.127 ruby.h --- ruby.h 6 Dec 2005 07:52:17 -0000 1.127 +++ ruby.h 27 Dec 2005 03:31:15 -0000 @@ -583,6 +583,17 @@ NORETURN(void rb_throw(const char*,VALUE VALUE rb_require(const char*); +#ifdef IA64 +void ruby_init_stack(VALUE*, void*); +#define RUBY_INIT_STACK \ + VALUE variable_in_this_stack_frame; \ + ruby_init_stack(&variable_in_this_stack_frame, rb_ia64_bsp()); \ +#else +void ruby_init_stack(VALUE*); +#define RUBY_INIT_STACK \ + VALUE variable_in_this_stack_frame; \ + ruby_init_stack(&variable_in_this_stack_frame); \ +#endif void ruby_init(void); void ruby_options(int, char**); NORETURN(void ruby_run(void)); -- [田中 哲][たなか あきら][Tanaka Akira]