In article <E1HygwQ-0001OA-4f / x31>,
  Yukihiro Matsumoto <matz / ruby-lang.org> writes:

> |# make testは実行できて(859 failed 14)
> |# make TESTS=ruby test-allはIllegal instructionでした
>
> Illegal instructionはいずれ追いかけないといけないでしょうね。

マルチスレッドになったんだから各スレッドの register stack を
GC で scan しないといけないし、Fiber や継続では register
stack を保存・復帰しなきゃいけないのに、そういうコードがない
んだから、そういうコードを足すところからですね。

そうやっても test-all で SEGV しますが、それが ia64 固有かど
うかはよくわかりません。SEGV するのは ia64 だけじゃありませ
んし。

いくらか GC 問題もつぶしましたが、その際の印象として、YARV
では VALUE を含む構造体へのポインタを扱っていて剣呑ですねぇ。

Index: eval_load.c
===================================================================
--- eval_load.c	(revision 12533)
+++ eval_load.c	(working copy)
@@ -574,10 +574,10 @@
 void
 Init_load()
 {
-    rb_load_path = rb_ary_new();
     rb_define_readonly_variable("$:", &rb_load_path);
     rb_define_readonly_variable("$-I", &rb_load_path);
     rb_define_readonly_variable("$LOAD_PATH", &rb_load_path);
+    rb_load_path = rb_ary_new();
 
     rb_define_virtual_variable("$\"", get_loaded_features, 0);
     rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
Index: variable.c
===================================================================
--- variable.c	(revision 12533)
+++ variable.c	(working copy)
@@ -428,7 +428,8 @@
 void
 rb_gc_mark_global_tbl(void)
 {
-    st_foreach_safe(rb_global_tbl, mark_global_entry, 0);
+    if (rb_global_tbl)
+        st_foreach_safe(rb_global_tbl, mark_global_entry, 0);
 }
 
 static ID
Index: thread.c
===================================================================
--- thread.c	(revision 12533)
+++ thread.c	(working copy)
@@ -276,18 +276,28 @@
     rb_thread_t *th = th_ptr;
     th->status = THREAD_KILLED;
     th->machine_stack_start = th->machine_stack_end = 0;
+#ifdef __ia64
+    th->machine_register_stack_start = th->machine_register_stack_end = 0;
+#endif
     native_mutex_destroy(&th->interrupt_lock);
     native_thread_destroy(th);
 }
 
 static int
-thread_start_func_2(rb_thread_t *th, VALUE *stack_start)
+thread_start_func_2(rb_thread_t *th, VALUE *stack_start
+#ifdef __ia64
+    , VALUE *register_stack_start
+#endif
+)
 {
     int state;
     VALUE args = th->first_args;
     rb_proc_t *proc;
     rb_thread_t *join_th;
     th->machine_stack_start = stack_start;
+#ifdef __ia64
+    th->machine_register_stack_start = register_stack_start;
+#endif
     th->thgroup = th->vm->thgroup_default;
     thread_debug("thread start: %p\n", th);
 
@@ -1822,6 +1832,9 @@
 rb_gc_save_machine_context(rb_thread_t *th)
 {
     rb_gc_set_stack_end(&th->machine_stack_end);
+#ifdef __ia64
+    th->machine_register_stack_end = rb_ia64_bsp();
+#endif
     setjmp(th->machine_regs);
 }
 
Index: gc.c
===================================================================
--- gc.c	(revision 12533)
+++ gc.c	(working copy)
@@ -540,7 +540,12 @@
     return (VALUE)data;
 }
 
+#ifdef __ia64
+#define SET_STACK_END (rb_gc_set_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)
+#endif
+
 #define STACK_START (th->machine_stack_start)
 #define STACK_END (th->machine_stack_end)
 
@@ -1384,10 +1389,10 @@
     else
       rb_gc_mark_locations(th->machine_stack_start, th->machine_stack_end + 1);
 #endif
