Esempio n. 1
0
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;
	}
    }
}
Esempio n. 2
0
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;
    }
}