[前][次][番号順一覧][スレッド一覧]

ruby-changes:29346

From: ko1 <ko1@a...>
Date: Wed, 19 Jun 2013 06:29:45 +0900 (JST)
Subject: [ruby-changes:29346] ko1:r41398 (trunk): * hash.c: `st_update()' also has same issue of last fix.

ko1	2013-06-19 06:29:30 +0900 (Wed, 19 Jun 2013)

  New Revision: 41398

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=41398

  Log:
    * hash.c: `st_update()' also has same issue of last fix.
      write barriers at callback function are too early.
      All write barriers are executed after `st_update()'

  Modified files:
    trunk/ChangeLog
    trunk/hash.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 41397)
+++ ChangeLog	(revision 41398)
@@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Wed Jun 19 06:26:49 2013  Koichi Sasada  <ko1@a...>
+
+	* hash.c: `st_update()' also has same issue of last fix.
+	  write barriers at callback function are too early.
+	  All write barriers are executed after `st_update()'
+
 Wed Jun 19 04:33:22 2013  Koichi Sasada  <ko1@a...>
 
 	* variable.c (rb_const_set): fix WB miss.
Index: hash.c
===================================================================
--- hash.c	(revision 41397)
+++ hash.c	(revision 41398)
@@ -331,24 +331,51 @@ struct update_callback_arg { https://github.com/ruby/ruby/blob/trunk/hash.c#L331
 int                                                                          \
 func##_noinsert(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;  \
     if (!existing) no_new_key();                                             \
-    return func(uc_arg->hash, key, val, uc_arg->arg, existing);              \
+    return func(key, val, (struct update_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);              \
+    return func(key, val, (struct update_arg *)arg, existing);               \
+}
+
+struct update_arg {
+    st_data_t arg;
+    VALUE hash;
+    VALUE new_key;
+    VALUE old_key;
+    VALUE new_value;
+    VALUE old_value;
+};
+
+static int
+tbl_update(VALUE hash, VALUE key, int (*func)(st_data_t *key, st_data_t *val, st_data_t arg, int existing), st_data_t optional_arg)
+{
+    struct update_arg arg;
+    int result;
+
+    arg.arg = optional_arg;
+    arg.hash = hash;
+    arg.new_key = 0;
+    arg.old_key = Qundef;
+    arg.new_value = 0;
+    arg.old_value = Qundef;
+
+    result = st_update(RHASH(hash)->ntbl, (st_data_t)key, func, (st_data_t)&arg);
+
+    /* write barrier */
+    if (arg.new_key)   OBJ_WRITTEN(hash, arg.old_key, arg.new_key);
+    if (arg.new_value) OBJ_WRITTEN(hash, arg.old_value, arg.new_value);
+
+    return result;
 }
 
 #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));                                     \
+#define RHASH_UPDATE_ITER(h, iter_lev, key, func, a) do {                        \
+    tbl_update((h), (key), UPDATE_CALLBACK((iter_lev), func), (st_data_t)(a)); \
 } while (0)
 
 #define RHASH_UPDATE(hash, key, func, arg) \
@@ -1198,26 +1225,27 @@ rb_hash_clear(VALUE hash) https://github.com/ruby/ruby/blob/trunk/hash.c#L1225
 }
 
 static int
-hash_aset(VALUE hash, st_data_t *key, st_data_t *val, st_data_t arg, int existing)
+hash_aset(st_data_t *key, st_data_t *val, struct update_arg *arg, int existing)
 {
     if (existing) {
-	OBJ_WRITTEN(hash, *val, arg);
+	arg->new_value = arg->arg;
+	arg->old_value = *val;
     }
     else {
-	OBJ_WRITTEN(hash, Qundef, *key);
-	OBJ_WRITTEN(hash, Qundef, arg);
+	arg->new_key = *key;
+	arg->new_value = arg->arg;
     }
-    *val = arg;
+    *val = arg->arg;
     return ST_CONTINUE;
 }
 
 static int
-hash_aset_str(VALUE hash, st_data_t *key, st_data_t *val, st_data_t arg, int existing)
+hash_aset_str(st_data_t *key, st_data_t *val, struct update_arg *arg, int existing)
 {
     if (!existing) {
 	*key = rb_str_new_frozen((VALUE)*key);
     }
-    return hash_aset(hash, key, val, arg, existing);
+    return hash_aset(key, val, arg, existing);
 }
 
 static NOINSERT_UPDATE_CALLBACK(hash_aset)
@@ -1894,16 +1922,17 @@ rb_hash_invert(VALUE hash) https://github.com/ruby/ruby/blob/trunk/hash.c#L1922
 }
 
 static int
-rb_hash_update_callback(VALUE hash, st_data_t *key, st_data_t *value, st_data_t arg, int existing)
+rb_hash_update_callback(st_data_t *key, st_data_t *value, struct update_arg *arg, int existing)
 {
     if (existing) {
-	OBJ_WRITTEN(hash, *value, arg);
+	arg->old_value = *value;
+	arg->new_value = arg->arg;
     }
     else {
-	OBJ_WRITTEN(hash, Qundef, *key);
-	OBJ_WRITTEN(hash, Qundef, arg);
+	arg->new_key = *key;
+	arg->new_value = arg->arg;
     }
-    *value = arg;
+    *value = arg->arg;
     return ST_CONTINUE;
 }
 
@@ -1917,17 +1946,18 @@ rb_hash_update_i(VALUE key, VALUE value, https://github.com/ruby/ruby/blob/trunk/hash.c#L1946
 }
 
 static int
-rb_hash_update_block_callback(VALUE hash, st_data_t *key, st_data_t *value, st_data_t arg, int existing)
+rb_hash_update_block_callback(st_data_t *key, st_data_t *value, struct update_arg *arg, int existing)
 {
-    VALUE newvalue = (VALUE)arg;
+    VALUE newvalue = (VALUE)arg->arg;
 
     if (existing) {
 	newvalue = rb_yield_values(3, (VALUE)*key, (VALUE)*value, newvalue);
-	OBJ_WRITTEN(hash, *value, newvalue);
+	arg->old_value = *value;
+	arg->new_value = newvalue;
     }
     else {
-	OBJ_WRITTEN(hash, Qundef, *key);
-	OBJ_WRITTEN(hash, Qundef, newvalue);
+	arg->new_key = *key;
+	arg->new_value = newvalue;
     }
     *value = newvalue;
     return ST_CONTINUE;
@@ -1979,24 +2009,26 @@ rb_hash_update(VALUE hash1, VALUE hash2) https://github.com/ruby/ruby/blob/trunk/hash.c#L2009
     return hash1;
 }
 
-struct update_arg {
+struct update_func_arg {
     VALUE hash;
     VALUE value;
     rb_hash_update_func *func;
 };
 
 static int
-rb_hash_update_func_callback(VALUE hash, st_data_t *key, st_data_t *value, st_data_t arg0, int existing)
+rb_hash_update_func_callback(st_data_t *key, st_data_t *value, struct update_arg *arg, int existing)
 {
-    struct update_arg *arg = (struct update_arg *)arg0;
-    VALUE newvalue = arg->value;
+    struct update_func_arg *uf_arg = (struct update_func_arg *)arg->arg;
+    VALUE newvalue = uf_arg->value;
+
     if (existing) {
-	newvalue = (*arg->func)((VALUE)*key, (VALUE)*value, newvalue);
-	OBJ_WRITTEN(hash, *value, newvalue);
+	newvalue = (*uf_arg->func)((VALUE)*key, (VALUE)*value, newvalue);
+	arg->old_value = *value;
+	arg->new_value = newvalue;
     }
     else {
-	OBJ_WRITTEN(hash, Qundef, *key);
-	OBJ_WRITTEN(hash, Qundef, newvalue);
+	arg->new_key = *key;
+	arg->new_value = newvalue;
     }
     *value = newvalue;
     return ST_CONTINUE;
@@ -2007,7 +2039,7 @@ static NOINSERT_UPDATE_CALLBACK(rb_hash_ https://github.com/ruby/ruby/blob/trunk/hash.c#L2039
 static int
 rb_hash_update_func_i(VALUE key, VALUE value, VALUE arg0)
 {
-    struct update_arg *arg = (struct update_arg *)arg0;
+    struct update_func_arg *arg = (struct update_func_arg *)arg0;
     VALUE hash = arg->hash;
 
     arg->value = value;
@@ -2021,7 +2053,7 @@ rb_hash_update_by(VALUE hash1, VALUE has https://github.com/ruby/ruby/blob/trunk/hash.c#L2053
     rb_hash_modify(hash1);
     hash2 = to_hash(hash2);
     if (func) {
-	struct update_arg arg;
+	struct update_func_arg arg;
 	arg.hash = hash1;
 	arg.func = func;
 	rb_hash_foreach(hash2, rb_hash_update_func_i, (VALUE)&arg);

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]