storage.h

/*
 * storage.h -- Declarations for storage management (gc)
 *
 * (C) m.b (Matthias Blume); Jun 1992, HUB; Nov 1993 PU/CS
 *         Humboldt-University of Berlin
 *         Princeton University, Dept. of Computer Science
 *
 * $Id: storage.h,v 2.6 1994/09/01 20:11:07 blume Exp $
 */

# ifndef STORAGE_H_
# define STORAGE_H_

# include <stdio.h>
# include <time.h>

# include "align.h"

# define MEM_UNITS(n) (((n) + sizeof (MEM_align_t) - 1) / sizeof (MEM_align_t))

/*
 * The implementation of the storage module never needs to access the
 * ``extension'' field (see below) and never computes the size of the
 * MEM_description structure.  Therefore, we are free to compile the
 * storage module in the absence of "storext.h" (which is supposed to
 * provide the real declaration of ``MEM_extension'').
 */
# ifdef MEM_IMPLEMENTATION
typedef int MEM_extension;
# else
# include "storext.h"
# endif

typedef unsigned long MEM_cnt;

typedef MEM_cnt (* MEM_measure) (void *object);
typedef void (* MEM_visitor) (void **object_ptr, void *cd);
typedef void (* MEM_iterator) (void *object, MEM_visitor v, void *cd);
typedef void (* MEM_dumper) (void *object, FILE *file);
typedef void  *(* MEM_excavator) (FILE *file);
typedef void (* MEM_revisor) (void *object);
typedef void (* MEM_task) (void);

# define MEM_NULL_measure   ((MEM_measure) 0)
# define MEM_NULL_iterator  ((MEM_iterator) 0)
# define MEM_NULL_dumper    ((MEM_dumper) 0)
# define MEM_NULL_excavator ((MEM_excavator) 0)
# define MEM_NULL_revisor   ((MEM_revisor) 0)
# define MEM_NULL_task      ((MEM_task) 0)

/*
 * In order to generate portable memory dumps, we use four different
 * descriptions for each type:
 *   1. the NORMAL type description
 *   2. a descriptor that says: objects has been MARKED
 *   3. a descriptor that says: objects has been marked AGAIN
 *   4.                       : multiply marked objects has been WRITTEN out
 */
typedef enum MEM_kind {
  MEM_NORMAL,
  MEM_MARKED,
  MEM_AGAIN,
  MEM_WRITTEN
} MEM_kind;

typedef struct MEM_description {
  MEM_kind kind;
  int identifier;		/* leading character in dump */
  MEM_cnt size;			/* if zero, see ``measure'' */
  MEM_measure measure;		/* NULL: non-heap object */
  MEM_iterator iterator;	/* how to show a ``visitor'' around ... */
  MEM_dumper dumper;		/* save all non-subs */
  MEM_excavator excavator;	/* inverse(dumper) */
  MEM_revisor revisor;		/* clean up after the visitor */
  MEM_task init;		/* called by init_all_modules() */
  MEM_task before_gc;		/* called before every gc */
  MEM_task after_gc;		/* called after every gc */
  struct MEM_description **vector;
  MEM_extension extension;
} MEM_description, *MEM_descriptor;

/* register address of a root object: */
extern void MEM_root (void *location, MEM_iterator iterator);
/* frequent special case: a root pointer */
# define MEM_root_var(var) MEM_root (&(var), MEM_NULL_iterator)

/*
 * Three things private to the storage module (visible to facilitate inlining):
 */
extern MEM_align_t *MEM_free;
extern MEM_align_t *MEM_ceiling;
extern void *MEM_getmem (MEM_cnt size);

# define MEM_TYPE(obj) (*(MEM_descriptor *)(obj))
# define ScmTypeOf(obj) MEM_TYPE(obj)

/*
 * Inlined storage allocation
 */
# define MEM_ALLOC(v,s) \
  ((v) = (void *) MEM_free, \
   (MEM_free += (s)) <= MEM_ceiling ? (void) 0 : (void) ((v) = MEM_getmem (s)))

# define MEM_NEW(v,t,s) (MEM_ALLOC (v, s), MEM_TYPE (v) = (t))

# define MEM_VECTOR(n,s,m,it,d,e,r,i,b,a,ext) \
  static MEM_description *MEM_ ## n ## _vector [4]; \
  MEM_description MEM_ ## n ## _1 = \
    { MEM_NORMAL,  n ## _IDENTIFIER, s, m, it, d, e, r, i, b, a, \
	MEM_ ## n ## _vector, ext }; \
  static MEM_description MEM_ ## n ## _2 = \
    { MEM_MARKED,  n ## _IDENTIFIER, s, m, it, d, e, r, i, b, a, \
	MEM_ ## n ## _vector, ext }; \
  static MEM_description MEM_ ## n ## _3 = \
    { MEM_AGAIN,   n ## _IDENTIFIER, s, m, it, d, e, r, i, b, a, \
	MEM_ ## n ## _vector, ext }; \
  static MEM_description MEM_ ## n ## _4 = \
    { MEM_WRITTEN, n ## _IDENTIFIER, s, m, it, d, e, r, i, b, a, \
	MEM_ ## n ## _vector, ext }; \
  static MEM_description * MEM_ ## n ## _vector [4] = \
    { &MEM_ ## n ## _1, &MEM_ ## n ## _2, &MEM_ ## n ## _3, &MEM_ ## n ## _4 }

# define DCL_MEM_TYPE(name) extern MEM_description MEM_ ## name ## _1

extern MEM_descriptor MEM_identifier_map [];
extern unsigned const MEM_identifier_map_length;

extern void MEM_init_all_modules (void);

/* prefix_string will be written as the first line of a dump file.  */
/* It cannot contain '\n', but can otherwise be chosen arbitrarily. */
extern void MEM_dump_storage (FILE *file, const char *prefix_string);
extern void MEM_restore_storage (FILE *file);

/* where is the object now? */
extern void *MEM_new_location_of (void *);

/* The current setting of the ``minimum heap size'' */
extern MEM_cnt MEM_min_heap_size;

/*
 * This function is called after every run of the garbage collector...
 * (The function must be supplied by the client of the storage module.)
 * The arguments are:
 *   n: total number of live objects on the heap
 *   t: total heap size
 *   u: size of used part of the heap
 *   c: time spent in this run of the collector
 */
extern void MEM_gc_statistics (MEM_cnt n, MEM_cnt t, MEM_cnt u, clock_t c);

/*
 * The following two procedures, which must be implemented by the
 * client of this storage module, will be called in order to announce
 * the start and end of a GC-run.  They must be present, but they are not
 * required to do anything.
 * One common use (as shown in the VSCM-Imlementation) is to supress
 * instant interrupt handling during garbage collection.
 */
extern void MEM_announce_gc_start (void);
extern void MEM_announce_gc_end (void);

/* query total time spent in the GC so far */
extern clock_t MEM_total_gc_clock (void);

/* two efficient routines to read and write unsigned long */
extern void MEM_dump_ul (unsigned long l, FILE *file);
extern unsigned long MEM_restore_ul (FILE *file);

# endif