-#ifdef __ia64__
+#ifdef __ia64
     /* mark backing store (flushed register stack) */
     /* the basic idea from guile GC code                         */
-    rb_gc_mark_locations(rb_gc_register_stack_start, (VALUE*)rb_ia64_bsp());
+    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),
@@ -1441,6 +1446,9 @@
 	rb_gc_mark_locations(th->machine_stack_end, th->machine_stack_start);
     }
 #endif
+#ifdef __ia64
+    rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end);
+#endif
 }
 
 
Index: yarvcore.c
===================================================================
--- yarvcore.c	(revision 12533)
+++ yarvcore.c	(working copy)
@@ -395,6 +395,9 @@
 
 VALUE insns_name_array(void);
 extern VALUE *rb_gc_stack_start;
+#ifdef __ia64
+extern VALUE *rb_gc_register_stack_start;
+#endif
 
 static VALUE
 sdr(void)
@@ -542,12 +545,13 @@
     {
 	rb_vm_t *vm = ruby_current_vm;
 	rb_thread_t *th = GET_THREAD();
+        volatile VALUE th_self;
 
 	/* create vm object */
 	vm->self = Data_Wrap_Struct(rb_cVM, vm_mark, vm_free, vm);
 
 	/* create main thread */
-	th->self = Data_Wrap_Struct(rb_cThread, thread_mark, thread_free, th);
+	th_self = th->self = Data_Wrap_Struct(rb_cThread, thread_mark, thread_free, th);
 
 	vm->main_thread = th;
 	vm->running_thread = th;
@@ -557,7 +561,7 @@
 	rb_thread_set_current(th);
 
 	vm->living_threads = st_init_numtable();
-	st_insert(vm->living_threads, th->self, (st_data_t) th->thread_id);
+	st_insert(vm->living_threads, th_self, (st_data_t) th->thread_id);
     }
     yarv_init_redefined_flag();
 }
@@ -575,6 +579,9 @@
     th_init2(th);
     th->vm = vm;
     th->machine_stack_start = rb_gc_stack_start;
+#ifdef __ia64
+    th->machine_register_stack_start = rb_gc_register_stack_start;
+#endif
     rb_thread_set_current_raw(th);
 }
 
Index: yarvcore.h
===================================================================
--- yarvcore.h	(revision 12533)
+++ yarvcore.h	(working copy)
@@ -486,6 +486,10 @@
     /* for GC */
     VALUE *machine_stack_start;
     VALUE *machine_stack_end;
+#ifdef __ia64
+    VALUE *machine_register_stack_start;
+    VALUE *machine_register_stack_end;
+#endif
     jmp_buf machine_regs;
     int mark_stack_len;
 
Index: thread_pthread.ci
===================================================================
--- thread_pthread.ci	(revision 12533)
+++ thread_pthread.ci	(working copy)
@@ -86,7 +86,11 @@
     posix_signal(SIGVTALRM, null_func);
 }
 
-NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start));
+NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start
+#ifdef __ia64
+  , VALUE *register_stack_start
+#endif
+));
 
 static void
 native_thread_destroy(rb_thread_t *th)
@@ -107,7 +111,7 @@
 	VALUE stack_start;
 
 	/* run */
-	thread_start_func_2(th, &stack_start);
+	thread_start_func_2(th, &stack_start, rb_ia64_bsp());
     }
 #if USE_THREAD_CACHE
     if (1) {
Index: cont.c
===================================================================
--- cont.c	(revision 12533)
+++ cont.c	(working copy)
@@ -22,6 +22,11 @@
     VALUE *vm_stack;
     VALUE *machine_stack;
     VALUE *machine_stack_src;
+#ifdef __ia64
+    VALUE *machine_register_stack;
+    VALUE *machine_register_stack_src;
+    int machine_register_stack_size;
+#endif
     rb_thread_t saved_thread;
     rb_jmpbuf_t jmpbuf;
     int machine_stack_size;
@@ -59,6 +64,12 @@
 	    rb_gc_mark_locations(cont->machine_stack,
 				 cont->machine_stack + cont->machine_stack_size);
 	}
