obj rs_gf_find_method( obj gf, obj rcvr ) { obj c, m, impl, h, k; UINT_32 k_ix, v_ix; #ifdef GF_DEBUG if (!foo) foo = fopen( "/tmp/gf.trc", "w" ); #endif /* GF_DEBUG */ c = object_class(rcvr); h = FX_AND(gvec_ref(c, CLASS_HASH_CODE),int2fx(3*2)); k_ix = GF_CACHE_0_K + FXWORDS_TO_RIBYTES(h); v_ix = k_ix + SLOT(1); k = gvec_ref( gf, k_ix ); #ifdef GF_DEBUG gf_stat(gf); #endif /* GF_DEBUG */ if (EQ(k,c)) return gvec_ref( gf, v_ix ); else { /* check the victim entry */ k = gvec_ref( gf, GF_VICTIM_K ); if (EQ(k,c)) { m = gvec_ref( gf, GF_VICTIM_V ); /* a hit -- victimize the primary entry * (note: there is no way you can hit in the victim cache * if your primary entry is #f) */ gvec_write_ptr( gf, GF_VICTIM_K, gvec_ref( gf, k_ix ) ); gvec_write_ptr( gf, GF_VICTIM_V, gvec_ref( gf, v_ix ) ); gvec_write_ptr( gf, k_ix, k ); gvec_write_ptr( gf, v_ix, m ); return m; } else { obj ov, new_ov, prev = ZERO; #ifdef GF_DEBUG fprintf( foo, "%s: check overflow for key = %s\n", symbol_text( gvec_ref( gf, SLOT(3) ) ), symbol_text( class_name( c ) ) ); if (truish( gvec_ref( gf, k_ix ) )) fprintf( foo, " primary[%d] => %s\n", fx2int(h), symbol_text( class_name( gvec_ref( gf, k_ix ) ) ) ); if (truish(k)) fprintf( foo, " victim => %s\n", symbol_text( class_name( k ) ) ); #endif /* GF_DEBUG */ /* a primary miss -- check the overflow list */ for (ov = gvec_ref( gf, GF_CACHE_OVERFLOW ); !EQ(ov,FALSE_OBJ); ov = gvec_ref( ov, SLOT(0) ) ) { k = gvec_ref( ov, SLOT(1) ); #ifdef GF_DEBUG fprintf( foo, " overflow {%#x} => %s\n", ov, symbol_text( class_name( k ) ) ); #endif /* GF_DEBUG */ if (EQ(k,c)) { #ifdef GF_DEBUG fprintf( foo, " HIT (prev = {%#x})\n", prev ); #endif /* GF_DEBUG */ m = gvec_ref( ov, SLOT(2) ); /* found it in the overflow list... move this entry * to the primary cache area and spill the victim cache */ new_ov = make3( vector_class, (EQ(prev,ZERO) ? gvec_ref( ov, SLOT(0) ) : gvec_ref( gf, GF_CACHE_OVERFLOW )), gvec_ref( gf, GF_VICTIM_K ), gvec_ref( gf, GF_VICTIM_V ) ); gvec_write_ptr( gf, GF_VICTIM_K, gvec_ref( gf, k_ix ) ); gvec_write_ptr( gf, GF_VICTIM_V, gvec_ref( gf, v_ix ) ); if (!EQ(prev,ZERO)) gvec_write( prev, SLOT(0), gvec_ref( ov, SLOT(0) ) ); gvec_write_ptr( gf, GF_CACHE_OVERFLOW, new_ov ); gvec_write_ptr( gf, k_ix, k ); gvec_write_ptr( gf, v_ix, m ); #ifdef GF_DEBUG gf_stat(gf); #endif /* GF_DEBUG */ return m; } prev = ov; } #ifdef GF_DEBUG fprintf( foo, " MISS\n" ); #endif /* GF_DEBUG */ return FALSE_OBJ; } } }
void split_bucket( obj table, obj bucket, obj h, obj k, obj v ) { int i, di, j, dir_bits, bucket_bits; obj b, vec; struct bucket_chain hi, lo; UINT_32 mask; dir_bits = fx2int(gvec_read(table,HASHTABLE_DIR_BITS)); vec = gvec_read( table, HASHTABLE_DIRECTORY ); if (EQ(bucket,FALSE_OBJ)) { bucket = make_bucket( gvec_read( table, HASHTABLE_BUCKET_CLASS ), dir_bits ); write_dir( vec, h, bucket ); write_bucket_hash( bucket, SLOT(2), h ); write_bucket_key( bucket, SLOT(2), k ); write_bucket_value( bucket, SLOT(2), v ); return; } bucket_bits = fx2int(gvec_read(bucket,BUCKET_BITS)); /* grow the hash table's directory if necessary */ if (dir_bits == bucket_bits) { UINT_32 i, old_size; obj old_vec = vec; old_size = 1<<dir_bits; dir_bits++; #ifdef DEBUG_0 printf( "growing directory from %u entries\n", old_size ); #endif /* DEBUG_0 */ vec = alloc( SLOT(2*old_size), vector_class ); for (i=0; i<old_size; i++) gvec_write_init( vec, SLOT(i), gvec_read( old_vec, SLOT(i) ) ); for (i=0; i<old_size; i++) gvec_write_init( vec, SLOT(i + old_size), gvec_read( old_vec, SLOT(i) ) ); gvec_write_ptr( table, HASHTABLE_DIRECTORY, vec ); gvec_write_non_ptr( table, HASHTABLE_DIR_BITS, int2fx(dir_bits) ); } /* initialize the structures for the new chains */ #ifdef DEBUG_0 printf( "initializing hi/lo\n" ); #endif /* DEBUG_0 */ init_chain( table, &hi, bucket_bits+1 ); init_chain( table, &lo, bucket_bits+1 ); /* traverse the bucket */ /* this mask selects the bit that distinguishes the "hi" bucket from the "lo" bucket */ mask = VAL(int2fx(1)) << bucket_bits; #ifdef DEBUG_0 printf( "mask = %#x\n", mask ); #endif /* DEBUG_0 */ chain_insert( (VAL(h) & mask) ? &hi : &lo, h, k, v ); for (b=bucket; !EQ(b,FALSE_OBJ); b=gvec_read(b,BUCKET_OVERFLOW)) { for (i=SLOT(2); i<SLOT(2+BUCKET_CAPACITY); i+=SLOT(1)) { obj h = gvec_read( b, i ); struct bucket_chain *use; use = (VAL(h) & mask) ? &hi : &lo; chain_insert( use, h, gvec_read( b, i+SLOT(BUCKET_CAPACITY) ), gvec_read( b, i+2*SLOT(BUCKET_CAPACITY) ) ); } } /* install the new bucket chains in the directory */ i = SLOT( fx2int( h ) & ((1 << bucket_bits) - 1) ); di = SLOT( 1 << bucket_bits ); for (j=0; j<(1<<(dir_bits - (bucket_bits+1))); j++) { #ifdef DEBUG_0 printf( "installing lo at %u\n", i/W ); #endif /* DEBUG_0 */ gvec_write( vec, i, lo.first ); i += di; #ifdef DEBUG_0 printf( "installing hi at %u\n", i/W ); #endif /* DEBUG_0 */ gvec_write( vec, i, hi.first ); i += di; } }