diff --git a/ChangeLog b/ChangeLog index 369adc733c..dc25ee6b25 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Thu Mar 2 14:12:26 2006 Tanaka Akira + + * 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] + Thu Mar 2 12:55:16 2006 Hirokazu Yamamoto * win32/win32.c (filetime_to_unixtime): should set tm_isdst to -1. 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); } diff --git a/object.c b/object.c index 233b9ee131..e3102acc2b 100644 --- a/object.c +++ b/object.c @@ -95,45 +95,6 @@ rb_obj_equal(VALUE obj1, VALUE obj2) return Qfalse; } - -/* - * 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) -{ - if (SPECIAL_CONST_P(obj)) { - return LONG2NUM((long)obj); - } - return (VALUE)((long)obj|FIXNUM_FLAG); -} - VALUE rb_class_real(VALUE cl) { @@ -2418,9 +2379,6 @@ Init_Object(void) rb_define_method(rb_mKernel, "eql?", rb_obj_equal, 1); - 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); rb_define_method(rb_mKernel, "class", rb_obj_class, 0); rb_define_method(rb_mKernel, "clone", rb_obj_clone, 0); diff --git a/ruby.h b/ruby.h index ca4cf27d3c..bd318d8f73 100644 --- a/ruby.h +++ b/ruby.h @@ -184,7 +184,7 @@ VALUE rb_ull2inum(unsigned LONG_LONG); #define SYMBOL_FLAG 0x0e #define SYMBOL_P(x) (((VALUE)(x)&0xff)==SYMBOL_FLAG) #define ID2SYM(x) ((VALUE)(((long)(x))<<8|SYMBOL_FLAG)) -#define SYM2ID(x) RSHIFT((long)x,8) +#define SYM2ID(x) RSHIFT((VALUE)x,8) /* special contants - i.e. non-zero and non-fixnum constants */ #define Qfalse ((VALUE)0)