core: Pointer cells: Allow smaller memory footprint using cellcpy.

* src/gc.c (gc_init)[GC_NOFLIP]: Do not use double sized arena.
(gc_cellcpy): New function.
* src/gc.c (gc_flip): Use it, do not flip.
(gc_init_news)[GC_NOFLIP]: Update.
This commit is contained in:
Jan (janneke) Nieuwenhuizen 2020-09-13 18:20:52 +02:00
parent 543419134f
commit 3de592d441
No known key found for this signature in database
GPG key ID: F3C1A0D9C1D65273

139
src/gc.c
View file

@ -104,15 +104,16 @@ gc_init ()
MAX_STRING = atoi (p); MAX_STRING = atoi (p);
long arena_bytes = (ARENA_SIZE + JAM_SIZE) * sizeof (struct scm); long arena_bytes = (ARENA_SIZE + JAM_SIZE) * sizeof (struct scm);
#if !POINTER_CELLS #if !POINTER_CELLS || GC_NOFLIP
long alloc_bytes = arena_bytes + (STACK_SIZE * sizeof (SCM)); long alloc_bytes = arena_bytes + (STACK_SIZE * sizeof (struct scm));
#else #else
long alloc_bytes = (arena_bytes * 2) + (STACK_SIZE * sizeof (struct scm*)); long alloc_bytes = (arena_bytes * 2) + (STACK_SIZE * sizeof (struct scm*));
#endif #endif
g_arena = malloc (alloc_bytes); g_arena = malloc (alloc_bytes);
g_cells = g_arena; g_cells = g_arena;
#if !POINTER_CELLS #if !POINTER_CELLS || GC_NOFLIP
g_stack_array = g_arena + arena_bytes; g_stack_array = g_arena + arena_bytes;
#else #else
g_stack_array = g_arena + (arena_bytes * 2); g_stack_array = g_arena + (arena_bytes * 2);
@ -324,11 +325,16 @@ gc_init_news ()
g_news = g_cells + g_free; g_news = g_cells + g_free;
SCM ncell_arena = cell_arena; SCM ncell_arena = cell_arena;
#else #else
#if GC_NOFLIP
g_news = g_free;
#else
char* p = g_cells - M2_CELL_SIZE; char* p = g_cells - M2_CELL_SIZE;
if (p == g_arena) if (p == g_arena)
g_news = g_free; g_news = g_free;
else else
g_news = g_arena; g_news = g_arena;
#endif
SCM ncell_arena = g_news; SCM ncell_arena = g_news;
#endif #endif
@ -392,14 +398,126 @@ gc_up_arena ()
g_cells = g_cells + M2_CELL_SIZE; g_cells = g_cells + M2_CELL_SIZE;
} }
/* A pointer relocating memcpy for pointer cells to avoid using only
half of the allocated cells.
For number based cells a simply memcpy could be used, as number
references are relative.
A simple stop and copy (SICP 5.3) garbage collector allocates twice
the cell arena size only for the garbage collector. The garbage
collector switches back and forth between cells and news, thus
utilizing only half the allocated memory. */
void
gc_cellcpy (struct scm *dest, struct scm *src, size_t n)
{
void *p = src;
void *q = dest;
long dist = p - q;
while (n != 0)
{
long t = src->type;
long a = src->car;
long d = src->cdr;
dest->type = t;
if (t == TBROKEN_HEART)
{
dest->type = 0;
a = 0;
d = 0;
#if 0
assert_msg (0, "gc_cellcpy: broken heart");
#endif
}
if (t == TMACRO
|| t == TPAIR
|| t == TREF
|| t == TVARIABLE)
dest->car = a - dist;
else
dest->car = a;
if (t == TBYTES
|| t == TCLOSURE
|| t == TCONTINUATION
|| t == TKEYWORD
|| t == TMACRO
|| t == TPAIR
|| t == TPORT
|| t == TSPECIAL
|| t == TSTRING
|| t == TSTRUCT
|| t == TSYMBOL
|| t == TVALUES
|| t == TVECTOR)
dest->cdr = d - dist;
else
dest->cdr = d;
if (t == TBYTES)
{
if (g_debug > 5)
{
eputs ("copying bytes[");
eputs (ntoab (cell_bytes (src), 16, 0));
eputs (", ");
eputs (ntoab (a, 10, 0));
eputs ("]: ");
eputs (cell_bytes (src));
eputs ("\n to [");
eputs (ntoab (cell_bytes (dest), 16, 0));
}
memcpy (cell_bytes (dest), cell_bytes (src), a);
if (g_debug > 5)
{
eputs ("]: ");
eputs (cell_bytes (dest));
eputs ("\n");
}
int i = bytes_cells (a);
n = n - i;
int c = i * M2_CELL_SIZE;
dest = dest + c;
src = src + c;
}
else
{
n = n - 1;
dest = dest + M2_CELL_SIZE;
src = src + M2_CELL_SIZE;
}
}
}
/* We do not actually flip cells and news, instead we move news back to
cells. */
void void
gc_flip () gc_flip ()
{ {
#if POINTER_CELLS #if POINTER_CELLS
if (g_free - g_news > JAM_SIZE)
JAM_SIZE = (g_free - g_news) + ((g_free - g_news) / 2);
#if GC_NOFLIP
cell_arena = g_cells - M2_CELL_SIZE; /* FIXME? */
gc_cellcpy (g_cells, g_news, (g_free - g_news) / M2_CELL_SIZE);
long dist = g_news - g_cells;
g_free = g_free - dist;
g_symbols = g_symbols - dist;
g_macros = g_macros - dist;
g_ports = g_ports - dist;
M0 = M0 - dist;
long i;
for (i = g_stack; i < STACK_SIZE; i = i + 1)
g_stack_array[i] = g_stack_array[i] - dist;
#else
g_cells = g_news; g_cells = g_news;
cell_arena = g_news - M2_CELL_SIZE; cell_arena = g_news - M2_CELL_SIZE;
cell_zero = cell_arena + M2_CELL_SIZE; cell_zero = cell_arena + M2_CELL_SIZE;
cell_nil = cell_zero + M2_CELL_SIZE; cell_nil = cell_zero + M2_CELL_SIZE;
#endif
#endif #endif
if (g_debug > 2) if (g_debug > 2)
@ -485,7 +603,14 @@ gc_loop (SCM scan)
{ {
long t = NTYPE (scan); long t = NTYPE (scan);
if (t == TBROKEN_HEART) if (t == TBROKEN_HEART)
assert_msg (0, "broken heart"); {
NTYPE (scan) = 0;
NCAR (scan) = 0;
NCDR (scan) = 0;
#if 0
assert_msg (0, "gc_loop: broken heart");
#endif
}
/* *INDENT-OFF* */ /* *INDENT-OFF* */
if (t == TMACRO if (t == TMACRO
|| t == TPAIR || t == TPAIR
@ -579,8 +704,9 @@ gc_ ()
for (s = cell_nil; s < g_symbol_max; s = s + M2_CELL_SIZE) for (s = cell_nil; s < g_symbol_max; s = s + M2_CELL_SIZE)
gc_copy (s); gc_copy (s);
#if POINTER_CELLS #if POINTER_CELLS && !GC_NOFLIP
cell_nil = new_cell_nil; cell_nil = new_cell_nil;
cell_arena = g_news - M2_CELL_SIZE; /* for debugging */
#if GC_TEST #if GC_TEST
cell_zero = cell_nil - M2_CELL_SIZE; cell_zero = cell_nil - M2_CELL_SIZE;
@ -596,13 +722,16 @@ gc_ ()
#endif #endif
#if !GC_TEST
g_symbols = gc_copy (g_symbols); g_symbols = gc_copy (g_symbols);
g_macros = gc_copy (g_macros); g_macros = gc_copy (g_macros);
g_ports = gc_copy (g_ports); g_ports = gc_copy (g_ports);
M0 = gc_copy (M0); M0 = gc_copy (M0);
long i; long i;
for (i = g_stack; i < STACK_SIZE; i = i + 1) for (i = g_stack; i < STACK_SIZE; i = i + 1)
copy_stack (i, gc_copy (g_stack_array[i])); copy_stack (i, gc_copy (g_stack_array[i]));
#endif
gc_loop (new_cell_nil); gc_loop (new_cell_nil);
} }