1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* array.c: make shared arrays WB-protected objects.

Shared arrays were WB-unprotected object because
  sharing array can modify shared array's buffer
  if it occupied shared array.
  [sharing array (ary)] -> [shared array (shared)] -> <buff>
                |                                       A
                +---------------------------------------+
             write `buff' with WB(ary, &buff[i], obj)
             -> if `ary' and `shared' are old, then only `ary'
                will be remembered.
             -> traverse from `ary'. But `shared' is old, so
                that written `obj' is not marked.
  It cause WB miss so that shared arrays were WB-unprotected.
  (WB-unprotected objects are marked everytime if it is living)
  This patch insert WB() for `shared' if it is needed.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45568 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
ko1 2014-04-11 08:47:00 +00:00
parent 036b55e5a4
commit 6bc463204a
2 changed files with 119 additions and 79 deletions

View file

@ -1,3 +1,25 @@
Fri Apr 11 16:54:26 2014 Koichi Sasada <ko1@atdot.net>
* array.c: make shared arrays WB-protected objects.
Shared arrays were WB-unprotected object because
sharing array can modify shared array's buffer
if it occupied shared array.
[sharing array (ary)] -> [shared array (shared)] -> <buff>
| A
+---------------------------------------+
write `buff' with WB(ary, &buff[i], obj)
-> if `ary' and `shared' are old, then only `ary'
will be remembered.
-> traverse from `ary'. But `shared' is old, so
that written `obj' is not marked.
It cause WB miss so that shared arrays were WB-unprotected.
(WB-unprotected objects are marked everytime if it is living)
This patch insert WB() for `shared' if it is needed.
Fri Apr 11 15:05:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org> Fri Apr 11 15:05:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
* proc.c (rb_method_call_with_block, umethod_bind): call with * proc.c (rb_method_call_with_block, umethod_bind): call with

176
array.c
View file

