diff --git a/README.md b/README.md index 2b175b1..412aaf3 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ It is fully self-contained and doesn't rely on a working standard library beyond - `free` - `putchar` +These functions need to be wrapped, the wrapper allows to make them stateful to keep individual heaps per context, +allowing to clean the context by cleaning up its allocations. + To make the library not use the standard library, build it with `NOSTDLIB` defined as a preprocessor directive. All of these functions need to work for `ink` to work. It is easy to add new functions to the interpreter. I added a diff --git a/include/ink.h b/include/ink.h index ede8912..2a17929 100644 --- a/include/ink.h +++ b/include/ink.h @@ -138,14 +138,14 @@ struct ink_type { struct context { int panic; - void *(*inner_malloc)(size_t); - void *(*inner_realloc)(void *, size_t); - void (*inner_free)(void *); - - void *(*malloc)(size_t); - void *(*realloc)(void *, size_t); - void (*free)(void *); - int (*putchar)(int); + void *(*inner_malloc)(struct context*,size_t); + void *(*inner_realloc)(struct context*,void *, size_t); + void (*inner_free)(struct context*,void *); + + void *(*malloc)(struct context*,size_t); + void *(*realloc)(struct context*,void *, size_t); + void (*free)(struct context*,void *); + int (*putchar)(struct context*,int); struct ink_routine *routines; int routines_capacity; @@ -230,7 +230,18 @@ int ink_push_fn(struct context *ctx, struct stack_frame value); * @param putchar a function to print to the output character by character * @return a pointer to a context allocated within the malloc function itself. */ -struct context* ink_make_context(void *(*malloc)(size_t), void *(*realloc)(void *, size_t), void(*free)(void *), int(*putchar)(int)); +struct context* ink_make_context(void*(*malloc)(struct context*, size_t), void*(*realloc)(struct context*, void*, size_t), void(*free)(struct context*, void*), int(*putchar)(struct context*, int)); + +/** + * Create a context to execute routines in-place + * @param location a pointer to where the context should be built, userdata can be set in advance + * @param malloc the memory allocation function, with a signature similar to the standard malloc + * @param realloc the memory allocation function, with a signature similar to the standard realloc + * @param free the memory allocation function, with a signature similar to the standard free + * @param putchar a function to print to the output character by character + * @return a pointer to a context allocated within the malloc function itself. + */ +void ink_make_context_inplace(struct context* location, void*(*malloc)(struct context*, size_t), void*(*realloc)(struct context*, void*, size_t), void(*free)(struct context*, void*), int(*putchar)(struct context*, int)); #ifndef NOSTDLIB /** diff --git a/lib.c b/lib.c index 7008b69..cb7e14d 100644 --- a/lib.c +++ b/lib.c @@ -116,14 +116,14 @@ int ink_add_native(struct context* ctx, const char* name, void(*value)(struct co int len; char* copy; if(ctx->native_words == NULL) { - ctx->native_words = ctx->inner_malloc(sizeof(struct native_fn) * 8); + ctx->native_words = ctx->inner_malloc(ctx, sizeof(struct native_fn) * 8); ctx->native_words_top = 0; ctx->native_words_capacity = 8; } else if(ctx->native_words_top == ctx->native_words_capacity) { int new_count; void* renewed; new_count = (ctx->native_words_capacity + ctx->native_words_capacity/2); - renewed = ctx->inner_realloc(ctx->native_words, sizeof(struct native_fn) * new_count); + renewed = ctx->inner_realloc(ctx, ctx->native_words, sizeof(struct native_fn) * new_count); if(renewed == NULL) { return -3; } else { @@ -132,7 +132,7 @@ int ink_add_native(struct context* ctx, const char* name, void(*value)(struct co } } len = strlen(name); - copy = ctx->inner_malloc(len+1); + copy = ctx->inner_malloc(ctx, len+1); if(copy == NULL) { return -4; } @@ -149,14 +149,14 @@ static int ink_add_indigenous(struct context* ctx, const char* name, struct elem char* copy; if(ctx->words == NULL) { - ctx->words = ctx->malloc(sizeof(struct fn) * 8); + ctx->words = ctx->malloc(ctx, sizeof(struct fn) * 8); ctx->words_top = 0; ctx->words_capacity = 8; } else if(ctx->words_top == ctx->words_capacity) { int new_count; void* renewed; new_count = (ctx->words_capacity + ctx->words_capacity/2); - renewed = ctx->realloc(ctx->words, sizeof(struct fn) * new_count); + renewed = ctx->realloc(ctx, ctx->words, sizeof(struct fn) * new_count); if(renewed == NULL) { return -1; } else { @@ -166,21 +166,21 @@ static int ink_add_indigenous(struct context* ctx, const char* name, struct elem } for(i = 0; i < ctx->words_top; ++i) { if(strcmp(name, ctx->words[i].name) == 0) { - ctx->free(ctx->words[i].things); - ctx->words[i].things = ctx->malloc(sizeof(struct elem) * count); + ctx->free(ctx, ctx->words[i].things); + ctx->words[i].things = ctx->malloc(ctx, sizeof(struct elem) * count); memcpy(ctx->words[i].things, m, sizeof(struct elem) * count); ctx->words[i].size = count; return i; } } len = strlen(name); - copy = ctx->malloc(len+1); + copy = ctx->malloc(ctx, len+1); if(copy == NULL) { return -2; } memcpy(copy, name, len); copy[len] = 0; - ctx->words[ctx->words_top].things = ctx->malloc(sizeof(struct elem) * count); + ctx->words[ctx->words_top].things = ctx->malloc(ctx, sizeof(struct elem) * count); memcpy(ctx->words[ctx->words_top].things, m, sizeof(struct elem) * count); ctx->words[ctx->words_top].size = count; ctx->words[ctx->words_top].name = copy; @@ -198,14 +198,14 @@ static int ink_add_lex_string(struct context* ctx, const char* name) { int i; int len; if(ctx->lex_reserved_words == NULL) { - ctx->lex_reserved_words = ctx->inner_malloc(sizeof(char*) * 8); + ctx->lex_reserved_words = ctx->inner_malloc(ctx, sizeof(char*) * 8); ctx->lex_reserved_words_top = 0; ctx->lex_reserved_words_capacity = 8; } else if(ctx->lex_reserved_words_top == ctx->lex_reserved_words_capacity) { int new_count; void* renewed; new_count = (ctx->lex_reserved_words_capacity + ctx->lex_reserved_words_capacity/2); - renewed = ctx->inner_realloc(ctx->lex_reserved_words, sizeof(struct native_fn) * new_count); + renewed = ctx->inner_realloc(ctx, ctx->lex_reserved_words, sizeof(struct native_fn) * new_count); if(renewed == NULL) { return -5; } else { @@ -220,7 +220,7 @@ static int ink_add_lex_string(struct context* ctx, const char* name) { } len = strlen(name); i = ctx->lex_reserved_words_top; - ctx->lex_reserved_words[i] = ctx->malloc(len+1); + ctx->lex_reserved_words[i] = ctx->malloc(ctx, len+1); memcpy(ctx->lex_reserved_words[i], name, len); ctx->lex_reserved_words[i][len] = 0; ctx->lex_reserved_words_top++; @@ -232,14 +232,14 @@ int ink_push(struct context* ctx, struct elem value) { if(ctx->routine_current >= ctx->routines_top) return -65; current = ctx->routines + ctx->routine_current; if(current->stack == NULL) { - current->stack = ctx->malloc(sizeof(struct elem) * 8); + current->stack = ctx->malloc(ctx, sizeof(struct elem) * 8); current->top = 0; current->capacity = 8; } else if(current->top == current->capacity) { int new_count; void* renewed; new_count = (current->capacity + current->capacity/2); - renewed = ctx->realloc(current->stack, sizeof(struct elem) * new_count); + renewed = ctx->realloc(ctx, current->stack, sizeof(struct elem) * new_count); if(renewed == NULL) { return -18; } else { @@ -259,14 +259,14 @@ int ink_push_fn(struct context* ctx, struct stack_frame value) { current = ctx->routines + ctx->routine_current; if(current->panic) return -56; if(current->function_stack == NULL) { - current->function_stack = ctx->malloc(sizeof(struct stack_frame) * 8); + current->function_stack = ctx->malloc(ctx, sizeof(struct stack_frame) * 8); current->function_stack_top = 0; current->function_stack_capacity = 8; } else if(current->function_stack_top == current->function_stack_capacity) { int new_count; void* renewed; new_count = (current->function_stack_capacity + current->function_stack_capacity/2); - renewed = ctx->realloc(current->function_stack, sizeof(struct stack_frame) * new_count); + renewed = ctx->realloc(ctx, current->function_stack, sizeof(struct stack_frame) * new_count); if(renewed == NULL) { return -9; } else { @@ -295,23 +295,23 @@ void ink_pop(struct context* ctx) { ctx->routines[ctx->routine_current].top--; } -struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, size_t), void(*free)(void*), int(*putchar)(int)) { +struct context* ink_make_context(void*(*malloc)(struct context*, size_t), void*(*realloc)(struct context*, void*, size_t), void(*free)(struct context*, void*), int(*putchar)(struct context*, int)) { struct context* ctx; - ctx = (struct context*)malloc(sizeof(struct context)); - ctx->malloc = malloc; - ctx->realloc = realloc; - ctx->free = free; - ctx->inner_malloc = malloc; - ctx->inner_realloc = realloc; - ctx->inner_free = free; - ctx->putchar = putchar; + ctx = (struct context*)malloc(NULL, sizeof(struct context)); + ctx->malloc = malloc; + ctx->realloc = realloc; + ctx->free = free; + ctx->inner_malloc = malloc; + ctx->inner_realloc = realloc; + ctx->inner_free = free; + ctx->putchar = putchar; ctx->panic = 0; ctx->routines = NULL; ctx->routines_capacity = 0; ctx->routines_top = 0; - ctx->types = NULL; - ctx->types_capacity = 0; - ctx->types_top = 0; + ctx->types = NULL; + ctx->types_capacity = 0; + ctx->types_top = 0; ctx->native_words = NULL; ctx->native_words_capacity = 0; ctx->native_words_top = 0; @@ -321,11 +321,40 @@ struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, ctx->lex_reserved_words = NULL; ctx->lex_reserved_words_capacity = 0; ctx->lex_reserved_words_top = 0; - ctx->collections = 0; - ctx->steps = 0; + ctx->collections = 0; + ctx->steps = 0; return ctx; } +void ink_make_context_inplace(struct context* location, void*(*malloc)(struct context*, size_t), void*(*realloc)(struct context*, void*, size_t), void(*free)(struct context*, void*), int(*putchar)(struct context*, int)) { + struct context* ctx = location; + ctx->malloc = malloc; + ctx->realloc = realloc; + ctx->free = free; + ctx->inner_malloc = malloc; + ctx->inner_realloc = realloc; + ctx->inner_free = free; + ctx->putchar = putchar; + ctx->panic = 0; + ctx->routines = NULL; + ctx->routines_capacity = 0; + ctx->routines_top = 0; + ctx->types = NULL; + ctx->types_capacity = 0; + ctx->types_top = 0; + ctx->native_words = NULL; + ctx->native_words_capacity = 0; + ctx->native_words_top = 0; + ctx->words = NULL; + ctx->words_capacity = 0; + ctx->words_top = 0; + ctx->lex_reserved_words = NULL; + ctx->lex_reserved_words_capacity = 0; + ctx->lex_reserved_words_top = 0; + ctx->collections = 0; + ctx->steps = 0; +} + /** * Allocates a string that contains the integer * @param _ context (used to allocate) @@ -336,7 +365,7 @@ struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, static char* ink_itoa(struct context* _, int cpy) { char* n; char* it; - n = _->malloc(16); + n = _->malloc(_, 16); n[15] = 0; it = n+15; do { @@ -349,9 +378,26 @@ static char* ink_itoa(struct context* _, int cpy) { } #ifndef NOSTDLIB +static void* ink_malloc(struct context* _, size_t sz) { + _=_; + return malloc(sz); +} +static void* ink_realloc(struct context* _, void* ptr, size_t sz) { + _=_; + return realloc(ptr, sz); +} +static void ink_free(struct context* _, void* ptr) { + _=_; + free(ptr); +} +static int ink_putchar(struct context* _, int c) { + _=_; + return putchar(c); +} + struct context* ink_make_default_context(void) { struct context* ctx; - ctx = ink_make_context(malloc, realloc, free, putchar); + ctx = ink_make_context(ink_malloc, ink_realloc, ink_free, ink_putchar); ink_std_library(ctx); return ctx; } @@ -584,7 +630,7 @@ int ink_make_routine(struct context* ctx) { /* Allocate space if needed */ if(ctx->routines == NULL) { - ctx->routines = ctx->inner_malloc(sizeof(struct ink_routine) * 8); + ctx->routines = ctx->inner_malloc(ctx, sizeof(struct ink_routine) * 8); ctx->routines_top = 0; ctx->routines_capacity = 8; it = ctx->routines; @@ -600,7 +646,7 @@ int ink_make_routine(struct context* ctx) { int new_count; void* renewed; new_count = (ctx->routines_capacity + ctx->routines_capacity/2); - renewed = ctx->inner_realloc(ctx->routines, sizeof(struct ink_routine) * new_count); + renewed = ctx->inner_realloc(ctx, ctx->routines, sizeof(struct ink_routine) * new_count); if(renewed == NULL) { return -99; } else { @@ -649,11 +695,11 @@ int ink_kill_routine(struct context* ctx, int routine){ return 0; } if(curr->stack != NULL) { - ctx->free(curr->stack); + ctx->free(ctx, curr->stack); curr->stack = NULL; } if(curr->function_stack != NULL) { - ctx->free(curr->function_stack); + ctx->free(ctx, curr->function_stack); curr->function_stack = NULL; } curr->panic = INK_ROUTINE_CAN_REUSE; @@ -932,7 +978,7 @@ int ink_compile(struct context *pContext, const char* buffer) { integer = ink_itoa(pContext, routine); integer_size = strlen(integer); memcpy(main_fn + 10, integer, integer_size); - pContext->free(integer); + pContext->free(pContext, integer); main_fn[10 + integer_size] = 0; frame.executing.value = ink_add_indigenous(pContext, main_fn, executable_buffer, executable_buffer_top); if (frame.executing.value < 0) { @@ -1023,14 +1069,14 @@ int ink_new_type( if(ctx->panic) return -128; /* Resize for push */ if(ctx->types == NULL) { - ctx->types = ctx->inner_malloc(sizeof(struct ink_type) * 8); + ctx->types = ctx->inner_malloc(ctx, sizeof(struct ink_type) * 8); ctx->types_top = 0; ctx->types_capacity = 8; } else if(ctx->types_top == ctx->types_capacity) { int new_count; void* renewed; new_count = (ctx->types_capacity + ctx->types_capacity/2); - renewed = ctx->inner_realloc(ctx->types, sizeof(struct ink_type) * new_count); + renewed = ctx->inner_realloc(ctx, ctx->types, sizeof(struct ink_type) * new_count); if(renewed == NULL) { return -129; } else { @@ -1099,7 +1145,7 @@ struct elem ink_make_native_unsafe(struct context* ctx, int type, void* ptr, int /* Resize for push of value in store */ if(ctx->types[type_id].elements == NULL) { - ctx->types[type_id].elements = ctx->inner_malloc(sizeof(struct element_slab) * 8); + ctx->types[type_id].elements = ctx->inner_malloc(ctx, sizeof(struct element_slab) * 8); ctx->types[type_id].elements_top = 0; ctx->types[type_id].elements_capacity = 8; memset(ctx->types[type_id].elements + ctx->types[type_id].elements_top, 0, sizeof(struct element_slab)*(ctx->types[type_id].elements_capacity - ctx->types[type_id].elements_top)); @@ -1107,7 +1153,7 @@ struct elem ink_make_native_unsafe(struct context* ctx, int type, void* ptr, int int new_count; void* renewed; new_count = (ctx->types[type_id].elements_capacity + ctx->types[type_id].elements_capacity/2); - renewed = ctx->inner_realloc(ctx->types[type_id].elements, sizeof(struct element_slab) * new_count); + renewed = ctx->inner_realloc(ctx, ctx->types[type_id].elements, sizeof(struct element_slab) * new_count); if(renewed == NULL) { ret.type = 0; ret.value = -129; @@ -1129,7 +1175,7 @@ struct elem ink_make_native_unsafe(struct context* ctx, int type, void* ptr, int if(ctx->types[type_id].element_size < 0) { ctx->types[type_id].elements[i].data = ptr; } else { - void* new_ptr = ctx->malloc(ctx->types[type_id].element_size); + void* new_ptr = ctx->malloc(ctx, ctx->types[type_id].element_size); if(new_ptr == NULL) { ret.type = 0; ret.value = -139; @@ -1183,8 +1229,8 @@ void ink_gc(struct context* ctx) { /* Start by marking the roots of the routines, Clear the routines if possible */ for(i = 0; i < ctx->routines_top; ++i) { if(ctx->routines[i].panic == INK_ROUTINE_SUCCESS) { - ctx->free(ctx->routines[i].stack); - ctx->free(ctx->routines[i].function_stack); + ctx->free(ctx, ctx->routines[i].stack); + ctx->free(ctx, ctx->routines[i].function_stack); ctx->routines[i].panic = INK_ROUTINE_CAN_REUSE; } if(ctx->routines[i].panic == INK_ROUTINE_CAN_REUSE) { @@ -1215,7 +1261,7 @@ void ink_gc(struct context* ctx) { marked = 1; } } - if (c.elements != NULL) ctx->inner_free(c.elements); + if (c.elements != NULL) ctx->inner_free(ctx, c.elements); } } } @@ -1228,7 +1274,7 @@ void ink_gc(struct context* ctx) { ctx->collections++; ctx->types[i].collect(ctx, ctx->types[i].elements[j].data); if(ctx->types[i].element_size > 0) { - ctx->free(ctx->types[i].elements[j].data); + ctx->free(ctx, ctx->types[i].elements[j].data); } ctx->types[i].elements[j].data = NULL; ctx->types[i].elements[j].uses = 0; @@ -1253,25 +1299,25 @@ static void print_stacktrace(struct context* _) { case INK_NATIVE_FUNCTION: { n = _->native_words[thing.value].name; while (*n) { - _->putchar(*n); + _->putchar(_, *n); ++n; } - _->putchar(10); + _->putchar(_, 10); break; } case INK_FUNCTION:{ n = _->words[thing.value].name; while (*n) { - _->putchar(*n); + _->putchar(_, *n); ++n; } - _->putchar(':'); + _->putchar(_, ':'); n = ink_itoa(_, currentRoutine->function_stack[i].index); while (*n) { - _->putchar(*n); + _->putchar(_, *n); ++n; } - _->putchar(10); + _->putchar(_, 10); break; } default: @@ -1636,10 +1682,10 @@ static void print_int(struct context* ctx) { n = ink_itoa(ctx, a.value); str = n; while (*str) { - ctx->putchar(*str); + ctx->putchar(ctx, *str); ++str; } - ctx->free(n); + ctx->free(ctx, n); } static void print_as_utf8(struct context* ctx) { @@ -1652,19 +1698,19 @@ static void print_as_utf8(struct context* ctx) { } a = currentRoutine->stack[currentRoutine->top-1]; if(a.value <= 0x7F) { - ctx->putchar(a.value); + ctx->putchar(ctx, a.value); } else if(a.value <= 0x7FF) { - ctx->putchar(((a.value & 0xFC0) >> 6) | 192); - ctx->putchar((a.value & 0x3F) | 128); + ctx->putchar(ctx, ((a.value & 0xFC0) >> 6) | 192); + ctx->putchar(ctx, (a.value & 0x3F) | 128); } else if(a.value <= 0xFFFF) { - ctx->putchar(((a.value & 0x3F000) >> 12) | 224); - ctx->putchar(((a.value & 0xFC0) >> 6) | 128); - ctx->putchar((a.value & 0x3F) | 128); + ctx->putchar(ctx, ((a.value & 0x3F000) >> 12) | 224); + ctx->putchar(ctx, ((a.value & 0xFC0) >> 6) | 128); + ctx->putchar(ctx, (a.value & 0x3F) | 128); } else if(a.value <= 0x10FFFF) { - ctx->putchar(((a.value & 0x3C0000) >> 18) | 240); - ctx->putchar(((a.value & 0x3F000) >> 12) | 128); - ctx->putchar(((a.value & 0xFC0) >> 6) | 128); - ctx->putchar((a.value & 0x3F) | 128); + ctx->putchar(ctx, ((a.value & 0x3C0000) >> 18) | 240); + ctx->putchar(ctx, ((a.value & 0x3F000) >> 12) | 128); + ctx->putchar(ctx, ((a.value & 0xFC0) >> 6) | 128); + ctx->putchar(ctx, (a.value & 0x3F) | 128); } else { ctx->panic = -1; return; @@ -1709,15 +1755,15 @@ static void dump_stack(struct context* ctx) { idx = ink_itoa(ctx,index); type = ink_itoa(ctx, currentRoutine->stack[index].type); value = ink_itoa(ctx,currentRoutine->stack[index].value); - for(it = idx; *it; ++it) ctx->putchar(*it); - ctx->putchar(' ');ctx->putchar('|');ctx->putchar(' '); - for(it = type; *it; ++it) ctx->putchar(*it); - ctx->putchar(' ');ctx->putchar('|');ctx->putchar(' '); - for(it = value; *it; ++it) ctx->putchar(*it); - ctx->putchar('\n'); - ctx->free(value); - ctx->free(type); - ctx->free(idx); + for(it = idx; *it; ++it) ctx->putchar(ctx, *it); + ctx->putchar(ctx, ' ');ctx->putchar(ctx, '|');ctx->putchar(ctx, ' '); + for(it = type; *it; ++it) ctx->putchar(ctx, *it); + ctx->putchar(ctx, ' ');ctx->putchar(ctx, '|');ctx->putchar(ctx, ' '); + for(it = value; *it; ++it) ctx->putchar(ctx, *it); + ctx->putchar(ctx, '\n'); + ctx->free(ctx, value); + ctx->free(ctx, type); + ctx->free(ctx, idx); } return; } @@ -1736,14 +1782,14 @@ static struct ink_collection_list gc_noop() { static void collect_array(struct context* ctx, void* array) { struct ink_array* ary; ary = array; - if(ary->elements != NULL) ctx->free(ary->elements); + if(ary->elements != NULL) ctx->free(ctx, ary->elements); } static struct ink_collection_list gc_array(struct context* ctx, void* array) { struct ink_array* ary; struct ink_collection_list c; ary = array; - c.elements = ctx->inner_malloc(sizeof(struct elem)*ary->top); + c.elements = ctx->inner_malloc(ctx, sizeof(struct elem)*ary->top); c.count = ary->top; memcpy(c.elements, ary->elements, sizeof(struct elem)*ary->top); return c; @@ -1787,14 +1833,14 @@ static void push_array_stack_delim(struct context* ctx) { int array_push_s(struct context* ctx, struct ink_array* ary, struct elem value) { if(ary->elements == NULL) { - ary->elements = ctx->malloc(sizeof(struct elem) * 8); + ary->elements = ctx->malloc(ctx, sizeof(struct elem) * 8); ary->top = 0; ary->capacity = 8; } else if(ary->top == ary->capacity) { int new_count; void* renewed; new_count = (ary->capacity + ary->capacity/2); - renewed = ctx->realloc(ary->elements, sizeof(struct elem) * new_count); + renewed = ctx->realloc(ctx, ary->elements, sizeof(struct elem) * new_count); if(renewed == NULL) { return 1; } else {