From: Yukihiro Matsumoto Date: 2008-12-12T09:37:33+09:00 Subject: [ruby-core:20497] Re: Status of copy-on-write friendly garbage collector --Multipart_Fri_Dec_12_09:44:29_2008-1 Content-Type: text/plain; charset=US-ASCII Hi, In message "Re: [ruby-core:20481] Re: Status of copy-on-write friendly garbage collector" on Fri, 12 Dec 2008 00:11:52 +0900, "Roger Pack" writes: |I assume that it works now, and was merged into trunk? It works now, but have not yet been merged it since it still slows down non-forking programs. I attach the diff from trunk for those who want to try and inspect the idea. matz. --Multipart_Fri_Dec_12_09:44:29_2008-1 Content-Type: application/octet-stream; type=patch Content-Disposition: attachment; filename="o1_bitmap_marking.diff" Content-Transfer-Encoding: 7bit diff --git a/debug.c b/debug.c index bfce7ad..384fbb2 100644 --- a/debug.c +++ b/debug.c @@ -31,7 +31,7 @@ static const union { RUBY_ENC_CODERANGE_7BIT = ENC_CODERANGE_7BIT, RUBY_ENC_CODERANGE_VALID = ENC_CODERANGE_VALID, RUBY_ENC_CODERANGE_BROKEN = ENC_CODERANGE_BROKEN, - RUBY_FL_MARK = FL_MARK, + RUBY_FL_ALIGNOFF = FL_ALIGNOFF, RUBY_FL_RESERVED = FL_RESERVED, RUBY_FL_FINALIZE = FL_FINALIZE, RUBY_FL_TAINT = FL_TAINT, diff --git a/gc.c b/gc.c index d2ef85f..864143a 100644 --- a/gc.c +++ b/gc.c @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef HAVE_SYS_TIME_H #include @@ -248,6 +249,13 @@ typedef struct RVALUE { VALUE flags; /* always 0 for freed obj */ struct RVALUE *next; } free; + struct { + VALUE flags; + struct RVALUE *next; + int *map; + VALUE slot; + int limit; + } bitmap; struct RBasic basic; struct RObject object; struct RClass klass; @@ -279,6 +287,7 @@ struct heaps_slot { void *membase; RVALUE *slot; int limit; + RVALUE *bitmap; }; #define HEAP_MIN_SLOTS 10000 @@ -308,6 +317,7 @@ typedef struct rb_objspace { RVALUE *freelist; RVALUE *range[2]; RVALUE *freed; + RVALUE *freed_bitmap; } heap; struct { int dont_gc; @@ -379,22 +389,12 @@ rb_objspace_alloc(void) #endif /* tiny heap size */ -/* 32KB */ -/*#define HEAP_SIZE 0x8000 */ -/* 128KB */ -/*#define HEAP_SIZE 0x20000 */ -/* 64KB */ -/*#define HEAP_SIZE 0x10000 */ -/* 16KB */ -#define HEAP_SIZE 0x4000 -/* 8KB */ -/*#define HEAP_SIZE 0x2000 */ -/* 4KB */ -/*#define HEAP_SIZE 0x1000 */ -/* 2KB */ -/*#define HEAP_SIZE 0x800 */ - -#define HEAP_OBJ_LIMIT (HEAP_SIZE / sizeof(struct RVALUE)) +#define BITMAP_ALIGN 0x4000 + +/* (16KB/sizeof(RVALUE) + 2) * sizeof(RVALUE) */ +#define HEAP_SIZE 0x4024 +#define BITMAP_MASK 0xFFFFc000 +#define HEAP_OBJ_LIMIT (HEAP_SIZE / sizeof(struct RVALUE) - 1) extern VALUE rb_cMutex; extern st_table *rb_class_tbl; @@ -783,6 +783,149 @@ allocate_heaps(rb_objspace_t *objspace, size_t next_heaps_length) heaps_length = next_heaps_length; } + +#define FIND_BITMAP(res, p) do {\ + if (((RVALUE *)p)->as.free.flags & FL_ALIGNOFF) {\ + res = (RVALUE *)((((VALUE)p & BITMAP_MASK) + BITMAP_ALIGN) / sizeof(RVALUE) * sizeof(RVALUE)); \ + }\ + else {\ + res = (RVALUE *)(((VALUE)p & BITMAP_MASK) / sizeof(RVALUE) * sizeof(RVALUE));\ + }\ +} while(0) + +#define NUM_IN_SLOT(p, slot) (((VALUE)p - (VALUE)slot)/sizeof(RVALUE)) +#define BITMAP_INDEX(bmap, p) (NUM_IN_SLOT(p, bmap->as.bitmap.slot) / (sizeof(int) * 8)) +// #define BITMAP_INDEX(bmap, p) (NUM_IN_SLOT(p, bmap->as.bitmap.slot) >> 5) +#define BITMAP_OFFSET(bmap, p) (NUM_IN_SLOT(p, bmap->as.bitmap.slot) & ((sizeof(int) * 8)-1)) +#define MARKED_IN_BITMAP(bmap, p) (bmap->as.bitmap.map[BITMAP_INDEX(bmap, p)] & 1 << BITMAP_OFFSET(bmap, p)) +#define MARK_IN_BITMAP(bmap, p) (bmap->as.bitmap.map[BITMAP_INDEX(bmap, p)] |= 1 << BITMAP_OFFSET(bmap, p)) +#define CLEAR_IN_BITMAP(bmap, p) (bmap->as.bitmap.map[BITMAP_INDEX(bmap, p)] &= ~(1 << BITMAP_OFFSET(bmap, p))) +#define MARKED_IN_BITMAP_DIRECT(map, index, offset) (map[index] & 1 << offset) +#define MARK_IN_BITMAP_DIRECT(map, index, offset) (map[index] |= 1 << offset) + +//for debug +void +bitmap_p(RVALUE *p) +{ + RVALUE *bmap; + int index, offset, marked; + + FIND_BITMAP(bmap, p); + index = BITMAP_INDEX(bmap, p); + offset = BITMAP_OFFSET(bmap, p); + marked = MARKED_IN_BITMAP(bmap, p); + printf("bitmap : ((RVALUE *)%p)\n", bmap); + printf("map_index : %d | offset : %d\n", index, offset); + printf("is mark ? %s\n", marked? "true" : "false"); +} + +VALUE +find_bitmap(RVALUE *p) { + RVALUE *res; + + FIND_BITMAP(res, p); + return (VALUE)res; +} + +void +dump_bitmap(RVALUE *bmap) { + int i; + + for (i = 0; i < 26; i++) { + printf("dump %p map %d : %d %s\n", bmap, i, bmap->as.bitmap.map[i], bmap->as.bitmap.map[i]? "remain" : "clean"); + } +} + +void +bitmap2obj(RVALUE *bmap, int index, int offset) +{ + printf("(RVALUE *)%p\n", (RVALUE *)(bmap->as.bitmap.slot + (index * sizeof(int) * 8 + offset) * sizeof(RVALUE))); +} + + +static void +make_bitmap(struct heaps_slot *slot) +{ + RVALUE *p, *pend, *bitmap, *last, *border; + int *map = 0; + int size; + + p = slot->slot; + pend = p + slot->limit; + last = pend - 1; + RBASIC(last)->flags = 0; + FIND_BITMAP(bitmap, last); + if (bitmap < p || pend <= bitmap) { + rb_bug("not include in heap slot: result bitmap(%p), find (%p), p (%p), pend(%p)", bitmap, last, p, pend); + } + border = bitmap; + if (!((VALUE)border % BITMAP_ALIGN)) { + border--; + } + while (p < pend) { + if (p <= border) { + RBASIC(p)->flags = FL_ALIGNOFF; + } + else { + RBASIC(p)->flags = 0; + } + p++; + } + + size = sizeof(int) * (HEAP_OBJ_LIMIT / (sizeof(int) * 8)+1); + map = (int *)malloc(size); + if (map == 0) { + rb_memerror(); + } + MEMZERO(map, int, (size/sizeof(int))); + bitmap->as.bitmap.flags |= T_BITMAP; + bitmap->as.bitmap.map = map; + bitmap->as.bitmap.slot = (VALUE)slot->slot; + bitmap->as.bitmap.limit = slot->limit; + slot->bitmap = bitmap; +} + +void +test_bitmap(RVALUE *p, RVALUE *pend) +{ + RVALUE *first, *bmap = 0, *bmap_tmp; + int i; + + first = p; + FIND_BITMAP(bmap_tmp, p); + while (p < pend) { + if (MARKED_IN_BITMAP(bmap, p)) printf("already marking! %p\n", p); + if (bmap_tmp != p) { + FIND_BITMAP(bmap, p); + if (bmap_tmp != bmap) printf("diffrence bmap %p : %p\n", bmap_tmp, bmap); + MARK_IN_BITMAP(bmap, p); + } + else { + MARK_IN_BITMAP(bmap, p); + } + if (!MARKED_IN_BITMAP(bmap, p)) printf("not marking! %p\n", p); + p++; + } + for (i =0; i < 26; i++) { + printf("bitmap[%d] : %x\n", i, bmap->as.bitmap.map[i]); + } + p = first; + while (p < pend) { + if (bmap_tmp != p) { + FIND_BITMAP(bmap, p); + CLEAR_IN_BITMAP(bmap, p); + } + else { + CLEAR_IN_BITMAP(bmap, p); + } + if (MARKED_IN_BITMAP(bmap, p)) printf("not clear! %p\n", p); + p++; + } + for (i =0; i < 26; i++) { + printf("bitmap[%d] : %x\n", i, bmap->as.bitmap.map[i]); + } +} + static void assign_heap_slot(rb_objspace_t *objspace) { @@ -801,9 +944,6 @@ assign_heap_slot(rb_objspace_t *objspace) membase = p; if ((VALUE)p % sizeof(RVALUE) != 0) { p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE))); - if ((HEAP_SIZE - HEAP_OBJ_LIMIT * sizeof(RVALUE)) < ((char*)p - (char*)membase)) { - objs--; - } } lo = 0; @@ -825,6 +965,7 @@ assign_heap_slot(rb_objspace_t *objspace) if (hi < heaps_used) { MEMMOVE(&heaps[hi+1], &heaps[hi], struct heaps_slot, heaps_used - hi); } + heaps[hi].membase = membase; heaps[hi].slot = p; heaps[hi].limit = objs; @@ -833,10 +974,12 @@ assign_heap_slot(rb_objspace_t *objspace) if (himem < pend) himem = pend; heaps_used++; + make_bitmap(&heaps[hi]); while (p < pend) { - p->as.free.flags = 0; - p->as.free.next = freelist; - freelist = p; + if (BUILTIN_TYPE(p) != T_BITMAP) { + p->as.free.next = freelist; + freelist = p; + } p++; } } @@ -888,6 +1031,7 @@ static VALUE rb_newobj_from_heap(rb_objspace_t *objspace) { VALUE obj; + int bmap_left = 0; if ((ruby_gc_stress && !ruby_disable_gc_stress) || !freelist) { if (!heaps_increment(objspace) && !garbage_collect(objspace)) { @@ -899,7 +1043,13 @@ rb_newobj_from_heap(rb_objspace_t *objspace) obj = (VALUE)freelist; freelist = freelist->as.free.next; + if (RANY(obj)->as.free.flags & FL_ALIGNOFF) { + bmap_left = Qtrue; + } MEMZERO((void*)obj, RVALUE, 1); + if (bmap_left) { + RANY(obj)->as.free.flags = FL_ALIGNOFF; + } #ifdef GC_DEBUG RANY(obj)->file = rb_sourcefile(); RANY(obj)->line = rb_sourceline(); @@ -915,13 +1065,15 @@ rb_fill_value_cache(rb_thread_t *th) rb_objspace_t *objspace = &rb_objspace; int i; VALUE rv; + RVALUE *bmap; /* LOCK */ for (i=0; ivalue_cache[i] = v; - RBASIC(v)->flags = FL_MARK; + FIND_BITMAP(bmap, v); + MARK_IN_BITMAP(bmap, v); } th->value_cache_ptr = &th->value_cache[0]; rv = rb_newobj_from_heap(objspace); @@ -960,7 +1112,7 @@ rb_newobj(void) #if USE_VALUE_CACHE if (v) { - RBASIC(v)->flags = 0; + FL_FORCE_SET(p, 0); th->value_cache_ptr++; } else { @@ -1085,18 +1237,21 @@ init_mark_stack(rb_objspace_t *objspace) static void gc_mark(rb_objspace_t *objspace, VALUE ptr, int lev); static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev); +#define IS_FREE_CELL(obj) ((obj->as.basic.flags & ~(FL_ALIGNOFF)) == 0) + static void gc_mark_all(rb_objspace_t *objspace) { - RVALUE *p, *pend; + RVALUE *p, *pend, *bmap; size_t i; init_mark_stack(objspace); for (i = 0; i < heaps_used; i++) { p = heaps[i].slot; pend = p + heaps[i].limit; + bmap = heaps[i].bitmap; while (p < pend) { - if ((p->as.basic.flags & FL_MARK) && - (p->as.basic.flags != FL_MARK)) { + if (MARKED_IN_BITMAP(bmap, p) && + !(IS_FREE_CELL(p))) { gc_mark_children(objspace, (VALUE)p, 0); } p++; @@ -1271,13 +1426,15 @@ rb_gc_mark_maybe(VALUE obj) static void gc_mark(rb_objspace_t *objspace, VALUE ptr, int lev) { - register RVALUE *obj; + register RVALUE *obj, *bmap; obj = RANY(ptr); if (rb_special_const_p(ptr)) return; /* special const not marked */ - if (obj->as.basic.flags == 0) return; /* free cell */ - if (obj->as.basic.flags & FL_MARK) return; /* already marked */ - obj->as.basic.flags |= FL_MARK; + if (IS_FREE_CELL(obj)) return; /* free cell */ + if (BUILTIN_TYPE(obj) == T_BITMAP) return; + FIND_BITMAP(bmap, obj); + if (MARKED_IN_BITMAP(bmap, obj)) return; /* already marked */ + MARK_IN_BITMAP(bmap, obj); if (lev > GC_LEVEL_MAX || (lev == 0 && stack_check())) { if (!mark_stack_overflow) { @@ -1303,16 +1460,17 @@ rb_gc_mark(VALUE ptr) static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev) { - register RVALUE *obj = RANY(ptr); + register RVALUE *obj = RANY(ptr), *bmap; goto marking; /* skip */ again: obj = RANY(ptr); if (rb_special_const_p(ptr)) return; /* special const not marked */ - if (obj->as.basic.flags == 0) return; /* free cell */ - if (obj->as.basic.flags & FL_MARK) return; /* already marked */ - obj->as.basic.flags |= FL_MARK; + if (IS_FREE_CELL(obj)) return; /* free cell */ + FIND_BITMAP(bmap, obj); + if (MARKED_IN_BITMAP(bmap, obj)) return; /* already marked */ + MARK_IN_BITMAP(bmap, obj); marking: if (FL_TEST(obj, FL_EXIVAR)) { @@ -1573,8 +1731,12 @@ static int obj_free(rb_objspace_t *, VALUE); static inline void add_freelist(rb_objspace_t *objspace, RVALUE *p) { + RVALUE *bmap; + VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); - p->as.free.flags = 0; + FL_FORCE_SET(p, 0); + FIND_BITMAP(bmap, p); + CLEAR_IN_BITMAP(bmap, p); p->as.free.next = freelist; freelist = p; } @@ -1600,15 +1762,17 @@ static void free_unused_heaps(rb_objspace_t *objspace) { size_t i, j; - RVALUE *last = 0; + RVALUE *last = 0, *bmap = 0; for (i = j = 1; j < heaps_used; i++) { if (heaps[i].limit == 0) { if (!last) { last = heaps[i].membase; + bmap = heaps[i].bitmap; } else { free(heaps[i].membase); + free(heaps[i].bitmap->as.bitmap.map); } heaps_used--; } @@ -1622,10 +1786,13 @@ free_unused_heaps(rb_objspace_t *objspace) if (last) { if (last < heaps_freed) { free(heaps_freed); + free(objspace->heap.freed_bitmap->as.bitmap.map); heaps_freed = last; + heaps_freed = bmap; } else { free(last); + free(bmap->as.bitmap.map); } } } @@ -1653,25 +1820,35 @@ gc_sweep(rb_objspace_t *objspace) int free_num = 0, final_num = 0; RVALUE *free = freelist; RVALUE *final = final_list; - int deferred; + int *map = heaps[i].bitmap->as.bitmap.map; + int deferred, bmap_index = 0, bmap_offset = 0; p = heaps[i].slot; pend = p + heaps[i].limit; while (p < pend) { - if (!(p->as.basic.flags & FL_MARK)) { - if (p->as.basic.flags && + if (BUILTIN_TYPE(p) == T_BITMAP) { + free_num++; + } + else if(!(MARKED_IN_BITMAP_DIRECT(map, bmap_index, bmap_offset))) { + if (!(IS_FREE_CELL(p)) && ((deferred = obj_free(objspace, (VALUE)p)) || ((FL_TEST(p, FL_FINALIZE)) && need_call_final))) { if (!deferred) { - p->as.free.flags = T_ZOMBIE; + FL_FORCE_SET(p, T_ZOMBIE); RDATA(p)->dfree = 0; } - p->as.free.flags |= FL_MARK; p->as.free.next = final_list; final_list = p; final_num++; } else { - add_freelist(objspace, p); + /* Do not touch the fields if they don't have to be modified. + * This is in order to preserve copy-on-write semantics. + */ + if (!IS_FREE_CELL(p)) + FL_FORCE_SET(p, 0); + if (p->as.free.next != freelist) + p->as.free.next = freelist; + freelist = p; free_num++; } } @@ -1680,11 +1857,16 @@ gc_sweep(rb_objspace_t *objspace) /* do nothing remain marked */ } else { - RBASIC(p)->flags &= ~FL_MARK; live++; } p++; + bmap_offset++; + if (bmap_offset >= (sizeof(int) * 8)) { + bmap_index++; + bmap_offset = 0; + } } + MEMZERO(heaps[i].bitmap->as.bitmap.map, int, bmap_index+1); if (final_num + free_num == heaps[i].limit && freed > do_heap_free) { RVALUE *pp; @@ -1714,11 +1896,16 @@ gc_sweep(rb_objspace_t *objspace) /* clear finalization list */ if (final_list) { + RVALUE *bmap, *pp; + for (pp = final_list; pp != 0; pp = pp->as.free.next) { + FIND_BITMAP(bmap, pp); + MARK_IN_BITMAP(bmap, pp); + } GC_PROF_SET_HEAP_INFO; deferred_final_list = final_list; RUBY_VM_SET_FINALIZER_INTERRUPT(GET_THREAD()); } - else{ + else { free_unused_heaps(objspace); GC_PROF_SET_HEAP_INFO; } @@ -1734,7 +1921,7 @@ rb_gc_force_recycle(VALUE p) static inline void make_deferred(RVALUE *p) { - p->as.basic.flags = (p->as.basic.flags & ~T_MASK) | T_ZOMBIE; + FL_FORCE_SET(p, ((p->as.basic.flags & ~T_MASK) | T_ZOMBIE)); } static inline void @@ -2102,12 +2289,13 @@ os_obj_of(rb_objspace_t *objspace, VALUE of) p = heaps[i].slot; pend = p + heaps[i].limit; for (;p < pend; p++) { - if (p->as.basic.flags) { + if (!IS_FREE_CELL(p)) { switch (BUILTIN_TYPE(p)) { case T_NONE: case T_ICLASS: case T_NODE: case T_ZOMBIE: + case T_BITMAP: continue; case T_CLASS: if (FL_TEST(p, FL_SINGLETON)) continue; @@ -2311,10 +2499,12 @@ rb_gc_finalize_deferred(void) static int chain_finalized_object(st_data_t key, st_data_t val, st_data_t arg) { - RVALUE *p = (RVALUE *)key, **final_list = (RVALUE **)arg; + RVALUE *p = (RVALUE *)key, **final_list = (RVALUE **)arg, *bmap; if (p->as.basic.flags & FL_FINALIZE) { if (BUILTIN_TYPE(p) != T_ZOMBIE) { - p->as.free.flags = FL_MARK | T_ZOMBIE; /* remain marked */ + FL_FORCE_SET(p, T_ZOMBIE); + FIND_BITMAP(bmap, p); + MARK_IN_BITMAP(bmap, p); RDATA(p)->dfree = 0; } p->as.free.next = *final_list; @@ -2358,7 +2548,7 @@ rb_gc_call_finalizer_at_exit(void) if (BUILTIN_TYPE(p) == T_DATA && DATA_PTR(p) && RANY(p)->as.data.dfree && RANY(p)->as.basic.klass != rb_cThread && RANY(p)->as.basic.klass != rb_cMutex) { - p->as.free.flags = 0; + FL_FORCE_SET(p, 0); if ((long)RANY(p)->as.data.dfree == -1) { xfree(DATA_PTR(p)); } @@ -2372,6 +2562,7 @@ rb_gc_call_finalizer_at_exit(void) if (RANY(p)->as.file.fptr) { make_io_deferred(RANY(p)); RANY(p)->as.free.next = final_list; + FL_FORCE_SET(p, 0); final_list = p; } } @@ -2564,7 +2755,7 @@ count_objects(int argc, VALUE *argv, VALUE os) p = heaps[i].slot; pend = p + heaps[i].limit; for (;p < pend; p++) { - if (p->as.basic.flags) { + if (!IS_FREE_CELL(p)) { counts[BUILTIN_TYPE(p)]++; } else { diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index b1fe650..40eca5f 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -310,6 +310,7 @@ enum ruby_value_type { RUBY_T_FALSE = 0x13, RUBY_T_SYMBOL = 0x14, RUBY_T_FIXNUM = 0x15, + RUBY_T_BITMAP = 0x19, RUBY_T_UNDEF = 0x1b, RUBY_T_NODE = 0x1c, @@ -334,6 +335,7 @@ enum ruby_value_type { #define T_BIGNUM RUBY_T_BIGNUM #define T_FILE RUBY_T_FILE #define T_FIXNUM RUBY_T_FIXNUM +#define T_BITMAP RUBY_T_BITMAP #define T_TRUE RUBY_T_TRUE #define T_FALSE RUBY_T_FALSE #define T_DATA RUBY_T_DATA @@ -499,9 +501,17 @@ char *rb_str2cstr(VALUE,long*); #define CHR2FIX(x) INT2FIX((long)((x)&0xff)) VALUE rb_newobj(void); +#define FL_FORCE_SET(obj,t) do {\ + if (RBASIC(obj)->flags & FL_ALIGNOFF) {\ + RBASIC(obj)->flags = FL_ALIGNOFF | t;\ + }\ + else {\ + RBASIC(obj)->flags = t;\ + }\ +} while(0) #define NEWOBJ(obj,type) type *obj = (type*)rb_newobj() #define OBJSETUP(obj,c,t) do {\ - RBASIC(obj)->flags = (t);\ + FL_FORCE_SET(obj, t);\ RBASIC(obj)->klass = (c);\ if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT | FL_UNTRUSTED);\ } while (0) @@ -777,7 +787,7 @@ struct RBignum { #define RCOMPLEX(obj) (R_CAST(RComplex)(obj)) #define FL_SINGLETON FL_USER0 -#define FL_MARK (((VALUE)1)<<5) +#define FL_ALIGNOFF (((VALUE)1)<<5) #define FL_RESERVED (((VALUE)1)<<6) /* will be used in the future GC */ #define FL_FINALIZE (((VALUE)1)<<7) #define FL_TAINT (((VALUE)1)<<8) diff --git a/object.c b/object.c index be99de6..7cc9f32 100644 --- a/object.c +++ b/object.c @@ -233,7 +233,8 @@ rb_obj_clone(VALUE obj) } clone = rb_obj_alloc(rb_obj_class(obj)); RBASIC(clone)->klass = rb_singleton_class_clone(obj); - RBASIC(clone)->flags = (RBASIC(obj)->flags | FL_TEST(clone, FL_TAINT) | FL_TEST(clone, FL_UNTRUSTED)) & ~(FL_FREEZE|FL_FINALIZE); + RBASIC(clone)->flags = ((RBASIC(obj)->flags & ~(FL_ALIGNOFF|FL_FREEZE|FL_FINALIZE)) | + FL_TEST(clone, FL_ALIGNOFF|FL_TAINT|FL_UNTRUSTED)); init_copy(clone, obj); RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE; diff --git a/vm.c b/vm.c index 782fc99..11d0ebe 100644 --- a/vm.c +++ b/vm.c @@ -1479,7 +1479,7 @@ thread_free(void *ptr) VALUE *ptr = th->value_cache_ptr; while (*ptr) { VALUE v = *ptr; - RBASIC(v)->flags = 0; + FL_FORCE_SET(v, 0); RBASIC(v)->klass = 0; ptr++; } @@ -1789,7 +1789,7 @@ Init_VM(void) /* ::VM::FrozenCore */ fcore = rb_class_new(rb_cBasicObject); - RBASIC(fcore)->flags = T_ICLASS; + FL_FORCE_SET(fcore, T_ICLASS); klass = rb_singleton_class(fcore); rb_define_method_id(klass, id_core_set_method_alias, m_core_set_method_alias, 3); rb_define_method_id(klass, id_core_set_variable_alias, m_core_set_variable_alias, 2); --Multipart_Fri_Dec_12_09:44:29_2008-1--