зеркало из https://github.com/github/ruby.git
suppport Ractor.send(move: true) for more deta
This patch allows to move more data types.
This commit is contained in:
Родитель
963359a762
Коммит
db7a3b63ba
12
gc.c
12
gc.c
|
@ -2292,18 +2292,6 @@ rb_newobj_of(VALUE klass, VALUE flags)
|
||||||
return newobj_of(klass, flags & ~FL_WB_PROTECTED, 0, 0, 0, flags & FL_WB_PROTECTED);
|
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) \
|
#define UNEXPECTED_NODE(func) \
|
||||||
rb_bug(#func"(): GC does not handle T_NODE 0x%x(%p) 0x%"PRIxVALUE, \
|
rb_bug(#func"(): GC does not handle T_NODE 0x%x(%p) 0x%"PRIxVALUE, \
|
||||||
BUILTIN_TYPE(obj), (void*)(obj), RBASIC(obj)->flags)
|
BUILTIN_TYPE(obj), (void*)(obj), RBASIC(obj)->flags)
|
||||||
|
|
474
ractor.c
474
ractor.c
|
@ -354,107 +354,6 @@ ractor_queue_enq(rb_ractor_t *r, struct rb_ractor_queue *rq, struct rb_ractor_ba
|
||||||
// fprintf(stderr, "%s %p->cnt:%d\n", __func__, rq, rq->cnt);
|
// 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
|
static void
|
||||||
ractor_basket_clear(struct rb_ractor_basket *b)
|
ractor_basket_clear(struct rb_ractor_basket *b)
|
||||||
{
|
{
|
||||||
|
@ -463,7 +362,7 @@ ractor_basket_clear(struct rb_ractor_basket *b)
|
||||||
b->sender = Qfalse;
|
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
|
static VALUE
|
||||||
ractor_basket_accept(struct rb_ractor_basket *b)
|
ractor_basket_accept(struct rb_ractor_basket *b)
|
||||||
|
@ -479,11 +378,8 @@ ractor_basket_accept(struct rb_ractor_basket *b)
|
||||||
RB_GC_GUARD(b->v);
|
RB_GC_GUARD(b->v);
|
||||||
break;
|
break;
|
||||||
case basket_type_move:
|
case basket_type_move:
|
||||||
v = ractor_moved_setup(b->v);
|
|
||||||
break;
|
|
||||||
case basket_type_will:
|
case basket_type_will:
|
||||||
v = b->v;
|
v = ractor_reset_belonging(b->v);
|
||||||
ractor_reset_belonging(v);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rb_bug("unreachable");
|
rb_bug("unreachable");
|
||||||
|
@ -502,19 +398,6 @@ ractor_basket_accept(struct rb_ractor_basket *b)
|
||||||
return v;
|
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
|
static VALUE
|
||||||
ractor_try_receive(rb_execution_context_t *ec, rb_ractor_t *r)
|
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_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE ractor_move(VALUE obj); // in this file
|
||||||
|
static VALUE
|
||||||
|
ractor_copy(VALUE obj)
|
||||||
|
{
|
||||||
|
return rb_marshal_dump(obj, Qnil);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ractor_basket_setup(rb_execution_context_t *ec, struct rb_ractor_basket *basket, VALUE obj, VALUE move, bool exc, bool is_will)
|
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,
|
||||||
basket->type = basket_type_will;
|
basket->type = basket_type_will;
|
||||||
basket->v = obj;
|
basket->v = obj;
|
||||||
}
|
}
|
||||||
|
else if (rb_ractor_shareable_p(obj)) {
|
||||||
|
basket->type = basket_type_ref;
|
||||||
|
basket->v = obj;
|
||||||
|
}
|
||||||
else if (!RTEST(move)) {
|
else if (!RTEST(move)) {
|
||||||
ractor_copy_setup(basket, obj);
|
basket->v = ractor_copy(obj);
|
||||||
|
basket->type = basket_type_copy;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ractor_move_setup(basket, obj);
|
basket->type = basket_type_move;
|
||||||
|
basket->v = ractor_move(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
@ -2203,13 +2098,344 @@ null_leave(VALUE obj)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static VALUE
|
||||||
ractor_reset_belonging(VALUE obj)
|
ractor_reset_belonging(VALUE obj)
|
||||||
{
|
{
|
||||||
#if RACTOR_CHECK_MODE > 0
|
#if RACTOR_CHECK_MODE > 0
|
||||||
rb_obj_traverse(obj, reset_belonging_enter, null_leave);
|
rb_obj_traverse(obj, reset_belonging_enter, null_leave);
|
||||||
|
|
||||||
#endif
|
#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 T_FILE:
|
||||||
|
case T_SYMBOL:
|
||||||
|
case T_MATCH:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_OBJECT:
|
||||||
|
{
|
||||||
|
uint32_t len = ROBJECT_NUMIV(obj);
|
||||||
|
VALUE *ptr = ROBJECT_IVPTR(obj);
|
||||||
|
|
||||||
|
for (uint32_t i=0; i<len; i++) {
|
||||||
|
if (ptr[i] != Qundef) {
|
||||||
|
CHECK_AND_REPLACE(ptr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_ARRAY:
|
||||||
|
{
|
||||||
|
for (int i = 0; i < RARRAY_LENINT(obj); i++) {
|
||||||
|
VALUE e = rb_ary_entry(obj, i);
|
||||||
|
if (obj_traverse_replace_i(e, data)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (e != data->replacement) {
|
||||||
|
RARRAY_ASET(obj, i, data->replacement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_HASH:
|
||||||
|
{
|
||||||
|
struct obj_traverse_replace_callback_data d = {
|
||||||
|
.stop = false,
|
||||||
|
.data = data,
|
||||||
|
.src = obj,
|
||||||
|
};
|
||||||
|
rb_hash_stlike_foreach_with_replace(obj,
|
||||||
|
obj_hash_traverse_replace_foreach_i,
|
||||||
|
obj_hash_traverse_replace_i,
|
||||||
|
(VALUE)&d);
|
||||||
|
if (d.stop) return 1;
|
||||||
|
// TODO: rehash here?
|
||||||
|
|
||||||
|
VALUE ifnone = RHASH_IFNONE(obj);
|
||||||
|
if (obj_traverse_replace_i(ifnone, data)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (ifnone != data->replacement) {
|
||||||
|
RHASH_SET_IFNONE(obj, data->replacement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_STRUCT:
|
||||||
|
{
|
||||||
|
long len = RSTRUCT_LEN(obj);
|
||||||
|
const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
|
||||||
|
|
||||||
|
for (long i=0; i<len; i++) {
|
||||||
|
CHECK_AND_REPLACE(ptr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_RATIONAL:
|
||||||
|
CHECK_AND_REPLACE(RRATIONAL(obj)->num);
|
||||||
|
CHECK_AND_REPLACE(RRATIONAL(obj)->den);
|
||||||
|
break;
|
||||||
|
case T_COMPLEX:
|
||||||
|
CHECK_AND_REPLACE(RCOMPLEX(obj)->real);
|
||||||
|
CHECK_AND_REPLACE(RCOMPLEX(obj)->imag);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_DATA:
|
||||||
|
case T_IMEMO:
|
||||||
|
// not supported yet
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// unreachable
|
||||||
|
case T_CLASS:
|
||||||
|
case T_MODULE:
|
||||||
|
case T_ICLASS:
|
||||||
|
default:
|
||||||
|
rp(obj);
|
||||||
|
rb_bug("unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
|
data->replacement = replacement;
|
||||||
|
|
||||||
|
if (data->leave_func(obj, data) == traverse_stop) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0: traverse all
|
||||||
|
// 1: stopped
|
||||||
|
static VALUE
|
||||||
|
rb_obj_traverse_replace(VALUE obj,
|
||||||
|
rb_obj_traverse_replace_enter_func enter_func,
|
||||||
|
rb_obj_traverse_replace_leave_func leave_func)
|
||||||
|
{
|
||||||
|
struct obj_traverse_replace_data data = {
|
||||||
|
.enter_func = enter_func,
|
||||||
|
.leave_func = leave_func,
|
||||||
|
.rec = NULL,
|
||||||
|
.replacement = Qundef,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (obj_traverse_replace_i(obj, &data)) {
|
||||||
|
return Qundef;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return data.replacement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RVALUE {
|
||||||
|
VALUE flags;
|
||||||
|
VALUE klass;
|
||||||
|
VALUE v1;
|
||||||
|
VALUE v2;
|
||||||
|
VALUE v3;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
ractor_moved_bang(VALUE obj)
|
||||||
|
{
|
||||||
|
// invalidate src object
|
||||||
|
struct RVALUE *rv = (void *)obj;
|
||||||
|
|
||||||
|
rv->klass = rb_cRactorMovedObject;
|
||||||
|
rv->v1 = 0;
|
||||||
|
rv->v2 = 0;
|
||||||
|
rv->v3 = 0;
|
||||||
|
|
||||||
|
// TODO: record moved location
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum obj_traverse_iterator_result
|
||||||
|
move_enter(VALUE obj, struct obj_traverse_replace_data *data)
|
||||||
|
{
|
||||||
|
if (rb_ractor_shareable_p(obj)) {
|
||||||
|
data->replacement = obj;
|
||||||
|
return traverse_skip;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data->replacement = rb_obj_alloc(RBASIC_CLASS(obj));
|
||||||
|
return traverse_cont;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rb_replace_generic_ivar(VALUE clone, VALUE obj); // variable.c
|
||||||
|
|
||||||
|
static enum obj_traverse_iterator_result
|
||||||
|
move_leave(VALUE obj, struct obj_traverse_replace_data *data)
|
||||||
|
{
|
||||||
|
VALUE v = data->replacement;
|
||||||
|
struct RVALUE *dst = (struct RVALUE *)v;
|
||||||
|
struct RVALUE *src = (struct RVALUE *)obj;
|
||||||
|
dst->flags |= (src->flags & (FL_USER1 |
|
||||||
|
FL_USER2 |
|
||||||
|
FL_USER3 |
|
||||||
|
FL_USER3 |
|
||||||
|
FL_USER4 |
|
||||||
|
FL_USER5 |
|
||||||
|
FL_USER6 |
|
||||||
|
FL_USER7 |
|
||||||
|
FL_USER8 |
|
||||||
|
FL_USER9 |
|
||||||
|
FL_USER10 |
|
||||||
|
FL_USER11 |
|
||||||
|
FL_USER12 |
|
||||||
|
FL_USER13 |
|
||||||
|
FL_USER14 |
|
||||||
|
FL_USER15 |
|
||||||
|
FL_USER16 |
|
||||||
|
FL_USER17 |
|
||||||
|
FL_USER18 |
|
||||||
|
FL_USER19));
|
||||||
|
|
||||||
|
dst->v1 = src->v1;
|
||||||
|
dst->v2 = src->v2;
|
||||||
|
dst->v3 = src->v3;
|
||||||
|
|
||||||
|
if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
|
||||||
|
rb_replace_generic_ivar(v, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: generic_ivar
|
||||||
|
|
||||||
|
ractor_moved_bang(obj);
|
||||||
|
return traverse_cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
ractor_move(VALUE obj)
|
||||||
|
{
|
||||||
|
VALUE val = rb_obj_traverse_replace(obj, move_enter, move_leave);
|
||||||
|
if (val != Qundef) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_raise(rb_eRactorError, "can not move the object");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "ractor.rbinc"
|
#include "ractor.rbinc"
|
||||||
|
|
21
variable.c
21
variable.c
|
@ -1670,6 +1670,27 @@ rb_copy_generic_ivar(VALUE clone, VALUE obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_replace_generic_ivar(VALUE clone, VALUE obj)
|
||||||
|
{
|
||||||
|
RUBY_ASSERT(FL_TEST(obj, FL_EXIVAR));
|
||||||
|
|
||||||
|
RB_VM_LOCK_ENTER();
|
||||||
|
{
|
||||||
|
struct gen_ivtbl **ivtbl;
|
||||||
|
if (st_lookup(generic_iv_tbl_, (st_data_t)obj, (st_data_t *)&ivtbl)) {
|
||||||
|
st_insert(generic_iv_tbl_, (st_data_t)clone, (st_data_t)ivtbl);
|
||||||
|
st_delete(generic_iv_tbl_, (st_data_t *)&obj, NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_bug("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RB_VM_LOCK_LEAVE();
|
||||||
|
|
||||||
|
FL_SET(clone, FL_EXIVAR);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_ivar_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
|
rb_ivar_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
|
||||||
{
|
{
|
||||||
|
|
Загрузка…
Ссылка в новой задаче