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

ruby-changes:33489

From: ko1 <ko1@a...>
Date: Fri, 11 Apr 2014 17:47:08 +0900 (JST)
Subject: [ruby-changes:33489] ko1:r45568 (trunk): * array.c: make shared arrays WB-protected objects.

ko1	2014-04-11 17:47:00 +0900 (Fri, 11 Apr 2014)

  New Revision: 45568

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

  Log:
    * 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.

  Modified files:
    trunk/ChangeLog
    trunk/array.c
Index: array.c
===================================================================
--- array.c	(revision 45567)
+++ array.c	(revision 45568)
@@ -31,70 +31,6 @@ static ID id_cmp, id_div, id_power; https://github.com/ruby/ruby/blob/trunk/array.c#L31
 #define ARY_DEFAULT_SIZE 16
 #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) \
     (assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \
      FL_TEST((ary),ELTS_SHARED)!=0)
@@ -195,6 +131,79 @@ ary_memcpy(VALUE ary, long beg, long arg https://github.com/ruby/ruby/blob/trunk/array.c#L131
     FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \
 } 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
 ary_resize_capa(VALUE ary, long capacity)
 {
@@ -351,7 +360,7 @@ rb_ary_modify(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L360
     }
 }
 
-static void
+static VALUE
 ary_ensure_room_for_push(VALUE ary, long add_len)
 {
     long new_len = RARRAY_LEN(ary) + add_len;
@@ -363,6 +372,7 @@ ary_ensure_room_for_push(VALUE ary, long https://github.com/ruby/ruby/blob/trunk/array.c#L372
 	    if (ARY_SHARED_OCCUPIED(shared)) {
 		if (RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared) + new_len <= RARRAY_LEN(shared)) {
 		    rb_ary_modify_check(ary);
+		    return shared;
 		}
 		else {
 		    /* 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 https://github.com/ruby/ruby/blob/trunk/array.c#L381
 		    if (new_len > capa - (capa >> 6)) {
 			ary_double_capa(ary, new_len);
 		    }
+		    return ary;
 		}
-		return;
 	    }
 	}
     }
@@ -381,6 +391,8 @@ ary_ensure_room_for_push(VALUE ary, long https://github.com/ruby/ruby/blob/trunk/array.c#L391
     if (new_len > capa) {
 	ary_double_capa(ary, new_len);
     }
+
+    return ary;
 }
 
 /*
@@ -581,7 +593,7 @@ ary_make_shared(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L593
     }
     else {
 	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);
 
 	ARY_SET_LEN((VALUE)shared, capa);
@@ -898,20 +910,20 @@ VALUE https://github.com/ruby/ruby/blob/trunk/array.c#L910
 rb_ary_push(VALUE ary, VALUE item)
 {
     long idx = RARRAY_LEN(ary);
-
-    ary_ensure_room_for_push(ary, 1);
-    RARRAY_ASET(ary, idx, item);
+    VALUE target_ary = ary_ensure_room_for_push(ary, 1);
+    RARRAY_PTR_USE(ary, ptr, {
+	RB_OBJ_WRITE(target_ary, &ptr[idx], item);
+    });
     ARY_SET_LEN(ary, idx + 1);
     return ary;
 }
 
 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);
-
-    ary_ensure_room_for_push(ary, len);
-    ary_memcpy(ary, oldlen, len, ptr);
+    VALUE target_ary = ary_ensure_room_for_push(ary, len);
+    ary_memcpy0(ary, oldlen, len, argv, target_ary);
     ARY_SET_LEN(ary, oldlen + len);
     return ary;
 }
@@ -1072,7 +1084,7 @@ rb_ary_shift_m(int argc, VALUE *argv, VA https://github.com/ruby/ruby/blob/trunk/array.c#L1084
     return result;
 }
 
-static void
+static VALUE
 ary_ensure_room_for_unshift(VALUE ary, int argc)
 {
     long len = RARRAY_LEN(ary);
@@ -1114,12 +1126,16 @@ ary_ensure_room_for_unshift(VALUE ary, i https://github.com/ruby/ruby/blob/trunk/array.c#L1126
 	    head = sharedp + argc + room;
 	}
 	ARY_SET_PTR(ary, head - argc);
+	assert(ARY_SHARED_OCCUPIED(ARY_SHARED(ary)));
+	return ARY_SHARED(ary);
     }
     else {
 	/* sliding items */
 	RARRAY_PTR_USE(ary, ptr, {
 	    MEMMOVE(ptr + argc, ptr, VALUE, len);
 	});
+
+	return ary;
     }
 }
 
@@ -1139,14 +1155,15 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/array.c#L1155
 rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
 {
     long len = RARRAY_LEN(ary);
+    VALUE target_ary;
 
     if (argc == 0) {
 	rb_ary_modify_check(ary);
 	return ary;
     }
 
-    ary_ensure_room_for_unshift(ary, argc);
-    ary_memcpy(ary, 0, argc, argv);
+    target_ary = ary_ensure_room_for_unshift(ary, argc);
+    ary_memcpy0(ary, 0, argc, argv, target_ary);
     ARY_SET_LEN(ary, len + argc);
     return ary;
 }
@@ -1557,14 +1574,15 @@ rb_ary_splice(VALUE ary, long beg, long https://github.com/ruby/ruby/blob/trunk/array.c#L1574
 	olen = RARRAY_LEN(ary);	/* ary may be resized in rpl.to_ary too */
     }
     if (beg >= olen) {
+	VALUE target_ary;
 	if (beg > ARY_MAX_SIZE - rlen) {
 	    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;
 	ary_mem_clear(ary, olen, beg - olen);
 	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);
     }
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 45567)
+++ ChangeLog	(revision 45568)
@@ -1,3 +1,25 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Fri Apr 11 16:54:26 2014  Koichi Sasada  <ko1@a...>
+
+	* 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@r...>
 
 	* proc.c (rb_method_call_with_block, umethod_bind): call with

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

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