From ecebbcce1f58687bdcc1028bc8813f004bc22427 Mon Sep 17 00:00:00 2001 From: akr Date: Thu, 2 Mar 2006 05:22:30 +0000 Subject: * gc.c: align VALUE with sizeof(RVALUE) globally. (is_pointer_to_heap): check alignment out of loop. (id2ref): avoid collision between symbols and objects. (rb_obj_id): ditto. moved from object.c. [ruby-talk:178364] [ruby-core:7401] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10013 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- gc.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 92 insertions(+), 10 deletions(-) (limited to 'gc.c') diff --git a/gc.c b/gc.c index f2a895926e..2e9c3b3eaa 100644 --- a/gc.c +++ b/gc.c @@ -344,6 +344,7 @@ static RVALUE *deferred_final_list = 0; #define HEAPS_INCREMENT 10 static struct heaps_slot { + void *membase; RVALUE *slot; int limit; } *heaps; @@ -381,8 +382,7 @@ add_heap(void) } for (;;) { - RUBY_CRITICAL(p = heaps[heaps_used].slot = (RVALUE*)malloc(sizeof(RVALUE)*heap_slots)); - heaps[heaps_used].limit = heap_slots; + RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1))); if (p == 0) { if (heap_slots == HEAP_MIN_SLOTS) { rb_memerror(); @@ -390,6 +390,13 @@ add_heap(void) heap_slots = HEAP_MIN_SLOTS; continue; } + heaps[heaps_used].membase = p; + if ((VALUE)p % sizeof(RVALUE) == 0) + heap_slots += 1; + else + p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE))); + heaps[heaps_used].slot = p; + heaps[heaps_used].limit = heap_slots; break; } pend = p + heap_slots; @@ -625,12 +632,12 @@ is_pointer_to_heap(void *ptr) register long i; if (p < lomem || p > himem) return Qfalse; + if ((VALUE)p % sizeof(RVALUE) != 0) return Qfalse; /* check if p looks like a pointer */ for (i=0; i < heaps_used; i++) { heap_org = heaps[i].slot; - if (heap_org <= p && p < heap_org + heaps[i].limit && - ((((char*)p)-((char*)heap_org))%sizeof(RVALUE)) == 0) + if (heap_org <= p && p < heap_org + heaps[i].limit) return Qtrue; } return Qfalse; @@ -1019,7 +1026,7 @@ free_unused_heaps(void) for (i = j = 1; j < heaps_used; i++) { if (heaps[i].limit == 0) { - free(heaps[i].slot); + free(heaps[i].membase); heaps_used--; } else { @@ -1905,7 +1912,7 @@ rb_gc_call_finalizer_at_exit(void) */ static VALUE -id2ref(VALUE obj, VALUE id) +id2ref(VALUE obj, VALUE objid) { #if SIZEOF_LONG == SIZEOF_VOIDP #define NUM2PTR(x) NUM2ULONG(x) @@ -1916,18 +1923,22 @@ id2ref(VALUE obj, VALUE id) void *p0; rb_secure(4); - ptr = NUM2PTR(id); + ptr = NUM2PTR(objid); p0 = (void *)ptr; if (ptr == Qtrue) return Qtrue; if (ptr == Qfalse) return Qfalse; if (ptr == Qnil) return Qnil; if (FIXNUM_P(ptr)) return (VALUE)ptr; - if (SYMBOL_P(ptr) && rb_id2name(SYM2ID((VALUE)ptr)) != 0) { - return (VALUE)ptr; + + if ((objid % sizeof(RVALUE)) == (4 << 2)) { + ID symid = objid / sizeof(RVALUE); + if (rb_id2name(symid) == 0) + rb_raise(rb_eRangeError, "%p is not symbol id value", p0); + return ID2SYM(symid); } - ptr = id ^ FIXNUM_FLAG; /* unset FIXNUM_FLAG */ + ptr = objid ^ FIXNUM_FLAG; /* unset FIXNUM_FLAG */ if (!is_pointer_to_heap((void *)ptr)|| BUILTIN_TYPE(ptr) >= T_BLOCK) { rb_raise(rb_eRangeError, "%p is not id value", p0); } @@ -1937,6 +1948,73 @@ id2ref(VALUE obj, VALUE id) return (VALUE)ptr; } +/* + * Document-method: __id__ + * Document-method: object_id + * + * call-seq: + * obj.__id__ => fixnum + * obj.object_id => fixnum + * + * Returns an integer identifier for obj. The same number will + * be returned on all calls to id for a given object, and + * no two active objects will share an id. + * Object#object_id is a different concept from the + * :name notation, which returns the symbol id of + * name. Replaces the deprecated Object#id. + */ + +/* + * call-seq: + * obj.hash => fixnum + * + * Generates a Fixnum hash value for this object. This + * function must have the property that a.eql?(b) implies + * a.hash == b.hash. The hash value is used by class + * Hash. Any hash value that exceeds the capacity of a + * Fixnum will be truncated before being used. + */ + +VALUE +rb_obj_id(VALUE obj) +{ + /* + * 32-bit VALUE space + * MSB ------------------------ LSB + * false 00000000000000000000000000000000 + * true 00000000000000000000000000000010 + * nil 00000000000000000000000000000100 + * undef 00000000000000000000000000000110 + * symbol ssssssssssssssssssssssss00001110 + * object oooooooooooooooooooooooooooooo00 = 0 (mod sizeof(RVALUE)) + * fixnum fffffffffffffffffffffffffffffff1 + * + * object_id space + * LSB + * false 00000000000000000000000000000000 + * true 00000000000000000000000000000010 + * nil 00000000000000000000000000000100 + * undef 00000000000000000000000000000110 + * symbol 000SSSSSSSSSSSSSSSSSSSSSSSSSSS0 S...S % A = 4 (S...S = s...s * A + 4) + * object oooooooooooooooooooooooooooooo0 o...o % A = 0 + * fixnum fffffffffffffffffffffffffffffff1 bignum if required + * + * where A = sizeof(RVALUE)/4 + * + * sizeof(RVALUE) is + * 20 if 32-bit, double is 4-byte aligned + * 24 if 32-bit, double is 8-byte aligned + * 40 if 64-bit + */ + if (TYPE(obj) == T_SYMBOL) { + return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG; + } + if (SPECIAL_CONST_P(obj)) { + return LONG2NUM((long)obj); + } + return (VALUE)((long)obj|FIXNUM_FLAG); +} + /* * The GC module provides an interface to Ruby's mark and * sweep garbage collection mechanism. Some of the underlying methods @@ -1978,4 +2056,8 @@ Init_GC(void) rb_global_variable(&nomem_error); nomem_error = rb_exc_new2(rb_eNoMemError, "failed to allocate memory"); + + rb_define_method(rb_mKernel, "hash", rb_obj_id, 0); + rb_define_method(rb_mKernel, "__id__", rb_obj_id, 0); + rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0); } -- cgit v1.2.3