diff --git a/src/logging.c b/src/logging.c index dd6c81c..b85e5e3 100644 --- a/src/logging.c +++ b/src/logging.c @@ -130,7 +130,7 @@ u6a_err_bad_bc_ver(const char* stage, const char* filename, int ver_major, int v U6A_COLD void u6a_err_vm_pool_oom(const char* stage) { - fprintf(stderr, "%s: [%s] VM object pool memory exhausted.\n", stage, prog_name); + fprintf(stderr, "%s: [%s] VM object pool memory exhausted.\n", prog_name, stage); } U6A_COLD void diff --git a/src/runtime.c b/src/runtime.c index 5cd4148..1d6db39 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -27,6 +27,7 @@ #include #include #include +#include static struct u6a_vm_ins* text; static uint32_t text_len; @@ -35,6 +36,7 @@ static uint32_t rodata_len; static bool force_exec; static struct u6a_vm_stack_ctx stack_ctx; static struct u6a_vm_pool_ctx pool_ctx; +static jmp_buf jmp_ctx; static const struct u6a_vm_ins text_subst[] = { { .opcode = u6a_vo_la }, @@ -181,10 +183,10 @@ u6a_runtime_init(struct u6a_runtime_options* options) { if (UNLIKELY(rodata_len != fread(rodata, sizeof(char), rodata_len, options->istream))) { goto runtime_init_failed; } - if (UNLIKELY(!u6a_vm_stack_init(&stack_ctx, options->stack_segment_size, err_runtime))) { + if (UNLIKELY(!u6a_vm_stack_init(&stack_ctx, options->stack_segment_size, &jmp_ctx, err_runtime))) { goto runtime_init_failed; } - if (UNLIKELY(!u6a_vm_pool_init(&pool_ctx, options->pool_size, text_len, err_runtime))) { + if (UNLIKELY(!u6a_vm_pool_init(&pool_ctx, options->pool_size, text_len, &jmp_ctx, err_runtime))) { goto runtime_init_failed; } stack_ctx.pool_ctx = &pool_ctx; @@ -209,6 +211,9 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { int current_char = EOF; struct u6a_vm_var_tuple tuple; void* cont; + if (setjmp(jmp_ctx)) { + goto runtime_error; + } while (true) { switch (ins->opcode) { case u6a_vo_app: diff --git a/src/vm_defs.h b/src/vm_defs.h index a0eb5dd..047e3d4 100644 --- a/src/vm_defs.h +++ b/src/vm_defs.h @@ -110,4 +110,6 @@ struct u6a_vm_var_tuple { #define U6A_VM_MIN_POOL_SIZE 16 #define U6A_VM_MAX_POOL_SIZE ( 16 * 1024 * 1024 ) +#define U6A_VM_ERR(ctx) longjmp(*(ctx)->jmp_ctx, -1) + #endif diff --git a/src/vm_pool.c b/src/vm_pool.c index 9d69a32..8e14bb0 100644 --- a/src/vm_pool.c +++ b/src/vm_pool.c @@ -24,7 +24,7 @@ #include bool -u6a_vm_pool_init(struct u6a_vm_pool_ctx* ctx, uint32_t pool_len, uint32_t ins_len, const char* err_stage) { +u6a_vm_pool_init(struct u6a_vm_pool_ctx* ctx, uint32_t pool_len, uint32_t ins_len, jmp_buf* jmp_ctx, const char* err_stage) { const uint32_t pool_size = sizeof(struct u6a_vm_pool) + pool_len * sizeof(struct u6a_vm_pool_elem); ctx->active_pool = malloc(pool_size); if (UNLIKELY(ctx->active_pool == NULL)) { @@ -49,6 +49,7 @@ u6a_vm_pool_init(struct u6a_vm_pool_ctx* ctx, uint32_t pool_len, uint32_t ins_le ctx->active_pool->pos = UINT32_MAX; ctx->holes->pos = UINT32_MAX; ctx->pool_len = pool_len; + ctx->jmp_ctx = jmp_ctx; ctx->err_stage = err_stage; return true; } diff --git a/src/vm_pool.h b/src/vm_pool.h index 2e8af67..df517bf 100644 --- a/src/vm_pool.h +++ b/src/vm_pool.h @@ -25,6 +25,7 @@ #include #include +#include struct u6a_vm_pool_elem { struct u6a_vm_var_tuple values; @@ -51,6 +52,7 @@ struct u6a_vm_pool_ctx { struct u6a_vm_stack_ctx* stack_ctx; uint32_t pool_len; uint32_t fstack_top; + jmp_buf* jmp_ctx; const char* err_stage; }; @@ -88,7 +90,7 @@ u6a_vm_pool_elem_alloc_(struct u6a_vm_pool_ctx* ctx) { if (ctx->holes->pos == UINT32_MAX) { if (UNLIKELY(++pool->pos == ctx->pool_len)) { u6a_err_vm_pool_oom(ctx->err_stage); - return NULL; + U6A_VM_ERR(ctx); } new_elem = pool->elems + pool->pos; } else { @@ -101,22 +103,16 @@ u6a_vm_pool_elem_alloc_(struct u6a_vm_pool_ctx* ctx) { static inline struct u6a_vm_pool_elem* u6a_vm_pool_elem_dup_(struct u6a_vm_pool_ctx* ctx, struct u6a_vm_pool_elem* elem) { struct u6a_vm_pool_elem* new_elem = u6a_vm_pool_elem_alloc_(ctx); - if (UNLIKELY(new_elem == NULL)) { - return NULL; - } *new_elem = *elem; return new_elem; } bool -u6a_vm_pool_init(struct u6a_vm_pool_ctx* ctx, uint32_t pool_len, uint32_t ins_len, const char* err_stage); +u6a_vm_pool_init(struct u6a_vm_pool_ctx* ctx, uint32_t pool_len, uint32_t ins_len, jmp_buf* jmp_ctx, const char* err_stage); static inline uint32_t u6a_vm_pool_alloc1(struct u6a_vm_pool_ctx* ctx, struct u6a_vm_var_fn v1) { struct u6a_vm_pool_elem* elem = u6a_vm_pool_elem_alloc_(ctx); - if (UNLIKELY(elem == NULL)) { - return UINT32_MAX; - } elem->values = (struct u6a_vm_var_tuple) { .v1.fn = v1, .v2.ptr = NULL }; elem->flags = 0; return elem - ctx->active_pool->elems; @@ -125,9 +121,6 @@ u6a_vm_pool_alloc1(struct u6a_vm_pool_ctx* ctx, struct u6a_vm_var_fn v1) { static inline uint32_t u6a_vm_pool_alloc2(struct u6a_vm_pool_ctx* ctx, struct u6a_vm_var_fn v1, struct u6a_vm_var_fn v2) { struct u6a_vm_pool_elem* elem = u6a_vm_pool_elem_alloc_(ctx); - if (UNLIKELY(elem == NULL)) { - return UINT32_MAX; - } elem->values = (struct u6a_vm_var_tuple) { .v1.fn = v1, .v2.fn = v2 }; elem->flags = 0; return elem - ctx->active_pool->elems; @@ -136,9 +129,6 @@ u6a_vm_pool_alloc2(struct u6a_vm_pool_ctx* ctx, struct u6a_vm_var_fn v1, struct static inline uint32_t u6a_vm_pool_alloc2_ptr(struct u6a_vm_pool_ctx* ctx, void* v1, void* v2) { struct u6a_vm_pool_elem* elem = u6a_vm_pool_elem_alloc_(ctx); - if (UNLIKELY(elem == NULL)) { - return UINT32_MAX; - } elem->values = (struct u6a_vm_var_tuple) { .v1.ptr = v1, .v2.ptr = v2 }; elem->flags = U6A_VM_POOL_ELEM_HOLDS_PTR; return elem - ctx->active_pool->elems; diff --git a/src/vm_stack.c b/src/vm_stack.c index 55b2340..6335d61 100644 --- a/src/vm_stack.c +++ b/src/vm_stack.c @@ -83,8 +83,9 @@ vm_stack_free(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_stack* vs) { } bool -u6a_vm_stack_init(struct u6a_vm_stack_ctx* ctx, uint32_t stack_seg_len, const char* err_stage) { +u6a_vm_stack_init(struct u6a_vm_stack_ctx* ctx, uint32_t stack_seg_len, jmp_buf* jmp_ctx, const char* err_stage) { ctx->stack_seg_len = stack_seg_len; + ctx->jmp_ctx = jmp_ctx; ctx->err_stage = err_stage; ctx->active_stack = vm_stack_create(ctx, NULL, UINT32_MAX); return ctx->active_stack != NULL; @@ -92,34 +93,32 @@ u6a_vm_stack_init(struct u6a_vm_stack_ctx* ctx, uint32_t stack_seg_len, const ch // Boilerplates below. If only we have C++ templates here... (macros just make things nastier) -U6A_HOT bool +U6A_HOT void u6a_vm_stack_push1_split_(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0) { struct u6a_vm_stack* vs = ctx->active_stack; ctx->active_stack = vm_stack_create(ctx, vs, 0); if (UNLIKELY(ctx->active_stack == NULL)) { ctx->active_stack = vs; - return false; + U6A_VM_ERR(ctx); } ++vs->refcnt; ctx->active_stack->elems[0] = v0; - return true; } -U6A_HOT bool +U6A_HOT void u6a_vm_stack_push2_split_(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, struct u6a_vm_var_fn v1) { struct u6a_vm_stack* vs = ctx->active_stack; ctx->active_stack = vm_stack_create(ctx, vs, 1); if (UNLIKELY(ctx->active_stack == NULL)) { ctx->active_stack = vs; - return false; + U6A_VM_ERR(ctx); } ++vs->refcnt; ctx->active_stack->elems[0] = v0; ctx->active_stack->elems[1] = v1; - return true; } -U6A_HOT bool +U6A_HOT void u6a_vm_stack_push3_split_(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, struct u6a_vm_var_fn v1, struct u6a_vm_var_fn v2) { @@ -127,16 +126,15 @@ u6a_vm_stack_push3_split_(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, ctx->active_stack = vm_stack_create(ctx, vs, 2); if (UNLIKELY(ctx->active_stack == NULL)) { ctx->active_stack = vs; - return false; + U6A_VM_ERR(ctx); } ++vs->refcnt; ctx->active_stack->elems[0] = v0; ctx->active_stack->elems[1] = v1; ctx->active_stack->elems[2] = v2; - return true; } -U6A_HOT bool +U6A_HOT void u6a_vm_stack_push4_split_(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, struct u6a_vm_var_fn v1, struct u6a_vm_var_fn v2, struct u6a_vm_var_fn v3) { @@ -144,35 +142,33 @@ u6a_vm_stack_push4_split_(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, ctx->active_stack = vm_stack_create(ctx, vs, 3); if (UNLIKELY(ctx->active_stack == NULL)) { ctx->active_stack = vs; - return false; + U6A_VM_ERR(ctx); } ++vs->refcnt; ctx->active_stack->elems[0] = v0; ctx->active_stack->elems[1] = v1; ctx->active_stack->elems[2] = v2; ctx->active_stack->elems[3] = v3; - return true; } -U6A_HOT bool +U6A_HOT void u6a_vm_stack_pop_split_(struct u6a_vm_stack_ctx* ctx) { struct u6a_vm_stack* vs = ctx->active_stack; ctx->active_stack = vs->prev; if (UNLIKELY(ctx->active_stack == NULL)) { u6a_err_stack_underflow(ctx->err_stage); ctx->active_stack = vs; - return false; + U6A_VM_ERR(ctx); } if (--ctx->active_stack->refcnt > 0) { ctx->active_stack = vm_stack_dup(ctx, ctx->active_stack); } if (UNLIKELY(ctx->active_stack == NULL)) { ctx->active_stack = vs; - return false; + U6A_VM_ERR(ctx); } free(vs); --ctx->active_stack->top; - return true; } U6A_HOT struct u6a_vm_var_fn @@ -183,12 +179,12 @@ u6a_vm_stack_xch_split_(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0) { struct u6a_vm_stack* prev = vs->prev; if (UNLIKELY(prev == NULL)) { u6a_err_stack_underflow(ctx->err_stage); - return U6A_VM_VAR_FN_EMPTY; + U6A_VM_ERR(ctx); } if (--prev->refcnt > 0) { prev = vm_stack_dup(ctx, prev); if (UNLIKELY(prev == NULL)) { - return U6A_VM_VAR_FN_EMPTY; + U6A_VM_ERR(ctx); } } if (vs->top == 0) { diff --git a/src/vm_stack.h b/src/vm_stack.h index d4234e2..9da2c63 100644 --- a/src/vm_stack.h +++ b/src/vm_stack.h @@ -25,6 +25,7 @@ #include #include +#include struct u6a_vm_stack { struct u6a_vm_stack* prev; @@ -34,14 +35,15 @@ struct u6a_vm_stack { }; struct u6a_vm_stack_ctx { - struct u6a_vm_stack* active_stack; - uint32_t stack_seg_len; - struct u6a_vm_pool_ctx* pool_ctx; - const char* err_stage; + struct u6a_vm_stack* active_stack; + uint32_t stack_seg_len; + struct u6a_vm_pool_ctx* pool_ctx; + jmp_buf* jmp_ctx; + const char* err_stage; }; bool -u6a_vm_stack_init(struct u6a_vm_stack_ctx* ctx, uint32_t stack_seg_len, const char* err_stage); +u6a_vm_stack_init(struct u6a_vm_stack_ctx* ctx, uint32_t stack_seg_len, jmp_buf* jmp_ctx, const char* err_stage); static inline struct u6a_vm_var_fn u6a_vm_stack_top(struct u6a_vm_stack_ctx* ctx) { @@ -49,45 +51,45 @@ u6a_vm_stack_top(struct u6a_vm_stack_ctx* ctx) { if (UNLIKELY(vs->top == UINT32_MAX)) { vs = vs->prev; if (UNLIKELY(vs == NULL)) { - return U6A_VM_VAR_FN_EMPTY; + U6A_VM_ERR(ctx); } ctx->active_stack = vs; } return vs->elems[vs->top]; } -bool +void u6a_vm_stack_push1_split_(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0); -static inline bool +static inline void u6a_vm_stack_push1(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0) { struct u6a_vm_stack* vs = ctx->active_stack; if (LIKELY(vs->top + 1 < ctx->stack_seg_len)) { vs->elems[++vs->top] = v0; - return true; + } else { + u6a_vm_stack_push1_split_(ctx, v0); } - return u6a_vm_stack_push1_split_(ctx, v0); } -bool +void u6a_vm_stack_push2_split_(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, struct u6a_vm_var_fn v1); -static inline bool +static inline void u6a_vm_stack_push2(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, struct u6a_vm_var_fn v1) { struct u6a_vm_stack* vs = ctx->active_stack; if (LIKELY(vs->top + 2 < ctx->stack_seg_len)) { vs->elems[++vs->top] = v0; vs->elems[++vs->top] = v1; - return true; + } else { + u6a_vm_stack_push2_split_(ctx, v0, v1); } - return u6a_vm_stack_push2_split_(ctx, v0, v1); } -bool +void u6a_vm_stack_push3_split_(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, struct u6a_vm_var_fn v1, struct u6a_vm_var_fn v2); -static inline bool +static inline void u6a_vm_stack_push3(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, struct u6a_vm_var_fn v1, struct u6a_vm_var_fn v2) { @@ -96,16 +98,16 @@ u6a_vm_stack_push3(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, struct vs->elems[++vs->top] = v0; vs->elems[++vs->top] = v1; vs->elems[++vs->top] = v2; - return true; + } else { + return u6a_vm_stack_push3_split_(ctx, v0, v1, v2); } - return u6a_vm_stack_push3_split_(ctx, v0, v1, v2); } -bool +void u6a_vm_stack_push4_split_(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, struct u6a_vm_var_fn v1, struct u6a_vm_var_fn v2, struct u6a_vm_var_fn v3); -static inline bool +static inline void u6a_vm_stack_push4(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, struct u6a_vm_var_fn v1, struct u6a_vm_var_fn v2, struct u6a_vm_var_fn v3) { @@ -115,21 +117,20 @@ u6a_vm_stack_push4(struct u6a_vm_stack_ctx* ctx, struct u6a_vm_var_fn v0, struct vs->elems[++vs->top] = v1; vs->elems[++vs->top] = v2; vs->elems[++vs->top] = v3; - return true; + } else { + u6a_vm_stack_push4_split_(ctx, v0, v1, v2, v3); } - return u6a_vm_stack_push4_split_(ctx, v0, v1, v2, v3); } -bool +void u6a_vm_stack_pop_split_(struct u6a_vm_stack_ctx* ctx); -static inline bool +static inline void u6a_vm_stack_pop(struct u6a_vm_stack_ctx* ctx) { struct u6a_vm_stack* vs = ctx->active_stack; - if (LIKELY(vs->top-- != UINT32_MAX)) { - return true; + if (UNLIKELY(vs->top-- == UINT32_MAX)) { + u6a_vm_stack_pop_split_(ctx); } - return u6a_vm_stack_pop_split_(ctx); } struct u6a_vm_var_fn