// Cache.h -- "Obstack"-like caches for translated code and pc maps
//
// Author: Ian.Piumarta@INRIA.Fr
//
// Last edited: 2000-12-06 14:55:33 by piumarta on emilia.rd.wdi.disney.com
//
// BUGS:
//	addresses should be "void *" but ANSI C++ makes life unreasonably
//	difficult by forbidding arithmetic on "void *", so we (ab)use
//	"char *" instead.


#ifndef _j_Cache_h
#define _j_Cache_h


#include "debug.h"	// dprintf(), assert(), fatal()
#include "xmalloc.h"

#include <stdlib.h>

// trivial obstack-like cache manager.
//
// allocation blocks are grabbed from malloc() and then carved up
// in two phases:
//	1: reserve(lbs) reserves up to lbs bytes in the cache, starting
//	   a new allocation block if necessary;
//	2: allocate(lbs) finalises the previously reserved memory, where
//	   the final lbs must be no greater than the reserved lbs.
//
// implementation is entirely inline, since cache clients are limited to
// the operators new() in a handful of classes. 

class Cache
{
private:

  // default delta if none speficied in ctor

  static const size_t DefaultQuantum= 128*1024;

private:
  size_t      quantum;	// delta by which cache grows
  char	     *base,	// base of current allocation block
	     *lwm,	// next free location in current block
	     *hwm;	// first location beyond current block
  int	     nBytes,	// number of bytes allocated
  	     nLost,	// number of bytes lost to fragmentation
	     nEntries,	// number of entries made
	     nBlocks;	// number of blocks allocated
  size_t     reserved;	// size of previously reserved block

public:

  Cache(size_t q= DefaultQuantum, char *b= 0);
  ~Cache(void);

  // declare intention to use up to lbs bytes in the cache.
  // called before allocate(N), where N <= lbs.

  char *reserve(size_t lbs);

  // definitive allocation of lbs bytes in the cache.
  // called after reserve(N), where lbs <= N.

  inline char *allocate(size_t lbs)
    {
      lbs= (lbs + 3) & ~3;	// round to nearest word
      if (lbs > reserved)
	fatal("cache overrun");
      assert((size_t)lwm + lbs < (size_t)hwm);
      ++nEntries;
      nBytes+= lbs;
      lwm+= lbs;
      return lwm - lbs;
    }

  size_t printStatsOn(char *buf)
    {
      buf+= sprintf(buf, "%5d blks,%8d byts,%6d lost,%5d byts/ent,%6.1f%% fragment",
		    nBlocks, nBytes, nLost, nBytes / nEntries,
		    percent(nLost, (nBlocks - 1) * quantum));
      return nBytes;
    }

}; // class Cache


extern Cache *mapCache;
extern Cache *codeCache;
extern Cache *iclCache;


#endif // _j_Cache_h
