Index: class.c =================================================================== RCS file: /src/ruby/class.c,v retrieving revision 1.51 diff -u -u -r1.51 class.c --- class.c 7 Nov 2002 19:18:10 -0000 1.51 +++ class.c 3 Dec 2002 16:37:09 -0000 @@ -77,7 +77,7 @@ } if (RCLASS(module)->m_tbl) { RCLASS(clone)->m_tbl = st_init_numtable(); - st_foreach(RCLASS(module)->m_tbl, clone_method, RCLASS(clone)->m_tbl); + st_foreach_cont(RCLASS(module)->m_tbl, clone_method, RCLASS(clone)->m_tbl); } return (VALUE)clone; @@ -566,7 +566,7 @@ ary = rb_ary_new(); for (klass = mod; klass; klass = RCLASS(klass)->super) { - st_foreach(RCLASS(klass)->m_tbl, func, ary); + st_foreach_cont(RCLASS(klass)->m_tbl, func, ary); if (!option) break; } p = q = RARRAY(ary)->ptr; pend = p + RARRAY(ary)->len; @@ -644,12 +644,12 @@ ary = rb_ary_new(); klass = CLASS_OF(obj); while (klass && FL_TEST(klass, FL_SINGLETON)) { - st_foreach(RCLASS(klass)->m_tbl, ins_methods_i, ary); + st_foreach_cont(RCLASS(klass)->m_tbl, ins_methods_i, ary); klass = RCLASS(klass)->super; } if (RTEST(all)) { while (klass && TYPE(klass) == T_ICLASS) { - st_foreach(RCLASS(klass)->m_tbl, ins_methods_i, ary); + st_foreach_cont(RCLASS(klass)->m_tbl, ins_methods_i, ary); klass = RCLASS(klass)->super; } } Index: dln.c =================================================================== RCS file: /src/ruby/dln.c,v retrieving revision 1.45 diff -u -u -r1.45 dln.c --- dln.c 2 Dec 2002 07:57:15 -0000 1.45 +++ dln.c 3 Dec 2002 16:37:10 -0000 @@ -476,7 +476,7 @@ dln_print_undef() { fprintf(stderr, " Undefined symbols:\n"); - st_foreach(undef_tbl, undef_print, NULL); + st_foreach_cont(undef_tbl, undef_print, NULL); } static void Index: eval.c =================================================================== RCS file: /src/ruby/eval.c,v retrieving revision 1.357 diff -u -u -r1.357 eval.c --- eval.c 2 Dec 2002 07:57:16 -0000 1.357 +++ eval.c 3 Dec 2002 16:37:14 -0000 @@ -188,6 +188,79 @@ static struct cache_entry cache[CACHE_SIZE]; +#define CACHE_DAMAGE_TYPE 2 +#if CACHE_DAMAGE_TYPE == 1 +static int cache_damage[CACHE_SIZE]; +#define Init_cache() ((void)0) +#define CACHE_DAMAGE(id) (cache_damage[(id)&CACHE_MASK]++) +#define CACHE_UNDAMAGE(id) ((cache_damage[(id)&CACHE_MASK] == 1) ? (cache_damage[(id)&CACHE_MASK] = 0) : 0) +#define CACHE_DAMAGED_P(id) (cache_damage[(id)&CACHE_MASK]) +#define CACHE_CLEAR_DAMAGE() memset(cache_damage, 0, sizeof cache_damage) +#elif CACHE_DAMAGE_TYPE == 2 +static st_table *cache_damage; +#define Init_cache() (cache_damage = st_init_numtable_with_size(CACHE_SIZE)) +#define CACHE_DAMAGE(id) st_insert(cache_damage, (char *)(id), NULL) +#define CACHE_UNDAMAGE(id) ((void)(id)) +#define CACHE_DAMAGED_P(id) st_delete(cache_damage, (char **)&(id), NULL) +#define CACHE_CLEAR_DAMAGE() st_cleanup_safe(cache_damage, 0) +#elif CACHE_DAMAGE_TYPE == 3 +struct damaged_entry { + ID mid; + struct damaged_entry *next; +}; +static struct damaged_entry *cache_damage[CACHE_SIZE]; +#define Init_cache() ((void)0) +#define CACHE_DAMAGE(id) damage(id) +#define CACHE_UNDAMAGE(id) ((void)(id)) +#define CACHE_DAMAGED_P(id) damaged_p(id) +#define CACHE_CLEAR_DAMAGE() clear_damage() +static void damage _((ID id)); +static int damaged_p _((ID id)); +static void clear_damage _((void)); +static void damage(id) + ID id; +{ + struct damaged_entry *ent, **entp = &cache_damage[id & CACHE_MASK]; + for (ent = *entp; ent; ent = ent->next) { + if (ent->mid == id) return; + } + ent = ALLOC(struct damaged_entry); + ent->mid = id; + ent->next = *entp; + *entp = ent; +} +static int damaged_p(id) + ID id; +{ + struct damaged_entry *ent = cache_damage[id & CACHE_MASK]; + for (; ent; ent = ent->next) { + if (ent->mid == id) return 1; + } + return 0; +} +static void clear_damage() +{ + struct damaged_entry **ent = cache_damage, **end = cache_damage + CACHE_SIZE; + for (; ent < end; ent++) { + struct damaged_entry *ptr = *ent; + if (ptr) { + do { + struct damaged_entry *next = ptr->next; + free(ptr); + ptr = next; + } while (ptr); + *ent = NULL; + } + } +} +#else +#define Init_cache() ((void)0) +#define CACHE_DAMAGE(id) ((void)(id)) +#define CACHE_UNDAMAGE(id) ((void)(id)) +#define CACHE_DAMAGED_P(id) (1) +#define CACHE_CLEAR_DAMAGE() ((void)0) +#endif + void rb_clear_cache() { @@ -198,6 +271,7 @@ ent->mid = 0; ent++; } + CACHE_CLEAR_DAMAGE(); } static void @@ -206,6 +280,8 @@ { struct cache_entry *ent, *end; + if (!CACHE_DAMAGED_P(id)) return; + CACHE_UNDAMAGE(id); ent = cache; end = ent + CACHE_SIZE; while (ent < end) { if (ent->mid == id) { @@ -285,6 +361,7 @@ NODE * volatile body; struct cache_entry *ent; + CACHE_DAMAGE(id); if ((body = search_method(klass, id, &origin)) == 0 || !body->nd_body) { /* store empty info in cache */ ent = cache + EXPR1(klass, id); @@ -1083,6 +1160,7 @@ Init_stack((void*)&state); Init_heap(); + Init_cache(); PUSH_SCOPE(); ruby_scope->local_vars = 0; ruby_scope->local_tbl = 0; Index: gc.c =================================================================== RCS file: /src/ruby/gc.c,v retrieving revision 1.112 diff -u -u -r1.112 gc.c --- gc.c 29 Oct 2002 21:35:27 -0000 1.112 +++ gc.c 3 Dec 2002 16:37:15 -0000 @@ -561,7 +561,13 @@ st_table *tbl; { if (!tbl) return; - st_foreach(tbl, mark_entry, 0); +#ifdef USE_ST_FOREACH + ST_FOREACH(tbl,( + rb_gc_mark((VALUE)ST_FOREACH_VALUE) + )); +#else + st_foreach_cont(tbl, mark_entry, 0); +#endif } static int Index: hash.c =================================================================== RCS file: /src/ruby/hash.c,v retrieving revision 1.82 diff -u -u -r1.82 hash.c --- hash.c 2 Dec 2002 07:57:16 -0000 1.82 +++ hash.c 3 Dec 2002 16:37:15 -0000 @@ -149,6 +149,29 @@ } static VALUE +rb_hash_foreach_cont_call(arg) + struct rb_hash_foreach_arg *arg; +{ +#ifdef USE_ST_FOREACH + ST_FOREACH(RHASH(arg->hash)->tbl, { + int status; + st_table *tbl = RHASH(arg->hash)->tbl; + struct st_table_entry **bins = tbl->bins; + + if ((VALUE)ST_FOREACH_KEY == Qundef) continue; + status = (*arg->func)(ST_FOREACH_KEY, (VALUE)ST_FOREACH_VALUE, arg->arg); + if (RHASH(arg->hash)->tbl != tbl || RHASH(arg->hash)->tbl->bins != bins){ + rb_raise(rb_eIndexError, "rehash occurred during iteration"); + } + }); +#else + st_foreach_cont(RHASH(arg->hash)->tbl, rb_hash_foreach_iter, arg); +#endif + return Qnil; +} + + +static VALUE rb_hash_foreach_ensure(hash) VALUE hash; { @@ -178,6 +201,22 @@ return rb_ensure(rb_hash_foreach_call, (VALUE)&arg, rb_hash_foreach_ensure, hash); } +static int +rb_hash_foreach_cont(hash, func, farg) + VALUE hash; + enum st_retval (*func)(); + char *farg; +{ + struct rb_hash_foreach_arg arg; + + RHASH(hash)->iter_lev++; + arg.hash = hash; + arg.func = func; + arg.arg = farg; + return rb_ensure(rb_hash_foreach_cont_call, (VALUE)&arg, rb_hash_foreach_ensure, hash); +} + + static VALUE rb_hash_s_alloc(klass) VALUE klass; @@ -275,7 +314,13 @@ rb_hash_modify(hash); tbl = st_init_table_with_size(&objhash, RHASH(hash)->tbl->num_entries); - st_foreach(RHASH(hash)->tbl, rb_hash_rehash_i, tbl); +#ifdef USE_ST_FOREACH + ST_FOREACH(RHASH(hash)->tbl, { + if ((VALUE)ST_FOREACH_KEY != Qundef) st_insert(tbl, ST_FOREACH_KEY, ST_FOREACH_VALUE); + }); +#else + st_foreach_cont(RHASH(hash)->tbl, rb_hash_rehash_i, tbl); +#endif st_free_table(RHASH(hash)->tbl); RHASH(hash)->tbl = tbl; @@ -582,7 +627,15 @@ hash2 = to_hash(hash2); if (hash == hash2) return hash; rb_hash_clear(hash); - st_foreach(RHASH(hash2)->tbl, replace_i, hash); +#ifdef USE_ST_FOREACH + ST_FOREACH(RHASH(hash2)->tbl, { + if ((VALUE)ST_FOREACH_KEY != Qundef) { + rb_hash_aset(hash, (VALUE)ST_FOREACH_KEY, (VALUE)ST_FOREACH_VALUE); + } + }); +#else + st_foreach_cont(RHASH(hash2)->tbl, replace_i, hash); +#endif RHASH(hash)->ifnone = RHASH(hash2)->ifnone; if (FL_TEST(hash2, HASH_PROC_DEFAULT)) { FL_SET(hash, HASH_PROC_DEFAULT); @@ -623,7 +676,7 @@ rb_hash_each_value(hash) VALUE hash; { - rb_hash_foreach(hash, each_value_i, 0); + rb_hash_foreach_cont(hash, each_value_i, 0); return hash; } @@ -640,7 +693,7 @@ rb_hash_each_key(hash) VALUE hash; { - rb_hash_foreach(hash, each_key_i, 0); + rb_hash_foreach_cont(hash, each_key_i, 0); return hash; } @@ -657,7 +710,7 @@ rb_hash_each_pair(hash) VALUE hash; { - rb_hash_foreach(hash, each_pair_i, 0); + rb_hash_foreach_cont(hash, each_pair_i, 0); return hash; } @@ -677,7 +730,15 @@ VALUE ary; ary = rb_ary_new(); - st_foreach(RHASH(hash)->tbl, to_a_i, ary); +#ifdef USE_ST_FOREACH + ST_FOREACH(RHASH(hash)->tbl, { + if ((VALUE)ST_FOREACH_KEY != Qundef){ + rb_ary_push(ary, rb_assoc_new((VALUE)ST_FOREACH_KEY, (VALUE)ST_FOREACH_VALUE)); + } + }); +#else + st_foreach_cont(RHASH(hash)->tbl, to_a_i, ary); +#endif if (OBJ_TAINTED(hash)) OBJ_TAINT(ary); return ary; @@ -720,7 +781,7 @@ VALUE str; str = rb_str_buf_new2("{"); - st_foreach(RHASH(hash)->tbl, inspect_i, str); + st_foreach_cont(RHASH(hash)->tbl, inspect_i, str); rb_str_buf_cat2(str, "}"); OBJ_INFECT(str, hash); @@ -775,7 +836,7 @@ VALUE ary; ary = rb_ary_new(); - st_foreach(RHASH(hash)->tbl, keys_i, ary); + st_foreach_cont(RHASH(hash)->tbl, keys_i, ary); return ary; } @@ -796,7 +857,7 @@ VALUE ary; ary = rb_ary_new(); - st_foreach(RHASH(hash)->tbl, values_i, ary); + st_foreach_cont(RHASH(hash)->tbl, values_i, ary); return ary; } @@ -898,7 +959,7 @@ { VALUE h = rb_hash_new(); - st_foreach(RHASH(hash)->tbl, rb_hash_invert_i, h); + st_foreach_cont(RHASH(hash)->tbl, rb_hash_invert_i, h); return h; } @@ -931,10 +992,10 @@ { hash2 = to_hash(hash2); if (rb_block_given_p()) { - st_foreach(RHASH(hash2)->tbl, rb_hash_update_block_i, hash1); + st_foreach_cont(RHASH(hash2)->tbl, rb_hash_update_block_i, hash1); } else { - st_foreach(RHASH(hash2)->tbl, rb_hash_update_i, hash1); + st_foreach_cont(RHASH(hash2)->tbl, rb_hash_update_i, hash1); } return hash1; } Index: object.c =================================================================== RCS file: /src/ruby/object.c,v retrieving revision 1.94 diff -u -u -r1.94 object.c --- object.c 3 Nov 2002 11:04:17 -0000 1.94 +++ object.c 3 Dec 2002 16:37:17 -0000 @@ -240,7 +240,7 @@ inspect_obj(obj, str) VALUE obj, str; { - st_foreach(ROBJECT(obj)->iv_tbl, inspect_i, str); + st_foreach_cont(ROBJECT(obj)->iv_tbl, inspect_i, str); rb_str_cat2(str, ">"); RSTRING(str)->ptr[0] = '#'; OBJ_INFECT(str, obj); Index: st.c =================================================================== RCS file: /src/ruby/st.c,v retrieving revision 1.23 diff -u -u -r1.23 st.c --- st.c 2 Dec 2002 07:57:16 -0000 1.23 +++ st.c 3 Dec 2002 16:37:17 -0000 @@ -11,15 +11,6 @@ #include #endif -typedef struct st_table_entry st_table_entry; - -struct st_table_entry { - unsigned int hash; - char *key; - char *record; - st_table_entry *next; -}; - #define ST_DEFAULT_MAX_DENSITY 5 #define ST_DEFAULT_INIT_TABLE_SIZE 11 @@ -478,6 +469,7 @@ table->num_entries = num_entries; } +#ifndef USE_ST_FOREACH_MACRO void st_foreach(table, func, arg) st_table *table; @@ -486,7 +478,7 @@ { st_table_entry *ptr, *last, *tmp; enum st_retval retval; - int i; + int i, num_bins; for(i = 0; i < table->num_bins; i++) { last = 0; @@ -514,6 +506,7 @@ } } } +#endif static int strhash(string) Index: st.h =================================================================== RCS file: /src/ruby/st.h,v retrieving revision 1.3 diff -u -u -r1.3 st.h --- st.h 5 Jan 2000 04:37:12 -0000 1.3 +++ st.h 3 Dec 2002 16:37:17 -0000 @@ -13,6 +13,15 @@ int (*hash)(); }; +typedef struct st_table_entry st_table_entry; + +struct st_table_entry { + unsigned int hash; + char *key; + char *record; + st_table_entry *next; +}; + struct st_table { struct st_hash_type *type; int num_bins; @@ -23,6 +32,48 @@ #define st_is_member(table,key) st_lookup(table,key,(char **)0) enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE}; + +#define USE_ST_FOREACH + +#define st_foreach_cont(table, func, arg) { \ + st_table_entry *ptr; \ + int i; \ + for(i = 0; i < table->num_bins; i++) { \ + for(ptr = table->bins[i]; ptr != 0; ptr = ptr->next) { \ + func(ptr->key, ptr->record, arg); \ + } \ + } \ +} + +#ifdef USE_ST_FOREACH +#define ST_FOREACH(table, code) do { \ + st_table *st_tbl = (table); \ + st_table_entry *st_ptr, *st_last; \ + int st_idx; \ + for (st_idx = 0; st_idx < st_tbl->num_bins; ++st_idx) { \ + st_last = 0; \ + for (st_ptr = st_tbl->bins[st_idx]; st_ptr; st_ptr = st_ptr->next){ \ + code; \ + } \ + } \ +} while(0) + +#define ST_DELETE_CURRENT_ITEM() do { \ + st_table_entry *tmp = st_ptr; \ + st_ptr = st_ptr->next; \ + if (st_last == 0) { \ + st_tbl->bins[st_idx] = st_ptr; \ + } \ + else { \ + st_last = st_ptr; \ + } \ + st_tbl->num_entries--; \ + free(tmp); \ +} while (0) + +#define ST_FOREACH_KEY (st_ptr->key) +#define ST_FOREACH_VALUE (st_ptr->record) +#endif st_table *st_init_table(); st_table *st_init_table_with_size(); Index: variable.c =================================================================== RCS file: /src/ruby/variable.c,v retrieving revision 1.73 diff -u -u -r1.73 variable.c --- variable.c 23 Oct 2002 08:20:35 -0000 1.73 +++ variable.c 3 Dec 2002 16:37:18 -0000 @@ -477,7 +477,7 @@ void rb_gc_mark_global_tbl() { - st_foreach(rb_global_tbl, mark_global_entry, 0); + st_foreach_cont(rb_global_tbl, mark_global_entry, 0); } static ID @@ -745,7 +745,7 @@ char buf[4]; char *s = "&`'+123456789"; - st_foreach(rb_global_tbl, gvar_i, ary); + st_foreach_cont(rb_global_tbl, gvar_i, ary); if (!NIL_P(rb_backref_get())) { while (*s) { sprintf(buf, "$%c", *s++); @@ -911,7 +911,7 @@ st_table *tbl; { if (rb_special_const_p(obj)) { - st_foreach(tbl, givar_mark_i, 0); + st_foreach_cont(tbl, givar_mark_i, 0); } return ST_CONTINUE; } @@ -921,7 +921,7 @@ { if (!generic_iv_tbl) return; if (special_generic_ivar == 0) return; - st_foreach(generic_iv_tbl, givar_i, 0); + st_foreach_cont(generic_iv_tbl, givar_i, 0); } void @@ -1045,7 +1045,7 @@ case T_CLASS: case T_MODULE: if (ROBJECT(obj)->iv_tbl) { - st_foreach(ROBJECT(obj)->iv_tbl, ivar_i, ary); + st_foreach_cont(ROBJECT(obj)->iv_tbl, ivar_i, ary); } break; default: @@ -1054,7 +1054,7 @@ st_table *tbl; if (st_lookup(generic_iv_tbl, obj, &tbl)) { - st_foreach(tbl, ivar_i, ary); + st_foreach_cont(tbl, ivar_i, ary); } } break; @@ -1247,12 +1247,12 @@ tbl = st_init_numtable(); } if (RCLASS(mod)->iv_tbl) { - st_foreach(RCLASS(mod)->iv_tbl, sv_i, tbl); + st_foreach_cont(RCLASS(mod)->iv_tbl, sv_i, tbl); } if ((VALUE)mod == rb_cObject) { - st_foreach(rb_class_tbl, sv_i, tbl); + st_foreach_cont(rb_class_tbl, sv_i, tbl); if (autoload_tbl) { - st_foreach(autoload_tbl, autoload_i, tbl); + st_foreach_cont(autoload_tbl, autoload_i, tbl); } } return tbl; @@ -1289,7 +1289,7 @@ if (!tbl) return rb_ary_new2(0); ary = rb_ary_new2(tbl->num_entries); - st_foreach(tbl, list_i, ary); + st_foreach_cont(tbl, list_i, ary); st_free_table(tbl); return ary; @@ -1609,7 +1609,7 @@ for (;;) { if (RCLASS(obj)->iv_tbl) { - st_foreach(RCLASS(obj)->iv_tbl, cv_i, ary); + st_foreach_cont(RCLASS(obj)->iv_tbl, cv_i, ary); } obj = RCLASS(obj)->super; if (!obj) break;