/* libsizzle/gc.h - memory management

  Copyright (C) 1999, 2000 Martin Grabmueller <mgrabmue@cs.tu-berlin.de>

  This is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2, or (at your option)
  any later version.

  This software is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this package; see the file COPYING.  If not, write to the
  Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  MA 02111-1307, USA.  */

#ifndef __SIZZLE_GC_H__
#define __SIZZLE_GC_H__

#if HAVE_CONFIG_H
# include <config.h>
#endif

#if __SIZZLE_IMPORT__
# define SIZZLE_API __declspec (dllimport)
#elif __SIZZLE_EXPORT__ 
# define SIZZLE_API __declspec (dllexport)
#else
# define SIZZLE_API
#endif

#include "result.h"

/* These data types are needed to perform casts from pointers into the
   heap to integer values.  The first is needed when manipulating
   fixnums, because the sign bit must be preserved, and the second for
   other objects, where only bit-twiddling on the pointer value is
   required.  */
typedef signed long zzz_signed_object_t;
typedef unsigned long zzz_object_t;

/* Cons cell data type. ------------------------------------------- */

/* The heap for holding cons cells is made from this objects of this
   structure type.  */
typedef struct zzz_scm * zzz_scm_t;
struct zzz_scm
{
  zzz_scm_t ccar;
  zzz_scm_t ccdr;
};

/* Tagged cell data type. ----------------------------------------- */

/* This type represents tagged cells.  The fields in fill[] are cast
   to the correct type whenever needed.  The first field in fill
   normally holds the tag type and tag info, the other fields are data
   slots and their usage depends on the definition of the tagged type.  */
typedef struct zzz_tagged * zzz_tagged_t;
struct zzz_tagged
{
  zzz_object_t fill[4];
};

/* This variable is true during shutdown.  */
SIZZLE_API extern int zzz_terminating;

/* Garbage collection issues. ------------------------------------- */

/* Points to the location where conservative C stack scanning stops.
   Must be set before using the garbage collector.  */
SIZZLE_API extern zzz_scm_t * zzz_top_of_c_stack;

/* PORTABILITY-NOTE: This may be necessary for platforms other than
   SPARC, but I can neither test it nor do I know much about other
   platforms. PowerPC, MIPS, anyone???. */

/* The following is needed on SPARC to make sure that all variables
   are on the stack when conservative marking is done.  That is the
   only way to make sure that all object roots are found and can be
   protected from being garbage collected.  */
#ifdef sparc
# define FLUSH_REGISTER_WINDOWS() asm ("ta 3")
#else
# define FLUSH_REGISTER_WINDOWS() /* nop */
#endif

/* Cell creation functions. --------------------------------------- */

/* Return a uninitialized pair.  */
SIZZLE_API zzz_scm_t zzz_alloc_cons_cell (void);

/* Creates a cons cell with car and cdr initialized to the values of
   @var{car} and @var{cdr}, respectively.  */
SIZZLE_API zzz_scm_t zzz_cons (zzz_scm_t car, zzz_scm_t cdr);

/* Allocate a tagged cell with tag TAG and data pointers @var{data0},
   @var{data1} and @var{data2}.  The constructor function for type
   @var{tag} is called to initialize the data slot of the cell.  */
SIZZLE_API zzz_scm_t zzz_create_tagged_cell (zzz_object_t tag, void * data0,
					    void * data1, void * data2);

/* Set the pointer @var{cell} to be the last (largest) location in the
   runtime stack.  This will be the highest address to be scanned for
   pointers to Scheme objects when garbage collecting.  The value
   passed to this function should normally be the address of a local
   variable or parameter which is guaranteed to be larger than any
   stack location where a variable of type @code{zzz_scm_t} is stored.  */
SIZZLE_API void zzz_set_top_of_stack (zzz_scm_t * cell);

/* Use this functions from the @dfn{marking function} of your tagged
   type if you have to mark a variable of type @code{zzz_scm_t}.  */
SIZZLE_API void zzz_mark_cell (zzz_scm_t cell);

/* Mark all pointers of types @code{zzz_scm_t} between @var{start}
   (inclusive) and @var{end} (exclusive).  */
SIZZLE_API void zzz_mark_area (zzz_scm_t * start, zzz_scm_t * end);

/* Invoke the garbage collection.  Normally the user does not need to
   do it since the library calls this function whenever necessary. */
SIZZLE_API void zzz_garbage_collect (void);

/* Block the garbage collection until @code{zzz_gc_unlock()} is
   called.  Calls to @code{zzz_gc_lock()} may be nested, but calls to
   @code{zzz_gc_lock()} and {zzz_gc_unlock()} must be nested properly,
   or garbage collection will remain locked forever.  */
SIZZLE_API void zzz_gc_lock (void);

/* Unlock the garbage collection.  If a garbage collection was
   requested during locking time, it will called now, but only if no
   other locks are held.  */
SIZZLE_API void zzz_gc_unlock (void);

/* Protect the variable pointed to by @var{scm} globally from being
   gc'ed.  */
SIZZLE_API result_t zzz_protect_global (zzz_scm_t * scm);

/* Define all Scheme variables for controlling the garbage collector
   from the Scheme level.  */
SIZZLE_API void zzz_init_gc_variables (void);

/* Initialize the garbage collector.  */
SIZZLE_API void zzz_init_gc (void);

/* Free all memory used by the garbage collector.  */
SIZZLE_API void zzz_finalize_gc (void);

#endif /* not __SIZZLE_GC_H__ */
