diff --git a/gc.c b/gc.c index b5c5b2c3..c2933930 100644 --- a/gc.c +++ b/gc.c @@ -4,10 +4,26 @@ #include "chibi/sexp.h" +/* These settings are configurable but only recommended for */ +/* experienced users, so they're not in config.h. */ + +/* the initial heap size in bytes */ +#ifndef SEXP_INITIAL_HEAP_SIZE #define SEXP_INITIAL_HEAP_SIZE (2*1024*1024) -#define SEXP_MAXIMUM_HEAP_SIZE 0 +#endif + +/* the maximum heap size in bytes - if 0 there is no limit */ +#ifndef SEXP_MAXIMUM_HEAP_SIZE +#define SEXP_MAXIMUM_HEAP_SIZE (4*1024*1024) +#endif + +/* if after GC more than this percentage of memory is still in use, */ +/* and we've not exceeded the maximum size, grow the heap */ +#ifndef SEXP_GROW_HEAP_RATIO +#define SEXP_GROW_HEAP_RATIO 0.75 +#endif + #define SEXP_MINIMUM_OBJECT_SIZE (sexp_sizeof(pair)) -#define SEXP_GROW_HEAP_RATIO 0.7 #if SEXP_64_BIT #define sexp_heap_align(n) sexp_align(n, 5) @@ -206,12 +222,12 @@ void* sexp_alloc (sexp ctx, size_t size) { max_freed = sexp_unbox_fixnum(sexp_gc(ctx, &sum_freed)); h = sexp_heap_last(sexp_context_heap(ctx)); if (((max_freed < size) - || ((h->size - sum_freed) < (h->size*(1 - SEXP_GROW_HEAP_RATIO)))) + || ((h->size - sum_freed) > (h->size*SEXP_GROW_HEAP_RATIO))) && ((! SEXP_MAXIMUM_HEAP_SIZE) || (size < SEXP_MAXIMUM_HEAP_SIZE))) sexp_grow_heap(ctx, size); res = sexp_try_alloc(ctx, size); if (! res) - errx(80, "out of memory allocating %zu bytes, aborting\n", size); + res = sexp_global(ctx, SEXP_G_OOM_ERROR); } return res; } diff --git a/include/chibi/sexp.h b/include/chibi/sexp.h index 575eeaad..03b044a0 100644 --- a/include/chibi/sexp.h +++ b/include/chibi/sexp.h @@ -668,6 +668,7 @@ enum sexp_context_globals { #if ! USE_GLOBAL_SYMBOLS SEXP_G_SYMBOLS, #endif + SEXP_G_OOM_ERROR, SEXP_G_QUOTE_SYMBOL, SEXP_G_QUASIQUOTE_SYMBOL, SEXP_G_UNQUOTE_SYMBOL, diff --git a/sexp.c b/sexp.c index 47b7fb2c..9ee6037a 100644 --- a/sexp.c +++ b/sexp.c @@ -49,7 +49,7 @@ sexp sexp_symbol_table[SEXP_SYMBOL_TABLE_SIZE]; sexp sexp_alloc_tagged(sexp ctx, size_t size, sexp_uint_t tag) { sexp res = (sexp) sexp_alloc(ctx, size); - if (res) sexp_pointer_tag(res) = tag; + if (res && ! sexp_exceptionp(res)) sexp_pointer_tag(res) = tag; return res; } @@ -187,6 +187,7 @@ void sexp_init_context_globals (sexp ctx) { #if ! USE_GLOBAL_SYMBOLS sexp_global(ctx, SEXP_G_SYMBOLS) = sexp_make_vector(ctx, sexp_make_fixnum(SEXP_SYMBOL_TABLE_SIZE), SEXP_NULL); #endif + sexp_global(ctx, SEXP_G_OOM_ERROR) = sexp_user_exception(ctx, SEXP_FALSE, "out of memory", SEXP_NULL); sexp_global(ctx, SEXP_G_QUOTE_SYMBOL) = sexp_intern(ctx, "quote"); sexp_global(ctx, SEXP_G_QUASIQUOTE_SYMBOL) = sexp_intern(ctx, "quasiquote"); sexp_global(ctx, SEXP_G_UNQUOTE_SYMBOL) = sexp_intern(ctx, "unquote"); @@ -211,6 +212,7 @@ sexp sexp_bootstrap_context (void) { ctx = sexp_alloc_type(dummy_ctx, context, SEXP_CONTEXT); sexp_context_heap(dummy_ctx) = NULL; sexp_context_heap(ctx) = heap; + free(dummy_ctx); return ctx; } #endif @@ -385,6 +387,7 @@ static sexp sexp_read_error (sexp ctx, char *msg, sexp irritants, sexp port) { sexp sexp_cons (sexp ctx, sexp head, sexp tail) { sexp pair = sexp_alloc_type(ctx, pair, SEXP_PAIR); + if (sexp_exceptionp(pair)) return pair; sexp_car(pair) = head; sexp_cdr(pair) = tail; sexp_pair_source(pair) = SEXP_FALSE; @@ -559,6 +562,7 @@ sexp sexp_equalp (sexp ctx, sexp a, sexp b) { #if ! USE_IMMEDIATE_FLONUMS sexp sexp_make_flonum(sexp ctx, double f) { sexp x = sexp_alloc_type(ctx, flonum, SEXP_FLONUM); + if (sexp_exceptionp(x)) return x; sexp_flonum_value(x) = f; return x; } @@ -570,6 +574,7 @@ sexp sexp_make_string(sexp ctx, sexp len, sexp ch) { if (! sexp_fixnump(len)) return sexp_type_exception(ctx, "bad length", len); if (clen < 0) return sexp_type_exception(ctx, "negative length", len); s = sexp_alloc_atomic(ctx, sexp_sizeof(string)+clen+1); + if (sexp_exceptionp(s)) return s; sexp_pointer_tag(s) = SEXP_STRING; sexp_string_length(s) = clen; if (sexp_charp(ch)) @@ -677,6 +682,7 @@ sexp sexp_intern(sexp ctx, char *str) { /* not found, make a new symbol */ sexp_gc_preserve1(ctx, sym); sym = sexp_alloc_type(ctx, symbol, SEXP_SYMBOL); + if (sexp_exceptionp(sym)) return sym; sexp_symbol_string(sym) = sexp_c_string(ctx, str, len); sexp_push(ctx, sexp_context_symbols(ctx)[bucket], sym); sexp_gc_release1(ctx); @@ -690,22 +696,25 @@ sexp sexp_string_to_symbol (sexp ctx, sexp str) { } sexp sexp_make_vector(sexp ctx, sexp len, sexp dflt) { - sexp v, *x; + sexp vec, *x; int i, clen = sexp_unbox_fixnum(len); if (! clen) return sexp_global(ctx, SEXP_G_EMPTY_VECTOR); - v = sexp_alloc_tagged(ctx, sexp_sizeof(vector) + clen*sizeof(sexp), - SEXP_VECTOR); - x = sexp_vector_data(v); + vec = sexp_alloc_tagged(ctx, sexp_sizeof(vector) + clen*sizeof(sexp), + SEXP_VECTOR); + if (sexp_exceptionp(vec)) return vec; + x = sexp_vector_data(vec); for (i=0; i