@ -31,70 +31,6 @@ static ID id_cmp, id_div, id_power;
#define ARY_DEFAULT_SIZE 16 #define ARY_DEFAULT_SIZE 16
#define ARY_MAX_SIZE (LONG_MAX / (int)sizeof(VALUE)) #define ARY_MAX_SIZE (LONG_MAX / (int)sizeof(VALUE))
void
rb_mem_clear(register VALUE *mem, register long size)
{
while (size--) {
*mem++ = Qnil;
}
}
static void
ary_mem_clear(VALUE ary, long beg, long size)
{
RARRAY_PTR_USE(ary, ptr, {
rb_mem_clear(ptr + beg, size);
});
}
static inline void
memfill(register VALUE *mem, register long size, register VALUE val)
{
while (size--) {
*mem++ = val;
}
}
static void
ary_memfill(VALUE ary, long beg, long size, VALUE val)
{
RARRAY_PTR_USE(ary, ptr, {
memfill(ptr + beg, size, val);
RB_OBJ_WRITTEN(ary, Qundef, val);
});
}
static void
ary_memcpy(VALUE ary, long beg, long argc, const VALUE *argv)
{
#if 1
if (OBJ_PROMOTED(ary)) {
if (argc > (int)(128/sizeof(VALUE)) /* is magic number (cache line size) */) {
rb_gc_writebarrier_remember_promoted(ary);
RARRAY_PTR_USE(ary, ptr, {
MEMCPY(ptr+beg, argv, VALUE, argc);
});
}
else {
int i;
RARRAY_PTR_USE(ary, ptr, {
for (i=0; i<argc; i++) {
RB_OBJ_WRITE(ary, &ptr[i+beg], argv[i]);
}
});
}
}
else {
RARRAY_PTR_USE(ary, ptr, {
MEMCPY(ptr+beg, argv, VALUE, argc);
});
}
#else
/* giveup write barrier (traditional way) */
MEMCPY(RARRAY_PTR(ary)+beg, argv, VALUE, argc);
#endif
}
# define ARY_SHARED_P(ary) \ # define ARY_SHARED_P(ary) \
(assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \ (assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \
FL_TEST((ary),ELTS_SHARED)!=0) FL_TEST((ary),ELTS_SHARED)!=0)
@ -195,6 +131,79 @@ ary_memcpy(VALUE ary, long beg, long argc, const VALUE *argv)
FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \ FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \
} while (0) } while (0)
void
rb_mem_clear(register VALUE *mem, register long size)
{
while (size--) {
*mem++ = Qnil;
}
}
static void
ary_mem_clear(VALUE ary, long beg, long size)
{
RARRAY_PTR_USE(ary, ptr, {
rb_mem_clear(ptr + beg, size);
});
}
static inline void
memfill(register VALUE *mem, register long size, register VALUE val)
{
while (size--) {
*mem++ = val;
}
}
static void
ary_memfill(VALUE ary, long beg, long size, VALUE val)
{
RARRAY_PTR_USE(ary, ptr, {
memfill(ptr + beg, size, val);
RB_OBJ_WRITTEN(ary, Qundef, val);
});
}
static void
ary_memcpy0(VALUE ary, long beg, long argc, const VALUE *argv, VALUE buff_owner_ary)
{
#if 1
assert(!ARY_SHARED_P(buff_owner_ary));
if (OBJ_PROMOTED(buff_owner_ary)) {
if (argc > (int)(128/sizeof(VALUE)) /* is magic number (cache line size) */) {
rb_gc_writebarrier_remember_promoted(buff_owner_ary);
RARRAY_PTR_USE(ary, ptr, {
MEMCPY(ptr+beg, argv, VALUE, argc);
});
}
else {
int i;
RARRAY_PTR_USE(ary, ptr, {
for (i=0; i<argc; i++) {
RB_OBJ_WRITE(buff_owner_ary, &ptr[i+beg], argv[i]);
}
});
}
}
else {
RARRAY_PTR_USE(ary, ptr, {
MEMCPY(ptr+beg, argv, VALUE, argc);
});
}
#else
/* giveup write barrier (traditional way) */
RARRAY_PTR(buff_owner_ary);
MEMCPY(RARRAY_PTR(ary)+beg, argv, VALUE, argc);
#endif
}
static void
ary_memcpy(VALUE ary, long beg, long argc, const VALUE *argv)
{
ary_memcpy0(ary, beg, argc, argv, ary);
}
static void static void
ary_resize_capa(VALUE ary, long capacity) ary_resize_capa(VALUE ary, long capacity)
{ {
@ -351,7 +360,7 @@ rb_ary_modify(VALUE ary)
} }
} }
static void static VALUE
ary_ensure_room_for_push(VALUE ary, long add_len) ary_ensure_room_for_push(VALUE ary, long add_len)
{ {
long new_len = RARRAY_LEN(ary) + add_len; long new_len = RARRAY_LEN(ary) + add_len;
@ -363,6 +372,7 @@ ary_ensure_room_for_push(VALUE ary, long add_len)
if (ARY_SHARED_OCCUPIED(shared)) { if (ARY_SHARED_OCCUPIED(shared)) {
if (RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared) + new_len <= RARRAY_LEN(shared)) { if (RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared) + new_len <= RARRAY_LEN(shared)) {
rb_ary_modify_check(ary); rb_ary_modify_check(ary);
return shared;
} }
else { else {
/* if array is shared, then it is likely it participate in push/shift pattern */ /* if array is shared, then it is likely it participate in push/shift pattern */
@ -371,8 +381,8 @@ ary_ensure_room_for_push(VALUE ary, long add_len)
if (new_len > capa - (capa >> 6)) { if (new_len > capa - (capa >> 6)) {
ary_double_capa(ary, new_len); ary_double_capa(ary, new_len);
} }
return ary;
} }
return;
} }
} }
} }
@ -381,6 +391,8 @@ ary_ensure_room_for_push(VALUE ary, long add_len)
if (new_len > capa) { if (new_len > capa) {
ary_double_capa(ary, new_len); ary_double_capa(ary, new_len);
} }
return ary;
} }
/* /*
@ -581,7 +593,7 @@ ary_make_shared(VALUE ary)
} }
else { else {
long capa = ARY_CAPA(ary), len = RARRAY_LEN(ary); long capa = ARY_CAPA(ary), len = RARRAY_LEN(ary);
NEWOBJ_OF(shared, struct RArray, 0, T_ARRAY); /* keep shared ary as non-WB-protected */ NEWOBJ_OF(shared, struct RArray, 0, T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0));
FL_UNSET_EMBED(shared); FL_UNSET_EMBED(shared);
ARY_SET_LEN((VALUE)shared, capa); ARY_SET_LEN((VALUE)shared, capa);
@ -898,20 +910,20 @@ VALUE
rb_ary_push(VALUE ary, VALUE item) rb_ary_push(VALUE ary, VALUE item)
{ {
long idx = RARRAY_LEN(ary); long idx = RARRAY_LEN(ary);
VALUE target_ary = ary_ensure_room_for_push(ary, 1);
ary_ensure_room_for_push(ary, 1); RARRAY_PTR_USE(ary, ptr, {
RARRAY_ASET(ary, idx, item); RB_OBJ_WRITE(target_ary, &ptr[idx], item);
});
ARY_SET_LEN(ary, idx + 1); ARY_SET_LEN(ary, idx + 1);
return ary; return ary;
} }
VALUE VALUE
rb_ary_cat(VALUE ary, const VALUE *ptr, long len) rb_ary_cat(VALUE ary, const VALUE *argv, long len)
{ {
long oldlen = RARRAY_LEN(ary); long oldlen = RARRAY_LEN(ary);
VALUE target_ary = ary_ensure_room_for_push(ary, len);
ary_ensure_room_for_push(ary, len); ary_memcpy0(ary, oldlen, len, argv, target_ary);
ary_memcpy(ary, oldlen, len, ptr);
ARY_SET_LEN(ary, oldlen + len); ARY_SET_LEN(ary, oldlen + len);
return ary; return ary;
} }
@ -1072,7 +1084,7 @@ rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
return result; return result;
} }
static void static VALUE
ary_ensure_room_for_unshift(VALUE ary, int argc) ary_ensure_room_for_unshift(VALUE ary, int argc)
{ {
long len = RARRAY_LEN(ary); long len = RARRAY_LEN(ary);
@ -1114,12 +1126,16 @@ ary_ensure_room_for_unshift(VALUE ary, int argc)
head = sharedp + argc + room; head = sharedp + argc + room;
} }
ARY_SET_PTR(ary, head - argc); ARY_SET_PTR(ary, head - argc);
assert(ARY_SHARED_OCCUPIED(ARY_SHARED(ary)));
return ARY_SHARED(ary);
} }
else { else {
/* sliding items */ /* sliding items */
RARRAY_PTR_USE(ary, ptr, { RARRAY_PTR_USE(ary, ptr, {
MEMMOVE(ptr + argc, ptr, VALUE, len); MEMMOVE(ptr + argc, ptr, VALUE, len);
}); });
return ary;
} }
} }
@ -1139,14 +1155,15 @@ static VALUE
rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary) rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
{ {
long len = RARRAY_LEN(ary); long len = RARRAY_LEN(ary);
VALUE target_ary;
if (argc == 0) { if (argc == 0) {
rb_ary_modify_check(ary); rb_ary_modify_check(ary);
return ary; return ary;
} }
ary_ensure_room_for_unshift(ary, argc); target_ary = ary_ensure_room_for_unshift(ary, argc);
ary_memcpy(ary, 0, argc, argv); ary_memcpy0(ary, 0, argc, argv, target_ary);
ARY_SET_LEN(ary, len + argc); ARY_SET_LEN(ary, len + argc);
return ary; return ary;
} }
@ -1557,14 +1574,15 @@ rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl)
olen = RARRAY_LEN(ary); /* ary may be resized in rpl.to_ary too */ olen = RARRAY_LEN(ary); /* ary may be resized in rpl.to_ary too */
} }
if (beg >= olen) { if (beg >= olen) {
VALUE target_ary;
if (beg > ARY_MAX_SIZE - rlen) { if (beg > ARY_MAX_SIZE - rlen) {
rb_raise(rb_eIndexError, "index %ld too big", beg); rb_raise(rb_eIndexError, "index %ld too big", beg);
} }
ary_ensure_room_for_push(ary, rlen-len); /* len is 0 or negative */ target_ary = ary_ensure_room_for_push(ary, rlen-len); /* len is 0 or negative */
len = beg + rlen; len = beg + rlen;
ary_mem_clear(ary, olen, beg - olen); ary_mem_clear(ary, olen, beg - olen);
if (rlen > 0) { if (rlen > 0) {
ary_memcpy(ary, beg, rlen, RARRAY_CONST_PTR(rpl)); ary_memcpy0(ary, beg, rlen, RARRAY_CONST_PTR(rpl), target_ary);
} }
ARY_SET_LEN(ary, len); ARY_SET_LEN(ary, len);
} }