+#ifdef __ia64
+	if (cont->machine_register_stack) {
+	    rb_gc_mark_locations(cont->machine_register_stack,
+				 cont->machine_register_stack + cont->machine_register_stack_size);
+	}
+#endif
     }
     MARK_REPORT_LEAVE("cont");
 }
@@ -71,6 +82,9 @@
 	rb_context_t *cont = ptr;
 	FREE_UNLESS_NULL(cont->saved_thread.stack);
 	FREE_UNLESS_NULL(cont->machine_stack);
+#ifdef __ia64
+	FREE_UNLESS_NULL(cont->machine_register_stack);
+#endif
 	FREE_UNLESS_NULL(cont->vm_stack);
 	ruby_xfree(ptr);
     }
@@ -83,6 +97,10 @@
     int size;
 
     rb_gc_set_stack_end(&th->machine_stack_end);
+#ifdef __ia64
+    th->machine_register_stack_end = rb_ia64_bsp();
+#endif
+
     if (th->machine_stack_start > th->machine_stack_end) {
 	size = cont->machine_stack_size = th->machine_stack_start - th->machine_stack_end;
 	cont->machine_stack_src = th->machine_stack_end;
@@ -100,6 +118,20 @@
     }
 
     MEMCPY(cont->machine_stack, cont->machine_stack_src, VALUE, size);
+
+#ifdef __ia64
+    rb_ia64_flushrs();
+    size = cont->machine_register_stack_size = th->machine_register_stack_end - th->machine_register_stack_start;
+    cont->machine_register_stack_src = th->machine_register_stack_start;
+    if (cont->machine_register_stack) {
+	REALLOC_N(cont->machine_register_stack, VALUE, size);
+    }
+    else {
+	cont->machine_register_stack = ALLOC_N(VALUE, size);
+    }
+
+    MEMCPY(cont->machine_register_stack, cont->machine_register_stack_src, VALUE, size);
+#endif
 }
 
 static rb_context_t *
@@ -132,9 +164,11 @@
 {
     rb_context_t *cont;
     rb_thread_t *th;
+    volatile VALUE contval;
 
     th_stack_to_heap(GET_THREAD());
     cont = cont_new(rb_cCont);
+    contval = cont->self;
     th = &cont->saved_thread;
 
     cont->vm_stack = ALLOC_N(VALUE, th->stack_size);
@@ -203,12 +237,51 @@
 	       VALUE, cont->machine_stack_size);
     }
 
+#ifdef __ia64
+    if (cont->machine_register_stack_src) {
+	MEMCPY(cont->machine_register_stack_src, cont->machine_register_stack,
+	       VALUE, cont->machine_register_stack_size);
+    }
+#endif
+
     ruby_longjmp(cont->jmpbuf, 1);
 }
 
 NORETURN(NOINLINE(static void cont_restore_0(rb_context_t *, VALUE *)));
 
+#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_context_t *, VALUE *)));
 static void
+register_stack_extend(rb_context_t *cont, 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 < cont->machine_register_stack_src+cont->machine_register_stack_size) {
+        register_stack_extend(cont, (VALUE*)rb_ia64_bsp());
+    }
+    cont_restore_1(cont);
+}
+#undef C
+#undef E
+#endif
+
+static void
 cont_restore_0(rb_context_t *cont, VALUE *addr_in_prev_frame)
 {
     if (cont->machine_stack_src) {
@@ -238,7 +311,11 @@
 	}
 #endif
     }
+#ifdef __ia64
+    register_stack_extend(cont, (VALUE*)rb_ia64_bsp());
+#else
     cont_restore_1(cont);
+#endif
 }
 
 /*
-- 
[田中 哲][たなか あきら][Tanaka Akira]