ruby-changes:29482
From: ko1 <ko1@a...>
Date: Fri, 21 Jun 2013 20:22:31 +0900 (JST)
Subject: [ruby-changes:29482] ko1:r41534 (trunk): * include/ruby/ruby.h: support write barrier protection for T_STRUCT.
ko1 2013-06-21 20:22:18 +0900 (Fri, 21 Jun 2013) New Revision: 41534 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=41534 Log: * include/ruby/ruby.h: support write barrier protection for T_STRUCT. Introduce the following C APIs: * RSTRUCT_RAWPTR(st) returns pointer (do WB on your risk). The type of returned pointer is (const VALUE *). * RSTRUCT_GET(st, idx) returns idx-th value of struct. * RSTRUCT_SET(st, idx, v) set idx-th value by v with WB. And * RSTRUCT_PTR(st) returns pointer with shady operation. The type of returned pointer is (VALUE *). * struct.c, re.c, gc.c, marshal.c: rewrite with above APIs. Modified files: trunk/ChangeLog trunk/gc.c trunk/include/ruby/ruby.h trunk/marshal.c trunk/range.c trunk/struct.c Index: include/ruby/ruby.h =================================================================== --- include/ruby/ruby.h (revision 41533) +++ include/ruby/ruby.h (revision 41534) @@ -709,6 +709,9 @@ VALUE rb_obj_setup(VALUE obj, VALUE klas https://github.com/ruby/ruby/blob/trunk/include/ruby/ruby.h#L709 #ifndef RGENGC_WB_PROTECTED_HASH #define RGENGC_WB_PROTECTED_HASH 1 #endif +#ifndef RGENGC_WB_PROTECTED_STRUCT +#define RGENGC_WB_PROTECTED_STRUCT 1 +#endif #ifndef RGENGC_WB_PROTECTED_STRING #define RGENGC_WB_PROTECTED_STRING 1 #endif @@ -1109,9 +1112,9 @@ struct RStruct { https://github.com/ruby/ruby/blob/trunk/include/ruby/ruby.h#L1112 union { struct { long len; - VALUE *ptr; + const VALUE *ptr; } heap; - VALUE ary[RSTRUCT_EMBED_LEN_MAX]; + const VALUE ary[RSTRUCT_EMBED_LEN_MAX]; } as; }; #define RSTRUCT_EMBED_LEN_MASK (FL_USER2|FL_USER1) @@ -1121,11 +1124,15 @@ struct RStruct { https://github.com/ruby/ruby/blob/trunk/include/ruby/ruby.h#L1124 (long)((RBASIC(st)->flags >> RSTRUCT_EMBED_LEN_SHIFT) & \ (RSTRUCT_EMBED_LEN_MASK >> RSTRUCT_EMBED_LEN_SHIFT)) : \ RSTRUCT(st)->as.heap.len) -#define RSTRUCT_PTR(st) \ - ((RBASIC(st)->flags & RSTRUCT_EMBED_LEN_MASK) ? \ - RSTRUCT(st)->as.ary : \ - RSTRUCT(st)->as.heap.ptr) #define RSTRUCT_LENINT(st) rb_long2int(RSTRUCT_LEN(st)) +#define RSTRUCT_RAWPTR(st) \ + ((RBASIC(st)->flags & RSTRUCT_EMBED_LEN_MASK) ? \ + RSTRUCT(st)->as.ary : \ + RSTRUCT(st)->as.heap.ptr) +#define RSTRUCT_PTR(st) ((VALUE *)RSTRUCT_RAWPTR(RGENGC_WB_PROTECTED_STRUCT ? OBJ_WB_GIVEUP((VALUE)st) : (VALUE)st)) + +#define RSTRUCT_SET(st, idx, v) OBJ_WRITE(st, (VALUE *)&RSTRUCT_RAWPTR(st)[idx], v) +#define RSTRUCT_GET(st, idx) (RSTRUCT_RAWPTR(st)[idx]) #define RBIGNUM_EMBED_LEN_MAX ((int)((sizeof(VALUE)*3)/sizeof(BDIGIT))) struct RBignum { Index: ChangeLog =================================================================== --- ChangeLog (revision 41533) +++ ChangeLog (revision 41534) @@ -1,3 +1,17 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Fri Jun 21 20:15:49 2013 Koichi Sasada <ko1@a...> + + * include/ruby/ruby.h: support write barrier protection for T_STRUCT. + Introduce the following C APIs: + * RSTRUCT_RAWPTR(st) returns pointer (do WB on your risk). + The type of returned pointer is (const VALUE *). + * RSTRUCT_GET(st, idx) returns idx-th value of struct. + * RSTRUCT_SET(st, idx, v) set idx-th value by v with WB. + And + * RSTRUCT_PTR(st) returns pointer with shady operation. + The type of returned pointer is (VALUE *). + + * struct.c, re.c, gc.c, marshal.c: rewrite with above APIs. + Fri Jun 21 19:38:37 2013 Tanaka Akira <akr@f...> * bignum.c (BDIGMAX): Use BIGRAD. Index: range.c =================================================================== --- range.c (revision 41533) +++ range.c (revision 41534) @@ -27,7 +27,12 @@ static ID id_cmp, id_succ, id_beg, id_en https://github.com/ruby/ruby/blob/trunk/range.c#L27 #define RANGE_EXCL(r) (RSTRUCT(r)->as.ary[2]) #define EXCL(r) RTEST(RANGE_EXCL(r)) -#define SET_EXCL(r,v) (RSTRUCT(r)->as.ary[2] = (v) ? Qtrue : Qfalse) +static inline VALUE +SET_EXCL(VALUE r, VALUE v) +{ + RSTRUCT_SET(r, 2, v); + return v ? Qtrue : Qfalse; +} static VALUE range_failed(void) @@ -59,8 +64,8 @@ range_init(VALUE range, VALUE beg, VALUE https://github.com/ruby/ruby/blob/trunk/range.c#L64 } SET_EXCL(range, exclude_end); - RSTRUCT(range)->as.ary[0] = beg; - RSTRUCT(range)->as.ary[1] = end; + RSTRUCT_SET(range, 0, beg); + RSTRUCT_SET(range, 1, end); } VALUE @@ -1228,9 +1233,9 @@ range_loader(VALUE range, VALUE obj) https://github.com/ruby/ruby/blob/trunk/range.c#L1233 rb_raise(rb_eTypeError, "not a dumped range object"); } - RSTRUCT(range)->as.ary[0] = rb_ivar_get(obj, id_beg); - RSTRUCT(range)->as.ary[1] = rb_ivar_get(obj, id_end); - RSTRUCT(range)->as.ary[2] = rb_ivar_get(obj, id_excl); + RSTRUCT_SET(range, 0, rb_ivar_get(obj, id_beg)); + RSTRUCT_SET(range, 1, rb_ivar_get(obj, id_end)); + RSTRUCT_SET(range, 2, rb_ivar_get(obj, id_excl)); return range; } Index: struct.c =================================================================== --- struct.c (revision 41533) +++ struct.c (revision 41534) @@ -89,17 +89,15 @@ rb_struct_members_m(VALUE obj) https://github.com/ruby/ruby/blob/trunk/struct.c#L89 VALUE rb_struct_getmember(VALUE obj, ID id) { - VALUE members, slot, *ptr, *ptr_members; + VALUE members, slot; long i, len; - ptr = RSTRUCT_PTR(obj); members = rb_struct_members(obj); - ptr_members = RARRAY_PTR(members); slot = ID2SYM(id); len = RARRAY_LEN(members); for (i=0; i<len; i++) { - if (ptr_members[i] == slot) { - return ptr[i]; + if (RARRAY_AREF(members, i) == slot) { + return RSTRUCT_GET(obj, i); } } rb_name_error(id, "%s is not struct member", rb_id2name(id)); @@ -113,16 +111,16 @@ rb_struct_ref(VALUE obj) https://github.com/ruby/ruby/blob/trunk/struct.c#L111 return rb_struct_getmember(obj, rb_frame_this_func()); } -static VALUE rb_struct_ref0(VALUE obj) {return RSTRUCT_PTR(obj)[0];} -static VALUE rb_struct_ref1(VALUE obj) {return RSTRUCT_PTR(obj)[1];} -static VALUE rb_struct_ref2(VALUE obj) {return RSTRUCT_PTR(obj)[2];} -static VALUE rb_struct_ref3(VALUE obj) {return RSTRUCT_PTR(obj)[3];} -static VALUE rb_struct_ref4(VALUE obj) {return RSTRUCT_PTR(obj)[4];} -static VALUE rb_struct_ref5(VALUE obj) {return RSTRUCT_PTR(obj)[5];} -static VALUE rb_struct_ref6(VALUE obj) {return RSTRUCT_PTR(obj)[6];} -static VALUE rb_struct_ref7(VALUE obj) {return RSTRUCT_PTR(obj)[7];} -static VALUE rb_struct_ref8(VALUE obj) {return RSTRUCT_PTR(obj)[8];} -static VALUE rb_struct_ref9(VALUE obj) {return RSTRUCT_PTR(obj)[9];} +static VALUE rb_struct_ref0(VALUE obj) {return RSTRUCT_GET(obj, 0);} +static VALUE rb_struct_ref1(VALUE obj) {return RSTRUCT_GET(obj, 1);} +static VALUE rb_struct_ref2(VALUE obj) {return RSTRUCT_GET(obj, 2);} +static VALUE rb_struct_ref3(VALUE obj) {return RSTRUCT_GET(obj, 3);} +static VALUE rb_struct_ref4(VALUE obj) {return RSTRUCT_GET(obj, 4);} +static VALUE rb_struct_ref5(VALUE obj) {return RSTRUCT_GET(obj, 5);} +static VALUE rb_struct_ref6(VALUE obj) {return RSTRUCT_GET(obj, 6);} +static VALUE rb_struct_ref7(VALUE obj) {return RSTRUCT_GET(obj, 7);} +static VALUE rb_struct_ref8(VALUE obj) {return RSTRUCT_GET(obj, 8);} +static VALUE rb_struct_ref9(VALUE obj) {return RSTRUCT_GET(obj, 9);} #define N_REF_FUNC numberof(ref_func) @@ -149,18 +147,16 @@ rb_struct_modify(VALUE s) https://github.com/ruby/ruby/blob/trunk/struct.c#L147 static VALUE rb_struct_set(VALUE obj, VALUE val) { - VALUE members, slot, *ptr, *ptr_members; + VALUE members, slot; long i, len; members = rb_struct_members(obj); - ptr_members = RARRAY_PTR(members); len = RARRAY_LEN(members); rb_struct_modify(obj); - ptr = RSTRUCT_PTR(obj); for (i=0; i<len; i++) { - slot = ptr_members[i]; + slot = RARRAY_AREF(members, i); if (rb_id_attrset(SYM2ID(slot)) == rb_frame_this_func()) { - return ptr[i] = val; + return RSTRUCT_SET(obj, i, val); } } rb_name_error(rb_frame_this_func(), "`%s' is not a struct member", @@ -390,16 +386,18 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/struct.c#L386 rb_struct_initialize_m(int argc, VALUE *argv, VALUE self) { VALUE klass = rb_obj_class(self); - long n; + long i, n; rb_struct_modify(self); n = num_members(klass); if (n < argc) { rb_raise(rb_eArgError, "struct size differs"); } - MEMCPY(RSTRUCT_PTR(self), argv, VALUE, argc); + for (i=0; i<argc; i++) { + RSTRUCT_SET(self, i, argv[i]); + } if (n > argc) { - rb_mem_clear(RSTRUCT_PTR(self)+argc, n-argc); + rb_mem_clear((VALUE *)RSTRUCT_RAWPTR(self)+argc, n-argc); } return Qnil; } @@ -414,18 +412,18 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/struct.c#L412 struct_alloc(VALUE klass) { long n; - NEWOBJ_OF(st, struct RStruct, klass, T_STRUCT); + NEWOBJ_OF(st, struct RStruct, klass, T_STRUCT | (RGENGC_WB_PROTECTED_STRUCT ? FL_WB_PROTECTED : 0)); n = num_members(klass); if (0 < n && n <= RSTRUCT_EMBED_LEN_MAX) { RBASIC(st)->flags &= ~RSTRUCT_EMBED_LEN_MASK; RBASIC(st)->flags |= n << RSTRUCT_EMBED_LEN_SHIFT; - rb_mem_clear(st->as.ary, n); + rb_mem_clear((VALUE *)st->as.ary, n); } else { st->as.heap.ptr = ALLOC_N(VALUE, n); - rb_mem_clear(st->as.heap.ptr, n); + rb_mem_clear((VALUE *)st->as.heap.ptr, n); st->as.heap.len = n; } @@ -488,7 +486,7 @@ rb_struct_each(VALUE s) https://github.com/ruby/ruby/blob/trunk/struct.c#L486 RETURN_SIZED_ENUMERATOR(s, 0, 0, rb_struct_size); for (i=0; i<RSTRUCT_LEN(s); i++) { - rb_yield(RSTRUCT_PTR(s)[i]); + rb_yield(RSTRUCT_GET(s, i)); } return s; } @@ -522,7 +520,7 @@ rb_struct_each_pair(VALUE s) https://github.com/ruby/ruby/blob/trunk/struct.c#L520 members = rb_struct_members(s); for (i=0; i<RSTRUCT_LEN(s); i++) { VALUE key = rb_ary_entry(members, i); - VALUE value = RSTRUCT_PTR(s)[i]; + VALUE value = RSTRUCT_GET(s, i); rb_yield(rb_assoc_new(key, value)); } return s; @@ -533,7 +531,6 @@ inspect_struct(VALUE s, VALUE dummy, int https://github.com/ruby/ruby/blob/trunk/struct.c#L531 { VALUE cname = rb_class_name(rb_obj_class(s)); VALUE members, str = rb_str_new2("#<struct "); - VALUE *ptr, *ptr_members; long i, len; char first = RSTRING_PTR(cname)[0]; @@ -545,9 +542,8 @@ inspect_struct(VALUE s, VALUE dummy, int https://github.com/ruby/ruby/blob/trunk/struct.c#L542 } members = rb_struct_members(s); - ptr_members = RARRAY_PTR(members); - ptr = RSTRUCT_PTR(s); len = RSTRUCT_LEN(s); + for (i=0; i<len; i++) { VALUE slot; ID id; @@ -558,7 +554,7 @@ inspect_struct(VALUE s, VALUE dummy, int https://github.com/ruby/ruby/blob/trunk/struct.c#L554 else if (first != '#') { rb_str_cat2(str, " "); } - slot = ptr_members[i]; + slot = RARRAY_AREF(members, i); id = SYM2ID(slot); if (rb_is_local_id(id) || rb_is_const_id(id)) { rb_str_append(str, rb_id2str(id)); @@ -567,7 +563,7 @@ inspect_struct(VALUE s, VALUE dummy, int https://github.com/ruby/ruby/blob/trunk/struct.c#L563 rb_str_append(str, rb_inspect(slot)); } rb_str_cat2(str, "="); - rb_str_append(str, rb_inspect(ptr[i])); + rb_str_append(str, rb_inspect(RSTRUCT_GET(s, i))); } rb_str_cat2(str, ">"); OBJ_INFECT(str, s); @@ -604,7 +600,7 @@ rb_struct_inspect(VALUE s) https://github.com/ruby/ruby/blob/trunk/struct.c#L600 static VALUE rb_struct_to_a(VALUE s) { - return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_PTR(s)); + return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_RAWPTR(s)); } /* @@ -626,7 +622,7 @@ rb_struct_to_h(VALUE s) https://github.com/ruby/ruby/blob/trunk/struct.c#L622 long i; for (i=0; i<RSTRUCT_LEN(s); i++) { - rb_hash_aset(h, rb_ary_entry(members, i), RSTRUCT_PTR(s)[i]); + rb_hash_aset(h, rb_ary_entry(members, i), RSTRUCT_GET(s, i)); } return h; } @@ -635,11 +631,16 @@ rb_struct_to_h(VALUE s) https://github.com/ruby/ruby/blob/trunk/struct.c#L631 VALUE rb_struct_init_copy(VALUE copy, VALUE s) { + long i, len; + if (!OBJ_INIT_COPY(copy, s)) return copy; if (RSTRUCT_LEN(copy) != RSTRUCT_LEN(s)) { rb_raise(rb_eTypeError, "struct size mismatch"); } - MEMCPY(RSTRUCT_PTR(copy), RSTRUCT_PTR(s), VALUE, RSTRUCT_LEN(copy)); + + for (i=0, len=RSTRUCT_LEN(copy); i<len; i++) { + RSTRUCT_SET(copy, i, RSTRUCT_GET(s, i)); + } return copy; } @@ -647,16 +648,12 @@ rb_struct_init_copy(VALUE copy, VALUE s) https://github.com/ruby/ruby/blob/trunk/struct.c#L648 static VALUE rb_struct_aref_id(VALUE s, ID id) { - VALUE *ptr, members, *ptr_members; - long i, len; + VALUE members = rb_struct_members(s); + long i, len = RARRAY_LEN(members); - ptr = RSTRUCT_PTR(s); - members = rb_struct_members(s); - ptr_members = RARRAY_PTR(members); - len = RARRAY_LEN(members); for (i=0; i<len; i++) { - if (SYM2ID(ptr_members[i]) == id) { - return ptr[i]; + if (SYM2ID(RARRAY_AREF(members, i)) == id) { + return RSTRUCT_GET(s, i); } } rb_name_error(id, "no member '%s' in struct", rb_id2name(id)); @@ -706,27 +703,24 @@ rb_struct_aref(VALUE s, VALUE idx) https://github.com/ruby/ruby/blob/trunk/struct.c#L703 if (RSTRUCT_LEN(s) <= i) rb_raise(rb_eIndexError, "offset %ld too large for struct(size:%ld)", i, RSTRUCT_LEN(s)); - return RSTRUCT_PTR(s)[i]; + return RSTRUCT_GET(s, i); } static VALUE rb_struct_aset_id(VALUE s, ID id, VALUE val) { - VALUE members, *ptr, *ptr_members; - long i, len; + VALUE members = rb_struct_members(s); + long i, len = RARRAY_LEN(members); - members = rb_struct_members(s); - len = RARRAY_LEN(members); - rb_struct_modify(s); if (RSTRUCT_LEN(s) != len) { rb_raise(rb_eTypeError, "struct size differs (%ld required %ld given)", len, RSTRUCT_LEN(s)); } - ptr = RSTRUCT_PTR(s); - ptr_members = RARRAY_PTR(members); + for (i=0; i<len; i++) { - if (SYM2ID(ptr_members[i]) == id) { - ptr[i] = val; + if (SYM2ID(RARRAY_AREF(members, i)) == id) { + rb_struct_modify(s); + RSTRUCT_SET(s, i, val); return val; } } @@ -782,7 +776,8 @@ rb_struct_aset(VALUE s, VALUE idx, VALUE https://github.com/ruby/ruby/blob/trunk/struct.c#L776 i, RSTRUCT_LEN(s)); } rb_struct_modify(s); - return RSTRUCT_PTR(s)[i] = val; + RSTRUCT_SET(s, i, val); + return val; } static VALUE @@ -835,8 +830,8 @@ rb_struct_select(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/struct.c#L830 RETURN_SIZED_ENUMERATOR(s, 0, 0, rb_struct_size); result = rb_ary_new(); for (i = 0; i < RSTRUCT_LEN(s); i++) { - if (RTEST(rb_yield(RSTRUCT_PTR(s)[i]))) { - rb_ary_push(result, RSTRUCT_PTR(s)[i]); + if (RTEST(rb_yield(RSTRUCT_GET(s, i)))) { + rb_ary_push(result, RSTRUCT_GET(s, i)); } } @@ -846,12 +841,12 @@ rb_struct_select(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/struct.c#L841 static VALUE recursive_equal(VALUE s, VALUE s2, int recur) { - VALUE *ptr, *ptr2; + const VALUE *ptr, *ptr2; long i, len; if (recur) return Qtrue; /* Subtle! */ - ptr = RSTRUCT_PTR(s); - ptr2 = RSTRUCT_PTR(s2); + ptr = RSTRUCT_RAWPTR(s); + ptr2 = RSTRUCT_RAWPTR(s2); len = RSTRUCT_LEN(s); for (i=0; i<len; i++) { if (!rb_equal(ptr[i], ptr2[i])) return Qfalse; @@ -892,11 +887,12 @@ recursive_hash(VALUE s, VALUE dummy, int https://github.com/ruby/ruby/blob/trunk/struct.c#L887 { long i, len; st_index_t h; - VALUE n, *ptr; + VALUE n; + const VALUE *ptr; h = rb_hash_start(rb_hash(rb_obj_class(s))); if (!recur) { - ptr = RSTRUCT_PTR(s); + ptr = RSTRUCT_RAWPTR(s); len = RSTRUCT_LEN(s); for (i = 0; i < len; i++) { n = rb_hash(ptr[i]); @@ -923,12 +919,12 @@ rb_struct_hash(VALUE s) https://github.com/ruby/ruby/blob/trunk/struct.c#L919 static VALUE recursive_eql(VALUE s, VALUE s2, int recur) { - VALUE *ptr, *ptr2; + const VALUE *ptr, *ptr2; long i, len; if (recur) return Qtrue; /* Subtle! */ - ptr = RSTRUCT_PTR(s); - ptr2 = RSTRUCT_PTR(s2); + ptr = RSTRUCT_RAWPTR(s); + ptr2 = RSTRUCT_RAWPTR(s2); len = RSTRUCT_LEN(s); for (i=0; i<len; i++) { if (!rb_eql(ptr[i], ptr2[i])) return Qfalse; Index: gc.c =================================================================== --- gc.c (revision 41533) +++ gc.c (revision 41534) @@ -1283,7 +1283,7 @@ obj_free(rb_objspace_t *objspace, VALUE https://github.com/ruby/ruby/blob/trunk/gc.c#L1283 case T_STRUCT: if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 && RANY(obj)->as.rstruct.as.heap.ptr) { - xfree(RANY(obj)->as.rstruct.as.heap.ptr); + xfree((void *)RANY(obj)->as.rstruct.as.heap.ptr); } break; @@ -3386,7 +3386,7 @@ gc_mark_children(rb_objspace_t *objspace https://github.com/ruby/ruby/blob/trunk/gc.c#L3386 case T_STRUCT: { long len = RSTRUCT_LEN(obj); - VALUE *ptr = RSTRUCT_PTR(obj); + const VALUE *ptr = RSTRUCT_RAWPTR(obj); while (len--) { gc_mark(objspace, *ptr++); Index: marshal.c =================================================================== --- marshal.c (revision 41533) +++ marshal.c (revision 41534) @@ -821,7 +821,7 @@ w_object(VALUE obj, struct dump_arg *arg https://github.com/ruby/ruby/blob/trunk/marshal.c#L821 mem = rb_struct_members(obj); for (i=0; i<len; i++) { w_symbol(SYM2ID(RARRAY_AREF(mem, i)), arg); - w_object(RSTRUCT_PTR(obj)[i], arg, limit); + w_object(RSTRUCT_GET(obj, i), arg, limit); } } break; -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/