> I've tried to fix the bug by partitioning the ID space as follows: > > LSB > false 00000000000000000000000000000001 > true 00000000000000000000000000000101 > nil 00000000000000000000000000001001 > Fixnum xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx10001 | > symbol ssssssssssssssssssssssss000011101 | expanded to Bignum > when needed > object oooooooooooooooooooooooooooooo11 > > > The patch is not pretty but it seems to work: I can attest to its ugliness, but not its correctness. Akira, Matz, Guy... someone of that calibre will have to do that. What I can say is that it DOES seem to work. It passes full unit tests (usual failures aside) and eric's torture script. PLEASE PLEASE PLEASE lets get this fixed and soon on both head and 1.8!!! This really messes with rails development (rails is by far one of the worst stress tests for ruby) and a lot of other stuff we're doing. We get it all the time. I backported it with a little difficulty to 1.8: Index: gc.c =================================================================== RCS file: /src/ruby/gc.c,v retrieving revision 1.168.2.37 diff -d -u -r1.168.2.37 gc.c --- gc.c 13 Feb 2006 09:10:53 -0000 1.168.2.37 +++ gc.c 28 Feb 2006 00:17:35 -0000 @@ -1888,19 +1888,47 @@ id2ref(obj, id) VALUE obj, id; { +#if SIZEOF_LONG == SIZEOF_VOIDP +#define NUM2PTR(x) NUM2ULONG(x) +#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP +#define NUM2PTR(x) NUM2ULL(x) +#endif unsigned long ptr, p0; + BDIGIT *digit; rb_secure(4); - p0 = ptr = NUM2ULONG(id); - 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) { + + if (TYPE(id) == T_BIGNUM) { + digit = ((BDIGIT*)RBIGNUM(id)->digits); + if((*digit & 0xf) == FIXNUM_ID_MASK) { + return rb_big_lshift(id, INT2FIX(-(FIXNUM_ID_SHIFT+1))); + } + else { + ptr = NUM2PTR(id); + p0 = (void *)ptr; + if (SYMBOL_P(ptr) && rb_id2name(SYM2ID((VALUE)ptr)) != 0) { + return (VALUE)ptr; + } + } + } + else { + ptr = NUM2PTR(id); + p0 = (void *)ptr; + + if (ptr == Qtrue) return Qtrue; + if (ptr == Qfalse) return Qfalse; + if (ptr == Qnil) return Qnil; + if (SYMBOL_P(ptr) && rb_id2name(SYM2ID((VALUE)ptr)) != 0) { return (VALUE)ptr; + } + + if ((ptr & 0xf) == FIXNUM_ID_MASK) { + return (VALUE)(ptr >> FIXNUM_ID_SHIFT); + } + + ptr = id ^ IMMEDIATE_MASK; /* unset IMMEDIATE_MASK */ } - ptr = id ^ FIXNUM_FLAG; /* unset FIXNUM_FLAG */ if (!is_pointer_to_heap((void *)ptr)|| BUILTIN_TYPE(ptr) >= T_BLKTAG) { rb_raise(rb_eRangeError, "0x%lx is not id value", p0); } Index: ruby.h =================================================================== RCS file: /src/ruby/ruby.h,v retrieving revision 1.97.2.11 diff -d -u -r1.97.2.11 ruby.h --- ruby.h 5 Feb 2006 15:43:10 -0000 1.97.2.11 +++ ruby.h 28 Feb 2006 00:17:35 -0000 @@ -164,10 +164,13 @@ #define IMMEDIATE_MASK 0x03 #define IMMEDIATE_P(x) ((VALUE)(x) & IMMEDIATE_MASK) +#define FIXNUM_ID_MASK 0x08 +#define FIXNUM_ID_SHIFT 3 + #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((unsigned long)x,8) /* special contants - i.e. non-zero and non-fixnum constants */ #define Qfalse ((VALUE)0)