ruby-changes:63500
From: Koichi <ko1@a...>
Date: Mon, 2 Nov 2020 01:37:55 +0900 (JST)
Subject: [ruby-changes:63500] db7a3b63ba (master): suppport Ractor.send(move: true) for more deta
https://git.ruby-lang.org/ruby.git/commit/?id=db7a3b63ba From db7a3b63bae810a03b19b5577ded1403bb789185 Mon Sep 17 00:00:00 2001 From: Koichi Sasada <ko1@a...> Date: Sun, 1 Nov 2020 09:56:40 +0900 Subject: suppport Ractor.send(move: true) for more deta This patch allows to move more data types. diff --git a/gc.c b/gc.c index 8d7449a..af7fcef 100644 --- a/gc.c +++ b/gc.c @@ -2292,18 +2292,6 @@ rb_newobj_of(VALUE klass, VALUE flags) https://github.com/ruby/ruby/blob/trunk/gc.c#L2292 return newobj_of(klass, flags & ~FL_WB_PROTECTED, 0, 0, 0, flags & FL_WB_PROTECTED); } -VALUE -rb_newobj_with(VALUE src) -{ - VALUE klass = RBASIC_CLASS(src); - VALUE flags = RBASIC(src)->flags; - - VALUE v1 = RANY(src)->as.values.v1; - VALUE v2 = RANY(src)->as.values.v2; - VALUE v3 = RANY(src)->as.values.v3; - return newobj_of(klass, flags & ~FL_WB_PROTECTED, v1, v2, v3, flags & FL_WB_PROTECTED); -} - #define UNEXPECTED_NODE(func) \ rb_bug(#func"(): GC does not handle T_NODE 0x%x(%p) 0x%"PRIxVALUE, \ BUILTIN_TYPE(obj), (void*)(obj), RBASIC(obj)->flags) diff --git a/ractor.c b/ractor.c index 203a4a8..d3053ec 100644 --- a/ractor.c +++ b/ractor.c @@ -354,107 +354,6 @@ ractor_queue_enq(rb_ractor_t *r, struct rb_ractor_queue *rq, struct rb_ractor_ba https://github.com/ruby/ruby/blob/trunk/ractor.c#L354 // fprintf(stderr, "%s %p->cnt:%d\n", __func__, rq, rq->cnt); } -VALUE rb_newobj_with(VALUE src); // gc.c - -static VALUE -ractor_moving_new(VALUE obj) -{ - // create moving object - VALUE v = rb_newobj_with(obj); - - // invalidate src object - struct RVALUE { - VALUE flags; - VALUE klass; - VALUE v1; - VALUE v2; - VALUE v3; - } *rv = (void *)obj; - - rv->klass = rb_cRactorMovedObject; - rv->v1 = 0; - rv->v2 = 0; - rv->v3 = 0; - - // TODO: record moved location - // TODO: check flags for each data types - - return v; -} - -static VALUE -ractor_move_shallow_copy(VALUE obj) -{ - if (rb_ractor_shareable_p(obj)) { - return obj; - } - else { - switch (BUILTIN_TYPE(obj)) { - case T_STRING: - case T_FILE: - if (!FL_TEST_RAW(obj, RUBY_FL_EXIVAR)) { - return ractor_moving_new(obj); - } - break; - case T_ARRAY: - if (!FL_TEST_RAW(obj, RUBY_FL_EXIVAR)) { - VALUE ary = ractor_moving_new(obj); - long len = RARRAY_LEN(ary); - for (long i=0; i<len; i++) { - VALUE e = RARRAY_AREF(ary, i); - RARRAY_ASET(ary, i, ractor_move_shallow_copy(e)); // confirm WB - } - return ary; - } - break; - default: - break; - } - - rb_raise(rb_eRactorError, "can't move this this kind of object:%"PRIsVALUE, obj); - } -} - -static VALUE -ractor_moved_setup(VALUE obj) -{ -#if RACTOR_CHECK_MODE - switch (BUILTIN_TYPE(obj)) { - case T_STRING: - case T_FILE: - rb_ractor_setup_belonging(obj); - break; - case T_ARRAY: - rb_ractor_setup_belonging(obj); - long len = RARRAY_LEN(obj); - for (long i=0; i<len; i++) { - VALUE e = RARRAY_AREF(obj, i); - if (!rb_ractor_shareable_p(e)) { - ractor_moved_setup(e); - } - } - break; - default: - rb_bug("unreachable"); - } -#endif - return obj; -} - -static void -ractor_move_setup(struct rb_ractor_basket *b, VALUE obj) -{ - if (rb_ractor_shareable_p(obj)) { - b->type = basket_type_ref; - b->v = obj; - } - else { - b->type = basket_type_move; - b->v = ractor_move_shallow_copy(obj); - return; - } -} - static void ractor_basket_clear(struct rb_ractor_basket *b) { @@ -463,7 +362,7 @@ ractor_basket_clear(struct rb_ractor_basket *b) https://github.com/ruby/ruby/blob/trunk/ractor.c#L362 b->sender = Qfalse; } -static void ractor_reset_belonging(VALUE obj); // in this file +static VALUE ractor_reset_belonging(VALUE obj); // in this file static VALUE ractor_basket_accept(struct rb_ractor_basket *b) @@ -479,11 +378,8 @@ ractor_basket_accept(struct rb_ractor_basket *b) https://github.com/ruby/ruby/blob/trunk/ractor.c#L378 RB_GC_GUARD(b->v); break; case basket_type_move: - v = ractor_moved_setup(b->v); - break; case basket_type_will: - v = b->v; - ractor_reset_belonging(v); + v = ractor_reset_belonging(b->v); break; default: rb_bug("unreachable"); @@ -502,19 +398,6 @@ ractor_basket_accept(struct rb_ractor_basket *b) https://github.com/ruby/ruby/blob/trunk/ractor.c#L398 return v; } -static void -ractor_copy_setup(struct rb_ractor_basket *b, VALUE obj) -{ - if (rb_ractor_shareable_p(obj)) { - b->type = basket_type_ref; - b->v = obj; - } - else { - b->v = rb_marshal_dump(obj, Qnil); - b->type = basket_type_copy; - } -} - static VALUE ractor_try_receive(rb_execution_context_t *ec, rb_ractor_t *r) { @@ -777,6 +660,13 @@ ractor_send_basket(rb_execution_context_t *ec, rb_ractor_t *r, struct rb_ractor_ https://github.com/ruby/ruby/blob/trunk/ractor.c#L660 } } +static VALUE ractor_move(VALUE obj); // in this file +static VALUE +ractor_copy(VALUE obj) +{ + return rb_marshal_dump(obj, Qnil); +} + static void ractor_basket_setup(rb_execution_context_t *ec, struct rb_ractor_basket *basket, VALUE obj, VALUE move, bool exc, bool is_will) { @@ -787,13 +677,18 @@ ractor_basket_setup(rb_execution_context_t *ec, struct rb_ractor_basket *basket, https://github.com/ruby/ruby/blob/trunk/ractor.c#L677 basket->type = basket_type_will; basket->v = obj; } + else if (rb_ractor_shareable_p(obj)) { + basket->type = basket_type_ref; + basket->v = obj; + } else if (!RTEST(move)) { - ractor_copy_setup(basket, obj); + basket->v = ractor_copy(obj); + basket->type = basket_type_copy; } else { - ractor_move_setup(basket, obj); + basket->type = basket_type_move; + basket->v = ractor_move(obj); } - } static VALUE @@ -2203,13 +2098,344 @@ null_leave(VALUE obj) https://github.com/ruby/ruby/blob/trunk/ractor.c#L2098 } #endif -static void +static VALUE ractor_reset_belonging(VALUE obj) { #if RACTOR_CHECK_MODE > 0 rb_obj_traverse(obj, reset_belonging_enter, null_leave); - #endif + return obj; +} + + +/// traverse and replace function + +// 2: stop search +// 1: skip child +// 0: continue + +struct obj_traverse_replace_data; +static int obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data); +typedef enum obj_traverse_iterator_result (*rb_obj_traverse_replace_enter_func)(VALUE obj, struct obj_traverse_replace_data *data); +typedef enum obj_traverse_iterator_result (*rb_obj_traverse_replace_leave_func)(VALUE obj, struct obj_traverse_replace_data *data); + +struct obj_traverse_replace_data { + rb_obj_traverse_replace_enter_func enter_func; + rb_obj_traverse_replace_leave_func leave_func; + + st_table *rec; + VALUE rec_hash; + + VALUE replacement; +}; + +struct obj_traverse_replace_callback_data { + bool stop; + VALUE src; + struct obj_traverse_replace_data *data; +}; + +static int +obj_hash_traverse_replace_foreach_i(st_data_t key, st_data_t value, st_data_t argp, int error) +{ + return ST_REPLACE; +} + +static int +obj_hash_traverse_replace_i(st_data_t *key, st_data_t *val, st_data_t ptr, int exists) +{ + struct obj_traverse_replace_callback_data *d = (struct obj_traverse_replace_callback_data *)ptr; + struct obj_traverse_replace_data *data = d->data; + + if (obj_traverse_replace_i(*key, data)) { + d->stop = true; + return ST_STOP; + } + else if (*key != data->replacement) { + VALUE v = *key = data->replacement; + RB_OBJ_WRITTEN(d->src, Qundef, v); + } + + if (obj_traverse_replace_i(*val, data)) { + d->stop = true; + return ST_STOP; + } + else if (*val != data->replacement) { + VALUE v = *val = data->replacement; + RB_OBJ_WRITTEN(d->src, Qundef, v); + } + + return ST_CONTINUE; +} + +static struct st_table * +obj_traverse_replace_rec(struct obj_traverse_replace_data *data) +{ + if (UNLIKELY(!data->rec)) { + data->rec_hash = rb_ident_hash_new(); + data->rec = rb_hash_st_table(data->rec_hash); + } + return data->rec; +} + +static int +obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data) +{ + VALUE replacement; + + if (RB_SPECIAL_CONST_P(obj)) { + data->replacement = obj; + return 0; + } + + switch (data->enter_func(obj, data)) { + case traverse_cont: break; + case traverse_skip: return 0; // skip children + case traverse_stop: return 1; // stop search + } + + replacement = data->replacement; + + if (UNLIKELY(st_lookup(obj_traverse_replace_rec(data), (st_data_t)obj, (st_data_t *)&replacement))) { + data->replacement = replacement; + return 0; + } + else { + st_insert(obj_traverse_replace_rec(data), (st_data_t)obj, (st_data_t)replacement); + } + +#define CHECK_AND_REPLACE(v) do { \ + VALUE _val = (v); \ + if (obj_traverse_replace_i(_val, data)) { return 1; } \ + else if (data->replacement != _val) { RB_OBJ_WRITE(obj, &v, data->replacement); } \ +} while (0) + + if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) { + struct gen_ivtbl *ivtbl; + rb_ivar_generic_ivtbl_lookup(obj, &ivtbl); + for (uint32_t i = 0; i < ivtbl->numiv; i++) { + if (ivtbl->ivptr[i] != Qundef) { + CHECK_AND_REPLACE(ivtbl->ivptr[i]); + } + } + } + + switch (BUILTIN_TYPE(obj)) { + // no child node + case T_STRING: + case T_FLOAT: + case T_BIGNUM: + case T_REGEXP: + case (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/