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:
parent
036b55e5a4
commit
6bc463204a
2 changed files with 119 additions and 79 deletions
22
ChangeLog
22
ChangeLog
|
@ -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
176
array.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue