From a20a14727f4c15fad7a07b8bd7c39074895aa845 Mon Sep 17 00:00:00 2001 From: ko1 Date: Sun, 26 May 2013 12:37:11 +0000 Subject: [PATCH] * hash.c, include/ruby/ruby.h: support WB protected hash. * constify RHash::ifnone and make new macro RHASH_SET_IFNONE(). * insert write barrier for st_update(). * include/ruby/intern.h: declare rb_hash_set_ifnone(hash, ifnone). * marshal.c (r_object0): use RHASH_SET_IFNONE(). * ext/openssl/ossl_x509name.c (Init_ossl_x509name): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40933 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 12 ++++ ext/openssl/ossl_x509name.c | 2 +- hash.c | 115 ++++++++++++++++++++++++------------ include/ruby/intern.h | 1 + include/ruby/ruby.h | 8 ++- marshal.c | 2 +- 6 files changed, 99 insertions(+), 41 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5b7c2dd0ad..9d33441b99 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +Sun May 26 21:31:46 2013 Koichi Sasada + + * hash.c, include/ruby/ruby.h: support WB protected hash. + * constify RHash::ifnone and make new macro RHASH_SET_IFNONE(). + * insert write barrier for st_update(). + + * include/ruby/intern.h: declare rb_hash_set_ifnone(hash, ifnone). + + * marshal.c (r_object0): use RHASH_SET_IFNONE(). + + * ext/openssl/ossl_x509name.c (Init_ossl_x509name): ditto. + Sat May 25 23:22:38 2013 Kazuki Tsujimoto * test/fiddle/test_c_struct_entry.rb, diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c index 4b397055ab..16a2dfd115 100644 --- a/ext/openssl/ossl_x509name.c +++ b/ext/openssl/ossl_x509name.c @@ -459,7 +459,7 @@ Init_ossl_x509name() */ rb_define_const(cX509Name, "DEFAULT_OBJECT_TYPE", utf8str); hash = rb_hash_new(); - RHASH(hash)->ifnone = utf8str; + RHASH_SET_IFNONE(hash, utf8str); rb_hash_aset(hash, rb_str_new2("C"), ptrstr); rb_hash_aset(hash, rb_str_new2("countryName"), ptrstr); rb_hash_aset(hash, rb_str_new2("serialNumber"), ptrstr); diff --git a/hash.c b/hash.c index f51da37001..bd14e36ffe 100644 --- a/hash.c +++ b/hash.c @@ -32,6 +32,16 @@ static VALUE rb_hash_s_try_convert(VALUE, VALUE); #define HASH_DELETED FL_USER1 #define HASH_PROC_DEFAULT FL_USER2 +/* + * Hash WB strategy: + * 1. Check mutate st_* functions + * * st_insert() + * * st_insert2() + * * st_update() + * * st_add_direct() + * 2. Insert WBs + */ + VALUE rb_hash_freeze(VALUE hash) { @@ -43,6 +53,13 @@ VALUE rb_cHash; static VALUE envtbl; static ID id_hash, id_yield, id_default; +VALUE +rb_hash_set_ifnone(VALUE hash, VALUE ifnone) +{ + OBJ_WRITE(hash, (VALUE *)(&RHASH(hash)->ifnone), ifnone); + return hash; +} + static int rb_any_cmp(VALUE a, VALUE b) { @@ -213,9 +230,9 @@ rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg) static VALUE hash_alloc(VALUE klass) { - NEWOBJ_OF(hash, struct RHash, klass, T_HASH); + NEWOBJ_OF(hash, struct RHash, klass, T_HASH | (RGENGC_WB_PROTECTED_HASH ? FL_WB_PROTECTED : 0)); - RHASH_IFNONE(hash) = Qnil; + RHASH_SET_IFNONE((VALUE)hash, Qnil); return (VALUE)hash; } @@ -250,7 +267,7 @@ rb_hash_dup(VALUE hash) if (FL_TEST(hash, HASH_PROC_DEFAULT)) { FL_SET(ret, HASH_PROC_DEFAULT); } - RHASH_IFNONE(ret) = RHASH_IFNONE(hash); + RHASH_SET_IFNONE(ret, RHASH_IFNONE(hash)); return (VALUE)ret; } @@ -262,8 +279,8 @@ rb_hash_modify_check(VALUE hash) rb_raise(rb_eSecurityError, "Insecure: can't modify hash"); } -struct st_table * -rb_hash_tbl(VALUE hash) +static struct st_table * +hash_tbl(VALUE hash) { if (!RHASH(hash)->ntbl) { RHASH(hash)->ntbl = st_init_table(&objhash); @@ -271,11 +288,18 @@ rb_hash_tbl(VALUE hash) return RHASH(hash)->ntbl; } +struct st_table * +rb_hash_tbl(VALUE hash) +{ + OBJ_WB_GIVEUP(hash); + return hash_tbl(hash); +} + static void rb_hash_modify(VALUE hash) { rb_hash_modify_check(hash); - rb_hash_tbl(hash); + hash_tbl(hash); } NORETURN(static void no_new_key(void)); @@ -285,20 +309,35 @@ no_new_key(void) rb_raise(rb_eRuntimeError, "can't add a new key into hash during iteration"); } -#define NOINSERT_UPDATE_CALLBACK(func) \ -int \ +struct update_callback_arg { + VALUE hash; + st_data_t arg; +}; + +#define NOINSERT_UPDATE_CALLBACK(func) \ +int \ func##_noinsert(st_data_t *key, st_data_t *val, st_data_t arg, int existing) \ -{ \ - if (!existing) no_new_key(); \ - return func(key, val, arg, existing); \ +{ \ + struct update_callback_arg *uc_arg = (struct update_callback_arg *)arg; \ + if (!existing) no_new_key(); \ + return func(uc_arg->hash, key, val, uc_arg->arg, existing); \ +} \ +int \ +func##_insert(st_data_t *key, st_data_t *val, st_data_t arg, int existing) \ +{ \ + struct update_callback_arg *uc_arg = (struct update_callback_arg *)arg; \ + return func(uc_arg->hash, key, val, uc_arg->arg, existing); \ } -#define UPDATE_CALLBACK(iter_lev, func) ((iter_lev) > 0 ? func##_noinsert : func) +#define UPDATE_CALLBACK(iter_lev, func) ((iter_lev) > 0 ? func##_noinsert : func##_insert) + +#define RHASH_UPDATE_ITER(h, iter_lev, key, func, a) do { \ + struct update_callback_arg uc_arg; uc_arg.hash = h; uc_arg.arg = a; \ + st_update(RHASH(h)->ntbl, (st_data_t)(key), \ + UPDATE_CALLBACK((iter_lev), func), \ + (st_data_t)(&uc_arg)); \ +} while (0) -#define RHASH_UPDATE_ITER(hash, iter_lev, key, func, arg) \ - st_update(RHASH(hash)->ntbl, (st_data_t)(key), \ - UPDATE_CALLBACK((iter_lev), func), \ - (st_data_t)(arg)) #define RHASH_UPDATE(hash, key, func, arg) \ RHASH_UPDATE_ITER(hash, RHASH_ITER_LEV(hash), key, func, arg) @@ -358,12 +397,12 @@ rb_hash_initialize(int argc, VALUE *argv, VALUE hash) rb_check_arity(argc, 0, 0); ifnone = rb_block_proc(); default_proc_arity_check(ifnone); - RHASH_IFNONE(hash) = ifnone; + RHASH_SET_IFNONE(hash, ifnone); FL_SET(hash, HASH_PROC_DEFAULT); } else { rb_scan_args(argc, argv, "01", &ifnone); - RHASH_IFNONE(hash) = ifnone; + RHASH_SET_IFNONE(hash, ifnone); } return hash; @@ -709,7 +748,7 @@ static VALUE rb_hash_set_default(VALUE hash, VALUE ifnone) { rb_hash_modify_check(hash); - RHASH_IFNONE(hash) = ifnone; + RHASH_SET_IFNONE(hash, ifnone); FL_UNSET(hash, HASH_PROC_DEFAULT); return ifnone; } @@ -759,7 +798,7 @@ rb_hash_set_default_proc(VALUE hash, VALUE proc) rb_hash_modify_check(hash); if (NIL_P(proc)) { FL_UNSET(hash, HASH_PROC_DEFAULT); - RHASH_IFNONE(hash) = proc; + RHASH_SET_IFNONE(hash, proc); return proc; } b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); @@ -770,7 +809,7 @@ rb_hash_set_default_proc(VALUE hash, VALUE proc) } proc = b; default_proc_arity_check(proc); - RHASH_IFNONE(hash) = proc; + RHASH_SET_IFNONE(hash, proc); FL_SET(hash, HASH_PROC_DEFAULT); return proc; } @@ -1146,17 +1185,17 @@ rb_hash_clear(VALUE hash) } static int -hash_aset(st_data_t *key, st_data_t *val, st_data_t arg, int existing) +hash_aset(VALUE hash, st_data_t *key, st_data_t *val, st_data_t arg, int existing) { - *val = arg; + OBJ_WRITE(hash, (VALUE *)val, arg); return ST_CONTINUE; } static int -hash_aset_str(st_data_t *key, st_data_t *val, st_data_t arg, int existing) +hash_aset_str(VALUE hash, st_data_t *key, st_data_t *val, st_data_t arg, int existing) { - *key = (st_data_t)rb_str_new_frozen((VALUE)*key); - return hash_aset(key, val, arg, existing); + OBJ_WRITE(hash, (VALUE *)key, rb_str_new_frozen((VALUE)*key)); + return hash_aset(hash, key, val, arg, existing); } static NOINSERT_UPDATE_CALLBACK(hash_aset) @@ -1189,7 +1228,7 @@ rb_hash_aset(VALUE hash, VALUE key, VALUE val) rb_hash_modify(hash); if (!tbl) { if (iter_lev > 0) no_new_key(); - tbl = RHASH_TBL(hash); + tbl = hash_tbl(hash); } if (tbl->type == &identhash || rb_obj_class(key) != rb_cString) { RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset, val); @@ -1227,7 +1266,7 @@ rb_hash_initialize_copy(VALUE hash, VALUE hash2) else { FL_UNSET(hash, HASH_PROC_DEFAULT); } - RHASH_IFNONE(hash) = RHASH_IFNONE(hash2); + RHASH_SET_IFNONE(hash, RHASH_IFNONE(hash2)); return hash; } @@ -1252,11 +1291,11 @@ rb_hash_replace(VALUE hash, VALUE hash2) if (hash == hash2) return hash; rb_hash_clear(hash); if (RHASH(hash2)->ntbl) { - rb_hash_tbl(hash); + hash_tbl(hash); RHASH(hash)->ntbl->type = RHASH(hash2)->ntbl->type; } rb_hash_foreach(hash2, replace_i, hash); - RHASH_IFNONE(hash) = RHASH_IFNONE(hash2); + RHASH_SET_IFNONE(hash, RHASH_IFNONE(hash2)); if (FL_TEST(hash2, HASH_PROC_DEFAULT)) { FL_SET(hash, HASH_PROC_DEFAULT); } @@ -1525,7 +1564,7 @@ rb_hash_to_h(VALUE hash) if (FL_TEST(hash, HASH_PROC_DEFAULT)) { FL_SET(ret, HASH_PROC_DEFAULT); } - RHASH_IFNONE(ret) = RHASH_IFNONE(hash); + RHASH_SET_IFNONE(ret, RHASH_IFNONE(hash)); return ret; } return hash; @@ -1832,9 +1871,9 @@ rb_hash_invert(VALUE hash) } static int -rb_hash_update_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existing) +rb_hash_update_callback(VALUE hash, st_data_t *key, st_data_t *value, st_data_t arg, int existing) { - *value = arg; + OBJ_WRITE(hash, (VALUE *)value, (VALUE)arg); return ST_CONTINUE; } @@ -1848,13 +1887,13 @@ rb_hash_update_i(VALUE key, VALUE value, VALUE hash) } static int -rb_hash_update_block_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existing) +rb_hash_update_block_callback(VALUE hash, st_data_t *key, st_data_t *value, st_data_t arg, int existing) { VALUE newvalue = (VALUE)arg; if (existing) { newvalue = rb_yield_values(3, (VALUE)*key, (VALUE)*value, newvalue); } - *value = (st_data_t)newvalue; + OBJ_WRITE(hash, (VALUE *)value, newvalue); return ST_CONTINUE; } @@ -1911,14 +1950,14 @@ struct update_arg { }; static int -rb_hash_update_func_callback(st_data_t *key, st_data_t *value, st_data_t arg0, int existing) +rb_hash_update_func_callback(VALUE hash, st_data_t *key, st_data_t *value, st_data_t arg0, int existing) { struct update_arg *arg = (struct update_arg *)arg0; VALUE newvalue = arg->value; if (existing) { newvalue = (*arg->func)((VALUE)*key, (VALUE)*value, newvalue); } - *value = (st_data_t)newvalue; + OBJ_WRITE(hash, (VALUE *)value, (VALUE)newvalue); return ST_CONTINUE; } @@ -1931,7 +1970,7 @@ rb_hash_update_func_i(VALUE key, VALUE value, VALUE arg0) VALUE hash = arg->hash; arg->value = value; - RHASH_UPDATE(hash, key, rb_hash_update_func_callback, arg); + RHASH_UPDATE(hash, key, rb_hash_update_func_callback, (VALUE)arg); return ST_CONTINUE; } diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 67356531e3..81b93b8971 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -460,6 +460,7 @@ VALUE rb_hash_aset(VALUE, VALUE, VALUE); VALUE rb_hash_clear(VALUE); VALUE rb_hash_delete_if(VALUE); VALUE rb_hash_delete(VALUE,VALUE); +VALUE rb_hash_set_ifnone(VALUE hash, VALUE ifnone); typedef VALUE rb_hash_update_func(VALUE newkey, VALUE oldkey, VALUE value); VALUE rb_hash_update_by(VALUE hash1, VALUE hash2, rb_hash_update_func *func); struct st_table *rb_hash_tbl(VALUE); diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index 8bfd351391..9404d97d80 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -689,6 +689,11 @@ VALUE rb_obj_setup(VALUE obj, VALUE klass, VALUE type); #ifndef RGENGC_WB_PROTECTED_ARRAY #define RGENGC_WB_PROTECTED_ARRAY 1 #endif + +#ifndef RGENGC_WB_PROTECTED_HASH +#define RGENGC_WB_PROTECTED_HASH 1 +#endif + #ifndef RGENGC_WB_PROTECTED_STRING #define RGENGC_WB_PROTECTED_STRING 1 #endif @@ -960,7 +965,7 @@ struct RHash { struct RBasic basic; struct st_table *ntbl; /* possibly 0 */ int iter_lev; - VALUE ifnone; + const VALUE ifnone; }; /* RHASH_TBL allocates st_table if not available. */ #define RHASH_TBL(h) rb_hash_tbl(h) @@ -968,6 +973,7 @@ struct RHash { #define RHASH_IFNONE(h) (RHASH(h)->ifnone) #define RHASH_SIZE(h) (RHASH(h)->ntbl ? RHASH(h)->ntbl->num_entries : 0) #define RHASH_EMPTY_P(h) (RHASH_SIZE(h) == 0) +#define RHASH_SET_IFNONE(h, ifnone) rb_hash_set_ifnone((VALUE)h, ifnone) struct RFile { struct RBasic basic; diff --git a/marshal.c b/marshal.c index 464ef1596f..ef44fb24d0 100644 --- a/marshal.c +++ b/marshal.c @@ -1725,7 +1725,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) } arg->readable += 2; if (type == TYPE_HASH_DEF) { - RHASH_IFNONE(v) = r_object(arg); + RHASH_SET_IFNONE(v, r_object(arg)); } v = r_leave(v, arg); }