From 35af4ba4fc21a4b2357c50e6b02a2e3e4b236e88 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Wed, 21 Apr 2021 15:07:16 +0200 Subject: treewide: rework internal data type system Instead of relying on json_object values internally, use custom types to represent the different ucode value types which brings a number of advantages compared to the previous approach: - Due to the use of tagged pointers, small integer, string and bool values can be stored directly in the pointer addresses, vastly reducing required heap memory - Ability to create circular data structures such as `let o; o = { test: o };` - Ability to register custom `tostring()` function through prototypes - Initial mark/sweep GC implementation to tear down circular object graphs on VM deinit The change also paves the way for possible future extensions such as constant variables and meta methods for custom ressource types. Signed-off-by: Jo-Philipp Wich --- vm.c | 1039 +++++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 549 insertions(+), 490 deletions(-) (limited to 'vm.c') diff --git a/vm.c b/vm.c index ce1aa0c..10e3286 100644 --- a/vm.c +++ b/vm.c @@ -51,8 +51,8 @@ static const uc_insn_definition insn_defs[__I_MAX] = { [I_LUPV] = { 0, 1, 4 }, [I_LVAL] = { 2, 1, 0 }, - [I_CLFN] = { 0, 1, 4, true }, - [I_ARFN] = { 0, 1, 4, true }, + [I_CLFN] = { 0, 1, 4 }, + [I_ARFN] = { 0, 1, 4 }, [I_SLOC] = { 0, 0, 4 }, [I_SUPV] = { 0, 0, 4 }, @@ -90,8 +90,8 @@ static const uc_insn_definition insn_defs[__I_MAX] = { [I_GT] = { 2, 1, 0 }, [I_IN] = { 2, 1, 0 }, - [I_JMP] = { 0, 0, -4, true }, - [I_JMPZ] = { 1, 0, -4, true }, + [I_JMP] = { 0, 0, -4 }, + [I_JMPZ] = { 1, 0, -4 }, [I_COPY] = { 0, 1, 1 }, [I_POP] = { 1, 0, 0 }, @@ -124,19 +124,19 @@ uc_vm_reset_stack(uc_vm *vm) { while (vm->stack.count > 0) { vm->stack.count--; - uc_value_put(vm->stack.entries[vm->stack.count]); + ucv_put(vm->stack.entries[vm->stack.count]); vm->stack.entries[vm->stack.count] = NULL; } } -static json_object * +static uc_value_t * uc_vm_callframe_pop(uc_vm *vm); static void uc_vm_reset_callframes(uc_vm *vm) { while (vm->callframes.count > 0) - uc_value_put(uc_vm_callframe_pop(vm)); + ucv_put(uc_vm_callframe_pop(vm)); } void uc_vm_init(uc_vm *vm, uc_parse_config *config) @@ -152,19 +152,22 @@ void uc_vm_init(uc_vm *vm, uc_parse_config *config) vm->open_upvals = NULL; + vm->values.prev = &vm->values; + vm->values.next = &vm->values; + uc_vm_reset_stack(vm); } void uc_vm_free(uc_vm *vm) { - uc_upvalref *ref; + uc_upvalref_t *ref; - uc_value_put(vm->exception.stacktrace); + ucv_put(vm->exception.stacktrace); free(vm->exception.message); while (vm->open_upvals) { ref = vm->open_upvals->next; - uc_value_put(vm->open_upvals->header.jso); + ucv_put(&vm->open_upvals->header); vm->open_upvals = ref; } @@ -172,6 +175,8 @@ void uc_vm_free(uc_vm *vm) uc_vm_reset_stack(vm); uc_vector_clear(&vm->stack); uc_vector_clear(&vm->callframes); + + ucv_gc(vm, true); } static uc_chunk * @@ -263,11 +268,12 @@ static void uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame) { uc_chunk *chunk = uc_vm_frame_chunk(frame); - uc_function *function; - uc_closure *closure; - uc_upvalref *ref; - json_object *v; + uc_function_t *function; + uc_closure_t *closure; + uc_upvalref_t *ref; + uc_value_t *v; size_t i; + char *s; fprintf(stderr, " [*] CALLFRAME[%zx]\n", frame - vm->callframes.entries); @@ -275,8 +281,9 @@ uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame) fprintf(stderr, " |- stackframe %zu/%zu\n", frame->stackframe, vm->stack.count); - fprintf(stderr, " |- ctx %s\n", - json_object_to_json_string(frame->ctx)); + s = ucv_to_string(NULL, frame->ctx); + fprintf(stderr, " |- ctx %s\n", s); + free(s); if (chunk) { fprintf(stderr, " |- %zu constants\n", @@ -284,12 +291,10 @@ uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame) for (i = 0; i < chunk->constants.isize; i++) { v = uc_chunk_get_constant(chunk, i); - - fprintf(stderr, " | [%zu] %s\n", - i, - json_object_to_json_string(v)); - - uc_value_put(v); + s = ucv_to_jsonstring(NULL, v); + fprintf(stderr, " | [%zu] %s\n", i, s); + free(s); + ucv_put(v); } closure = frame->closure; @@ -301,80 +306,88 @@ uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame) for (i = 0; i < function->nupvals; i++) { ref = closure->upvals[i]; v = uc_chunk_debug_get_variable(chunk, 0, i, true); + s = ucv_to_string(NULL, v); + fprintf(stderr, " [%zu] <%p> %s ", i, ref, s); + free(s); - if (ref->closed) - fprintf(stderr, " [%zu] <%p> %s {closed} %s\n", - i, - ref, - json_object_to_json_string(v), - json_object_to_json_string(ref->value)); - else - fprintf(stderr, " [%zu] <%p> %s {open[%zu]} %s\n", - i, - ref, - json_object_to_json_string(v), - ref->slot, - json_object_to_json_string(vm->stack.entries[ref->slot])); - - uc_value_put(v); + if (ref->closed) { + s = ucv_to_jsonstring(NULL, ref->value); + fprintf(stderr, "{closed} %s\n", s); + } + else { + s = ucv_to_jsonstring(NULL, vm->stack.entries[ref->slot]); + fprintf(stderr, "{open[%zu]} %s\n", ref->slot, s); + } + + ucv_put(v); + free(s); } } } void -uc_vm_stack_push(uc_vm *vm, json_object *value) +uc_vm_stack_push(uc_vm *vm, uc_value_t *value) { + char *s; + uc_vector_grow(&vm->stack); - uc_value_put(vm->stack.entries[vm->stack.count]); + ucv_put(vm->stack.entries[vm->stack.count]); vm->stack.entries[vm->stack.count] = value; vm->stack.count++; - if (vm->trace) - fprintf(stderr, " [+%zd] %s\n", - vm->stack.count - 1, - json_object_to_json_string(value)); + if (vm->trace) { + s = ucv_to_jsonstring(NULL, value); + fprintf(stderr, " [+%zd] %s\n", vm->stack.count - 1, s); + free(s); + } } -json_object * +uc_value_t * uc_vm_stack_pop(uc_vm *vm) { - json_object *rv; + uc_value_t *rv; + char *s; vm->stack.count--; rv = vm->stack.entries[vm->stack.count]; vm->stack.entries[vm->stack.count] = NULL; - if (vm->trace) - fprintf(stderr, " [-%zd] %s\n", - vm->stack.count, - json_object_to_json_string(rv)); + if (vm->trace) { + s = ucv_to_jsonstring(NULL, rv); + fprintf(stderr, " [-%zd] %s\n", vm->stack.count, s); + free(s); + } return rv; } -json_object * +uc_value_t * uc_vm_stack_peek(uc_vm *vm, size_t offset) { return vm->stack.entries[vm->stack.count + (-1 - offset)]; } static void -uc_vm_stack_set(uc_vm *vm, size_t offset, json_object *value) +uc_vm_stack_set(uc_vm *vm, size_t offset, uc_value_t *value) { - if (vm->trace) - fprintf(stderr, " [!%zu] %s\n", - offset, json_object_to_json_string(value)); + char *s; - uc_value_put(vm->stack.entries[offset]); + if (vm->trace) { + s = ucv_to_jsonstring(NULL, value); + fprintf(stderr, " [!%zu] %s\n", offset, s); + free(s); + } + + ucv_put(vm->stack.entries[offset]); vm->stack.entries[offset] = value; } static void -uc_vm_call_native(uc_vm *vm, json_object *ctx, uc_cfunction *fptr, bool mcall, size_t nargs) +uc_vm_call_native(uc_vm *vm, uc_value_t *ctx, uc_cfunction_t *fptr, bool mcall, size_t nargs) { - json_object *res = NULL; + uc_value_t *res = NULL; uc_callframe *frame; /* add new callframe */ @@ -393,24 +406,25 @@ uc_vm_call_native(uc_vm *vm, json_object *ctx, uc_cfunction *fptr, bool mcall, s res = fptr->cfn(vm, nargs); /* reset stack */ - uc_value_put(uc_vm_callframe_pop(vm)); + ucv_put(uc_vm_callframe_pop(vm)); /* push return value */ if (!vm->exception.type) uc_vm_stack_push(vm, res); else - uc_value_put(res); + ucv_put(res); } static bool -uc_vm_call_function(uc_vm *vm, json_object *ctx, json_object *fno, bool mcall, size_t argspec) +uc_vm_call_function(uc_vm *vm, uc_value_t *ctx, uc_value_t *fno, bool mcall, size_t argspec) { size_t i, j, stackoff, nargs = argspec & 0xffff, nspreads = argspec >> 16; uc_callframe *frame = uc_vm_current_frame(vm); - json_object *ellip, *arg; - uc_function *function; - uc_closure *closure; + uc_value_t *ellip, *arg; + uc_function_t *function; + uc_closure_t *closure; uint16_t slot, tmp; + char *s; /* XXX: make dependent on stack size */ if (vm->callframes.count >= 1000) { @@ -424,11 +438,11 @@ uc_vm_call_function(uc_vm *vm, json_object *ctx, json_object *fno, bool mcall, s /* argument list contains spread operations, we need to reshuffle the stack */ if (nspreads > 0) { /* create temporary array */ - ellip = xjs_new_array_size(nargs); + ellip = ucv_array_new_length(vm, nargs); /* pop original stack values and push to temp array in reverse order */ for (i = 0; i < nargs; i++) - json_object_array_add(ellip, uc_vm_stack_pop(vm)); + ucv_array_push(ellip, uc_vm_stack_pop(vm)); /* for each spread value index ... */ for (i = 0, slot = nargs; i < nspreads; i++) { @@ -437,61 +451,61 @@ uc_vm_call_function(uc_vm *vm, json_object *ctx, json_object *fno, bool mcall, s frame->ip += 2; /* push each preceeding non-spread value to the stack */ - for (j = slot; j > tmp + 1; j--) - uc_vm_stack_push(vm, uc_value_get(json_object_array_get_idx(ellip, j - 1))); + for (j = slot; j > tmp + 1UL; j--) + uc_vm_stack_push(vm, ucv_get(ucv_array_get(ellip, j - 1))); /* read spread value at index... */ slot = tmp; - arg = uc_value_get(json_object_array_get_idx(ellip, slot)); + arg = ucv_get(ucv_array_get(ellip, slot)); /* ... ensure that it is an array type ... */ - if (!json_object_is_type(arg, json_type_array)) { - uc_vm_raise_exception(vm, EXCEPTION_TYPE, - "(%s) is not iterable", - json_object_to_json_string(arg)); + if (ucv_type(arg) != UC_ARRAY) { + s = ucv_to_string(vm, arg); + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "(%s) is not iterable", s); + free(s); return false; } /* ... and push each spread array value as argument to the stack */ - for (j = 0; j < json_object_array_length(arg); j++) - uc_vm_stack_push(vm, uc_value_get(json_object_array_get_idx(arg, j))); + for (j = 0; j < ucv_array_length(arg); j++) + uc_vm_stack_push(vm, ucv_get(ucv_array_get(arg, j))); - uc_value_put(arg); + ucv_put(arg); } /* push remaining non-spread arguments to the stack */ for (i = slot; i > 0; i--) - uc_vm_stack_push(vm, uc_value_get(json_object_array_get_idx(ellip, i - 1))); + uc_vm_stack_push(vm, ucv_get(ucv_array_get(ellip, i - 1))); /* free temp array */ - uc_value_put(ellip); + ucv_put(ellip); /* update arg count */ nargs = vm->stack.count - stackoff - 1; } /* is a native function */ - if (uc_object_is_type(fno, UC_OBJ_CFUNCTION)) { - uc_vm_call_native(vm, ctx, uc_object_as_cfunction(fno), mcall, nargs); + if (ucv_type(fno) == UC_CFUNCTION) { + uc_vm_call_native(vm, ctx, (uc_cfunction_t *)fno, mcall, nargs); return true; } - if (!uc_object_is_type(fno, UC_OBJ_CLOSURE)) { + if (ucv_type(fno) != UC_CLOSURE) { uc_vm_raise_exception(vm, EXCEPTION_TYPE, "left-hand side is not a function"); return false; } - closure = uc_object_as_closure(fno); + closure = (uc_closure_t *)fno; function = closure->function; /* fewer arguments on stack than function expects => pad */ if (nargs < function->nargs) { for (i = nargs; i < function->nargs; i++) { if (function->vararg && (i + 1) == function->nargs) - uc_vm_stack_push(vm, xjs_new_array_size(0)); + uc_vm_stack_push(vm, ucv_array_new_length(vm, 0)); else uc_vm_stack_push(vm, NULL); } @@ -501,10 +515,10 @@ uc_vm_call_function(uc_vm *vm, json_object *ctx, json_object *fno, bool mcall, s else if (nargs > function->nargs - function->vararg) { /* is a vararg function => pass excess args as array */ if (function->vararg) { - ellip = xjs_new_array_size(nargs - (function->nargs - 1)); + ellip = ucv_array_new_length(vm, nargs - (function->nargs - 1)); for (i = function->nargs; i <= nargs; i++) - json_object_array_add(ellip, uc_vm_stack_peek(vm, nargs - i)); + ucv_array_push(ellip, uc_vm_stack_peek(vm, nargs - i)); for (i = function->nargs; i <= nargs; i++) uc_vm_stack_pop(vm); @@ -515,7 +529,7 @@ uc_vm_call_function(uc_vm *vm, json_object *ctx, json_object *fno, bool mcall, s /* static amount of args => drop excess values */ else { for (i = function->nargs; i < nargs; i++) - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); } } @@ -543,19 +557,19 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); uc_chunk *chunk = uc_vm_frame_chunk(frame); - size_t msglen = 0, srcpos; - json_object *cnst = NULL; - char *msg = NULL; + uc_stringbuf_t *buf = NULL; + uc_value_t *cnst = NULL; + size_t srcpos; + char *s; - srcpos = uc_function_get_srcpos(frame->closure->function, pos - chunk->entries); + srcpos = ucv_function_srcpos((uc_value_t *)frame->closure->function, pos - chunk->entries); if (last_srcpos == 0 || last_source != frame->closure->function->source || srcpos != last_srcpos) { - format_source_context(&msg, &msglen, - frame->closure->function->source, - srcpos, true); + buf = xprintbuf_new(); - fprintf(stderr, "%s", msg); - free(msg); + format_source_context(buf, frame->closure->function->source, srcpos, true); + fwrite(buf->buf, 1, printbuf_length(buf), stderr); + printbuf_free(buf); last_source = frame->closure->function->source; last_srcpos = srcpos; @@ -574,13 +588,13 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) case -2: fprintf(stderr, " {%c0x%hx}", vm->arg.s16 < 0 ? '-' : '+', - vm->arg.s16 < 0 ? -(unsigned)vm->arg.s16 : vm->arg.s16); + vm->arg.s16 < 0 ? -(unsigned)vm->arg.s16 : (unsigned)vm->arg.s16); break; case -4: fprintf(stderr, " {%c0x%x}", vm->arg.s32 < 0 ? '-' : '+', - vm->arg.s32 < 0 ? -(unsigned)vm->arg.s32 : vm->arg.s32); + vm->arg.s32 < 0 ? -(unsigned)vm->arg.s32 : (unsigned)vm->arg.s32); break; case 1: @@ -605,9 +619,11 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) case I_LVAR: case I_SVAR: cnst = uc_chunk_get_constant(uc_vm_frame_chunk(uc_vector_last(&vm->callframes)), vm->arg.u32); + s = cnst ? ucv_to_jsonstring(NULL, cnst) : NULL; - fprintf(stderr, "\t; %s", cnst ? json_object_to_json_string(cnst) : "null"); - uc_value_put(cnst); + fprintf(stderr, "\t; %s", s ? s : "(?)"); + ucv_put(cnst); + free(s); break; case I_LLOC: @@ -615,9 +631,11 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) case I_SLOC: case I_SUPV: cnst = uc_chunk_debug_get_variable(chunk, pos - chunk->entries, vm->arg.u32, (insn == I_LUPV || insn == I_SUPV)); + s = cnst ? ucv_to_jsonstring(NULL, cnst) : NULL; - fprintf(stderr, "\t; %s", cnst ? json_object_to_json_string(cnst) : "(?)"); - uc_value_put(cnst); + fprintf(stderr, "\t; %s", s ? s : "(?)"); + ucv_put(cnst); + free(s); break; case I_ULOC: @@ -629,11 +647,14 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) if (!cnst) cnst = uc_chunk_get_constant(uc_vm_frame_chunk(uc_vector_last(&vm->callframes)), vm->arg.u32 & 0x00ffffff); + s = cnst ? ucv_to_jsonstring(NULL, cnst) : NULL; + fprintf(stderr, "\t; %s (%s)", - cnst ? json_object_to_json_string(cnst) : "(?)", + s ? s : "(?)", insn_names[vm->arg.u32 >> 24]); - uc_value_put(cnst); + ucv_put(cnst); + free(s); break; case I_UVAL: @@ -647,14 +668,38 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) fprintf(stderr, "\n"); } -static int -uc_vm_exception_tostring(json_object *jso, struct printbuf *pb, int level, int flags) +static uc_value_t * +uc_vm_exception_tostring(uc_vm *vm, size_t nargs) { - bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT); - json_object *message = json_object_object_get(jso, "message"); + uc_callframe *frame = uc_vm_current_frame(vm); + uc_value_t *message = ucv_object_get(frame->ctx, "message", NULL); - return sprintbuf(pb, "%s", - strict ? json_object_to_json_string(message) : json_object_get_string(message)); + return message ? ucv_get(message) : ucv_string_new("Exception"); +} + +static uc_value_t *exception_prototype = NULL; + +static uc_value_t * +uc_vm_exception_new(uc_vm *vm, uc_exception_type_t type, const char *message, uc_value_t *stacktrace) +{ + uc_value_t *exo; + + if (exception_prototype == NULL) { + exception_prototype = ucv_object_new(vm); + + ucv_object_add(exception_prototype, "tostring", + ucv_cfunction_new("tostring", uc_vm_exception_tostring)); + } + + exo = ucv_object_new(vm); + + ucv_object_add(exo, "type", ucv_string_new(exception_type_strings[type])); + ucv_object_add(exo, "message", ucv_string_new(message)); + ucv_object_add(exo, "stacktrace", ucv_get(stacktrace)); + + ucv_prototype_set(exo, ucv_get(exception_prototype)); + + return exo; } static bool @@ -662,7 +707,7 @@ uc_vm_handle_exception(uc_vm *vm) { uc_callframe *frame = uc_vm_current_frame(vm); uc_chunk *chunk = NULL; - json_object *exo; + uc_value_t *exo; size_t i, pos; if (!frame->closure) @@ -680,16 +725,11 @@ uc_vm_handle_exception(uc_vm *vm) /* we found a matching range... first unwind stack */ while (vm->stack.count > frame->stackframe + chunk->ehranges.entries[i].slot) - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); /* prepare exception object and expose it to user handler code */ - exo = xjs_new_object(); + exo = uc_vm_exception_new(vm, vm->exception.type, vm->exception.message, vm->exception.stacktrace); - json_object_object_add(exo, "type", xjs_new_string(exception_type_strings[vm->exception.type])); - json_object_object_add(exo, "message", xjs_new_string(vm->exception.message)); - json_object_object_add(exo, "stacktrace", uc_value_get(vm->exception.stacktrace)); - - json_object_set_serializer(exo, uc_vm_exception_tostring, NULL, NULL); uc_vm_stack_push(vm, exo); /* reset exception information */ @@ -721,35 +761,35 @@ uc_vm_handle_exception(uc_vm *vm) return false; } -static json_object * +static uc_value_t * uc_vm_capture_stacktrace(uc_vm *vm, size_t i) { - json_object *stacktrace, *entry, *last = NULL; - uc_function *function; + uc_value_t *stacktrace, *entry, *last = NULL; + uc_function_t *function; uc_callframe *frame; size_t off, srcpos; char *name; - stacktrace = xjs_new_array(); + stacktrace = ucv_array_new(vm); for (; i > 0; i--) { frame = &vm->callframes.entries[i - 1]; - entry = xjs_new_object(); + entry = ucv_object_new(vm); if (frame->closure) { function = frame->closure->function; off = (frame->ip - uc_vm_frame_chunk(frame)->entries) - 1; - srcpos = uc_function_get_srcpos(function, off); + srcpos = ucv_function_srcpos((uc_value_t *)function, off); - json_object_object_add(entry, "filename", xjs_new_string(function->source->filename)); - json_object_object_add(entry, "line", xjs_new_int64(uc_source_get_line(function->source, &srcpos))); - json_object_object_add(entry, "byte", xjs_new_int64(srcpos)); + ucv_object_add(entry, "filename", ucv_string_new(function->source->filename)); + ucv_object_add(entry, "line", ucv_int64_new(uc_source_get_line(function->source, &srcpos))); + ucv_object_add(entry, "byte", ucv_int64_new(srcpos)); } if (i > 1) { if (frame->closure) { - if (frame->closure->function->name) + if (frame->closure->function->name[0]) name = frame->closure->function->name; else if (frame->closure->is_arrow) name = "[arrow function]"; @@ -760,29 +800,29 @@ uc_vm_capture_stacktrace(uc_vm *vm, size_t i) name = frame->cfunction->name; } - json_object_object_add(entry, "function", xjs_new_string(name)); + ucv_object_add(entry, "function", ucv_string_new(name)); } - if (!json_object_equal(last, entry)) { - json_object_array_add(stacktrace, entry); + if (!ucv_equal(last, entry)) { + ucv_array_push(stacktrace, entry); last = entry; } else { - uc_value_put(entry); + ucv_put(entry); } } return stacktrace; } -static json_object * +static uc_value_t * uc_vm_get_error_context(uc_vm *vm) { - json_object *stacktrace; + uc_value_t *stacktrace; uc_callframe *frame; + uc_stringbuf_t *buf; uc_chunk *chunk; - size_t offset, len = 0, i; - char *msg = NULL; + size_t offset, i; /* skip to first non-native function call frame */ for (i = vm->callframes.count; i > 0; i--) @@ -795,17 +835,17 @@ uc_vm_get_error_context(uc_vm *vm) return NULL; chunk = uc_vm_frame_chunk(frame); - offset = uc_function_get_srcpos(frame->closure->function, (frame->ip - chunk->entries) - 1); + offset = ucv_function_srcpos((uc_value_t *)frame->closure->function, (frame->ip - chunk->entries) - 1); stacktrace = uc_vm_capture_stacktrace(vm, i); + buf = ucv_stringbuf_new(); + if (offset) - format_error_context(&msg, &len, frame->closure->function->source, stacktrace, offset); + format_error_context(buf, frame->closure->function->source, stacktrace, offset); else - xasprintf(&msg, "At offset %zu", (frame->ip - chunk->entries) - 1); + ucv_stringbuf_printf(buf, "At offset %zu", (frame->ip - chunk->entries) - 1); - json_object_object_add(json_object_array_get_idx(stacktrace, 0), "context", xjs_new_string(msg)); - - free(msg); + ucv_object_add(ucv_array_get(stacktrace, 0), "context", ucv_stringbuf_finish(buf)); return stacktrace; } @@ -823,7 +863,7 @@ uc_vm_raise_exception(uc_vm *vm, uc_exception_type_t type, const char *fmt, ...) xvasprintf(&vm->exception.message, fmt, ap); va_end(ap); - uc_value_put(vm->exception.stacktrace); + ucv_put(vm->exception.stacktrace); vm->exception.stacktrace = uc_vm_get_error_context(vm); } @@ -837,15 +877,15 @@ uc_vm_insn_load(uc_vm *vm, enum insn_type insn) break; case I_LOAD8: - uc_vm_stack_push(vm, xjs_new_int64(vm->arg.s8)); + uc_vm_stack_push(vm, ucv_int64_new(vm->arg.s8)); break; case I_LOAD16: - uc_vm_stack_push(vm, xjs_new_int64(vm->arg.s16)); + uc_vm_stack_push(vm, ucv_int64_new(vm->arg.s16)); break; case I_LOAD32: - uc_vm_stack_push(vm, xjs_new_int64(vm->arg.s32)); + uc_vm_stack_push(vm, ucv_int64_new(vm->arg.s32)); break; default: @@ -856,33 +896,33 @@ uc_vm_insn_load(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_load_regexp(uc_vm *vm, enum insn_type insn) { + uc_value_t *re, *jstr = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32); bool icase = false, newline = false, global = false; - json_object *jstr = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32); - const char *str; - uc_regexp *re; - char *err; + char *str, *err = NULL; - if (!json_object_is_type(jstr, json_type_string) || json_object_get_string_len(jstr) < 2) { + if (ucv_type(jstr) != UC_STRING || ucv_string_length(jstr) < 2) { uc_vm_stack_push(vm, NULL); - uc_value_put(jstr); + ucv_put(jstr); return; } - str = json_object_get_string(jstr); + str = ucv_string_get(jstr); global = (*str & (1 << 0)); icase = (*str & (1 << 1)); newline = (*str & (1 << 2)); - re = uc_regexp_new(++str, icase, newline, global, &err); + re = ucv_regexp_new(++str, icase, newline, global, &err); - uc_value_put(jstr); + ucv_put(jstr); if (re) - uc_vm_stack_push(vm, re->header.jso); + uc_vm_stack_push(vm, re); else uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, "%s", err); + + free(err); } static void @@ -894,29 +934,32 @@ uc_vm_insn_load_null(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_load_bool(uc_vm *vm, enum insn_type insn) { - uc_vm_stack_push(vm, xjs_new_boolean(insn == I_LTRUE)); + uc_vm_stack_push(vm, ucv_boolean_new(insn == I_LTRUE)); } static void uc_vm_insn_load_var(uc_vm *vm, enum insn_type insn) { - json_object *name, *val = NULL; - uc_prototype *scope, *next; + uc_value_t *name, *val = NULL; + uc_value_t *scope, *next; + bool found; scope = vm->globals; name = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32); - while (json_object_get_type(name) == json_type_string) { - if (json_object_object_get_ex(scope->header.jso, json_object_get_string(name), &val)) + while (ucv_type(name) == UC_STRING) { + val = ucv_object_get(scope, ucv_string_get(name), &found); + + if (found) break; - next = scope->parent; + next = ucv_prototype_get(scope); if (!next) { if (vm->config->strict_declarations) { uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, "access to undeclared variable %s", - json_object_get_string(name)); + ucv_string_get(name)); } break; @@ -925,21 +968,21 @@ uc_vm_insn_load_var(uc_vm *vm, enum insn_type insn) scope = next; } - uc_value_put(name); + ucv_put(name); - uc_vm_stack_push(vm, uc_value_get(val)); + uc_vm_stack_push(vm, ucv_get(val)); } static void uc_vm_insn_load_val(uc_vm *vm, enum insn_type insn) { - json_object *k = uc_vm_stack_pop(vm); - json_object *v = uc_vm_stack_pop(vm); + uc_value_t *k = uc_vm_stack_pop(vm); + uc_value_t *v = uc_vm_stack_pop(vm); - switch (json_object_get_type(v)) { - case json_type_object: - case json_type_array: - uc_vm_stack_push(vm, uc_getval(v, k)); + switch (ucv_type(v)) { + case UC_OBJECT: + case UC_ARRAY: + uc_vm_stack_push(vm, uc_getval(vm, v, k)); break; default: @@ -950,21 +993,20 @@ uc_vm_insn_load_val(uc_vm *vm, enum insn_type insn) break; } - - uc_value_put(k); - uc_value_put(v); + ucv_put(k); + ucv_put(v); } static void uc_vm_insn_load_upval(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); - uc_upvalref *ref = frame->closure->upvals[vm->arg.u32]; + uc_upvalref_t *ref = frame->closure->upvals[vm->arg.u32]; if (ref->closed) - uc_vm_stack_push(vm, uc_value_get(ref->value)); + uc_vm_stack_push(vm, ucv_get(ref->value)); else - uc_vm_stack_push(vm, uc_value_get(vm->stack.entries[ref->slot])); + uc_vm_stack_push(vm, ucv_get(vm->stack.entries[ref->slot])); } static void @@ -972,15 +1014,16 @@ uc_vm_insn_load_local(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); - uc_vm_stack_push(vm, uc_value_get(vm->stack.entries[frame->stackframe + vm->arg.u32])); + uc_vm_stack_push(vm, ucv_get(vm->stack.entries[frame->stackframe + vm->arg.u32])); } -static uc_upvalref * +static uc_upvalref_t * uc_vm_capture_upval(uc_vm *vm, size_t slot) { - uc_upvalref *curr = vm->open_upvals; - uc_upvalref *prev = NULL; - uc_upvalref *created; + uc_upvalref_t *curr = vm->open_upvals; + uc_upvalref_t *prev = NULL; + uc_upvalref_t *created; + char *s; while (curr && curr->slot > slot) { prev = curr; @@ -988,23 +1031,23 @@ uc_vm_capture_upval(uc_vm *vm, size_t slot) } if (curr && curr->slot == slot) { - if (vm->trace) - fprintf(stderr, " {+%zu} <%p> %s\n", - slot, - curr, - json_object_to_json_string(vm->stack.entries[slot])); + if (vm->trace) { + s = ucv_to_string(NULL, vm->stack.entries[slot]); + fprintf(stderr, " {+%zu} <%p> %s\n", slot, curr, s); + free(s); + } return curr; } - created = uc_upvalref_new(slot); + created = (uc_upvalref_t *)ucv_upvalref_new(slot); created->next = curr; - if (vm->trace) - fprintf(stderr, " {*%zu} <%p> %s\n", - slot, - created, - json_object_to_json_string(vm->stack.entries[slot])); + if (vm->trace) { + s = ucv_to_string(NULL, vm->stack.entries[slot]); + fprintf(stderr, " {*%zu} <%p> %s\n", slot, created, s); + free(s); + } if (prev) prev->next = created; @@ -1017,21 +1060,22 @@ uc_vm_capture_upval(uc_vm *vm, size_t slot) static void uc_vm_close_upvals(uc_vm *vm, size_t slot) { - uc_upvalref *ref; + uc_upvalref_t *ref; + char *s; while (vm->open_upvals && vm->open_upvals->slot >= slot) { ref = vm->open_upvals; - ref->value = uc_value_get(vm->stack.entries[ref->slot]); + ref->value = ucv_get(vm->stack.entries[ref->slot]); ref->closed = true; - if (vm->trace) - fprintf(stderr, " {!%zu} <%p> %s\n", - ref->slot, - ref, - json_object_to_json_string(ref->value)); + if (vm->trace) { + s = ucv_to_string(NULL, ref->value); + fprintf(stderr, " {!%zu} <%p> %s\n", ref->slot, ref, s); + free(s); + } vm->open_upvals = ref->next; - json_object_put(ref->header.jso); + ucv_put(&ref->header); } } @@ -1039,13 +1083,13 @@ static void uc_vm_insn_load_closure(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); - json_object *fno = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32); - uc_function *function = uc_object_as_function(fno); - uc_closure *closure = uc_closure_new(function, insn == I_ARFN); + uc_value_t *fno = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32); + uc_function_t *function = (uc_function_t *)fno; + uc_closure_t *closure = (uc_closure_t *)ucv_closure_new(vm, function, insn == I_ARFN); volatile int32_t uv; size_t i; - uc_vm_stack_push(vm, closure->header.jso); + uc_vm_stack_push(vm, &closure->header); for (i = 0; i < function->nupvals; i++) { uv = ( @@ -1060,7 +1104,7 @@ uc_vm_insn_load_closure(uc_vm *vm, enum insn_type insn) else closure->upvals[i] = frame->closure->upvals[uv]; - uc_value_get(closure->upvals[i]->header.jso); + ucv_get(&closure->upvals[i]->header); frame->ip += 4; } @@ -1069,23 +1113,26 @@ uc_vm_insn_load_closure(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_store_var(uc_vm *vm, enum insn_type insn) { - json_object *name, *v = uc_vm_stack_pop(vm); - uc_prototype *scope, *next; + uc_value_t *name, *v = uc_vm_stack_pop(vm); + uc_value_t *scope, *next; + bool found; scope = vm->globals; name = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32); - while (json_object_get_type(name) == json_type_string) { - if (json_object_object_get_ex(scope->header.jso, json_object_get_string(name), NULL)) + while (ucv_type(name) == UC_STRING) { + ucv_object_get(scope, ucv_string_get(name), &found); + + if (found) break; - next = scope->parent; + next = ucv_prototype_get(scope); if (!next) { if (vm->config->strict_declarations) { uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, "access to undeclared variable %s", - json_object_get_string(name)); + ucv_string_get(name)); } break; @@ -1094,53 +1141,45 @@ uc_vm_insn_store_var(uc_vm *vm, enum insn_type insn) scope = next; } - if (scope && json_object_get_type(name) == json_type_string) - json_object_object_add(scope->header.jso, json_object_get_string(name), uc_value_get(v)); + if (scope && ucv_type(name) == UC_STRING) + ucv_object_add(scope, ucv_string_get(name), ucv_get(v)); - uc_value_put(name); + ucv_put(name); uc_vm_stack_push(vm, v); } static void uc_vm_insn_store_val(uc_vm *vm, enum insn_type insn) { - json_object *v = uc_vm_stack_pop(vm); - json_object *k = uc_vm_stack_pop(vm); - json_object *o = uc_vm_stack_pop(vm); - - const char *typenames[] = { - [json_type_string] = "string", - [json_type_int] = "integer", - [json_type_double] = "double", - [json_type_boolean] = "boolean", - [json_type_null] = "null" - }; + uc_value_t *v = uc_vm_stack_pop(vm); + uc_value_t *k = uc_vm_stack_pop(vm); + uc_value_t *o = uc_vm_stack_pop(vm); - switch (json_object_get_type(o)) { - case json_type_object: - case json_type_array: - uc_vm_stack_push(vm, uc_setval(o, k, v)); + switch (ucv_type(o)) { + case UC_OBJECT: + case UC_ARRAY: + uc_vm_stack_push(vm, uc_setval(vm, o, k, v)); break; default: uc_vm_raise_exception(vm, EXCEPTION_TYPE, "attempt to set property on %s value", - typenames[json_object_get_type(o)]); + ucv_typename(o)); } - uc_value_put(o); - uc_value_put(k); + ucv_put(o); + ucv_put(k); } static void uc_vm_insn_store_upval(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); - uc_upvalref *ref = frame->closure->upvals[vm->arg.u32]; - json_object *val = uc_value_get(uc_vm_stack_peek(vm, 0)); + uc_upvalref_t *ref = frame->closure->upvals[vm->arg.u32]; + uc_value_t *val = ucv_get(uc_vm_stack_peek(vm, 0)); if (ref->closed) { - uc_value_put(ref->value); + ucv_put(ref->value); ref->value = val; } else { @@ -1152,43 +1191,43 @@ static void uc_vm_insn_store_local(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); - json_object *val = uc_value_get(uc_vm_stack_peek(vm, 0)); + uc_value_t *val = ucv_get(uc_vm_stack_peek(vm, 0)); uc_vm_stack_set(vm, frame->stackframe + vm->arg.u32, val); } -static json_object * -uc_vm_value_bitop(uc_vm *vm, enum insn_type operation, json_object *value, json_object *operand) +static uc_value_t * +uc_vm_value_bitop(uc_vm *vm, enum insn_type operation, uc_value_t *value, uc_value_t *operand) { - json_object *rv = NULL; + uc_value_t *rv = NULL; int64_t n1, n2; double d; - if (uc_cast_number(value, &n1, &d) == json_type_double) + if (uc_cast_number(value, &n1, &d) == UC_DOUBLE) n1 = isnan(d) ? 0 : (int64_t)d; - if (uc_cast_number(operand, &n2, &d) == json_type_double) + if (uc_cast_number(operand, &n2, &d) == UC_DOUBLE) n2 = isnan(d) ? 0 : (int64_t)d; switch (operation) { case I_LSHIFT: - rv = xjs_new_int64(n1 << n2); + rv = ucv_int64_new(n1 << n2); break; case I_RSHIFT: - rv = xjs_new_int64(n1 >> n2); + rv = ucv_int64_new(n1 >> n2); break; case I_BAND: - rv = xjs_new_int64(n1 & n2); + rv = ucv_int64_new(n1 & n2); break; case I_BXOR: - rv = xjs_new_int64(n1 ^ n2); + rv = ucv_int64_new(n1 ^ n2); break; case I_BOR: - rv = xjs_new_int64(n1 | n2); + rv = ucv_int64_new(n1 | n2); break; default: @@ -1198,32 +1237,32 @@ uc_vm_value_bitop(uc_vm *vm, enum insn_type operation, json_object *value, json_ return rv; } -static json_object * -uc_vm_value_arith(uc_vm *vm, enum insn_type operation, json_object *value, json_object *operand) +static uc_value_t * +uc_vm_value_arith(uc_vm *vm, enum insn_type operation, uc_value_t *value, uc_value_t *operand) { - json_object *rv = NULL; - enum json_type t1, t2; - const char *s1, *s2; + uc_value_t *rv = NULL; + uc_type_t t1, t2; + char *s, *s1, *s2; size_t len1, len2; int64_t n1, n2; double d1, d2; - char *s; if (operation > I_MOD) return uc_vm_value_bitop(vm, operation, value, operand); - if (operation == I_ADD && - (json_object_is_type(value, json_type_string) || - json_object_is_type(operand, json_type_string))) { - s1 = value ? json_object_get_string(value) : "null"; - s2 = operand ? json_object_get_string(operand) : "null"; - len1 = strlen(s1); - len2 = strlen(s2); + if (operation == I_ADD && (ucv_type(value) == UC_STRING || ucv_type(operand) == UC_STRING)) { + s1 = (ucv_type(value) != UC_STRING) ? ucv_to_string(vm, value) : NULL; + s2 = (ucv_type(operand) != UC_STRING) ? ucv_to_string(vm, operand) : NULL; + len1 = s1 ? strlen(s1) : ucv_string_length(value); + len2 = s2 ? strlen(s2) : ucv_string_length(operand); s = xalloc(len1 + len2 + 1); - snprintf(s, len1 + len2 + 1, "%s%s", s1, s2); + memcpy(s, s1 ? s1 : ucv_string_get(value), len1); + memcpy(s + len1, s2 ? s2 : ucv_string_get(operand), len2); + free(s1); + free(s2); - rv = xjs_new_string(s); + rv = ucv_string_new_length(s, len1 + len2); free(s); @@ -1233,38 +1272,38 @@ uc_vm_value_arith(uc_vm *vm, enum insn_type operation, json_object *value, json_ t1 = uc_cast_number(value, &n1, &d1); t2 = uc_cast_number(operand, &n2, &d2); - if (t1 == json_type_double || t2 == json_type_double) { - d1 = (t1 == json_type_double) ? d1 : (double)n1; - d2 = (t2 == json_type_double) ? d2 : (double)n2; + if (t1 == UC_DOUBLE || t2 == UC_DOUBLE) { + d1 = (t1 == UC_DOUBLE) ? d1 : (double)n1; + d2 = (t2 == UC_DOUBLE) ? d2 : (double)n2; switch (operation) { case I_ADD: case I_PLUS: - rv = uc_double_new(d1 + d2); + rv = ucv_double_new(d1 + d2); break; case I_SUB: - rv = uc_double_new(d1 - d2); + rv = ucv_double_new(d1 - d2); break; case I_MUL: - rv = uc_double_new(d1 * d2); + rv = ucv_double_new(d1 * d2); break; case I_DIV: if (d2 == 0.0) - rv = uc_double_new(INFINITY); + rv = ucv_double_new(INFINITY); else if (isnan(d2)) - rv = uc_double_new(NAN); + rv = ucv_double_new(NAN); else if (!isfinite(d2)) - rv = uc_double_new(isfinite(d1) ? 0.0 : NAN); + rv = ucv_double_new(isfinite(d1) ? 0.0 : NAN); else - rv = uc_double_new(d1 / d2); + rv = ucv_double_new(d1 / d2); break; case I_MOD: - rv = uc_double_new(NAN); + rv = ucv_double_new(NAN); break; default: @@ -1278,27 +1317,27 @@ uc_vm_value_arith(uc_vm *vm, enum insn_type operation, json_object *value, json_ switch (operation) { case I_ADD: case I_PLUS: - rv = xjs_new_int64(n1 + n2); + rv = ucv_int64_new(n1 + n2); break; case I_SUB: - rv = xjs_new_int64(n1 - n2); + rv = ucv_int64_new(n1 - n2); break; case I_MUL: - rv = xjs_new_int64(n1 * n2); + rv = ucv_int64_new(n1 * n2); break; case I_DIV: if (n2 == 0) - rv = uc_double_new(INFINITY); + rv = ucv_double_new(INFINITY); else - rv = xjs_new_int64(n1 / n2); + rv = ucv_int64_new(n1 / n2); break; case I_MOD: - rv = xjs_new_int64(n1 % n2); + rv = ucv_int64_new(n1 % n2); break; default: @@ -1315,25 +1354,28 @@ uc_vm_value_arith(uc_vm *vm, enum insn_type operation, json_object *value, json_ static void uc_vm_insn_update_var(uc_vm *vm, enum insn_type insn) { - json_object *name, *val, *inc = uc_vm_stack_pop(vm); - uc_prototype *scope, *next; + uc_value_t *name, *val, *inc = uc_vm_stack_pop(vm); + uc_value_t *scope, *next; + bool found; scope = vm->globals; name = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32 & 0x00FFFFFF); - assert(json_object_is_type(name, json_type_string)); + assert(ucv_type(name) == UC_STRING); + + while (true) { + val = ucv_object_get(scope, ucv_string_get(name), &found); - while (true) { - if (json_object_object_get_ex(scope->header.jso, json_object_get_string(name), &val)) + if (found) break; - next = scope->parent; + next = ucv_prototype_get(scope); if (!next) { if (vm->config->strict_declarations) { uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, "access to undeclared variable %s", - json_object_get_string(name)); + ucv_string_get(name)); } break; @@ -1344,26 +1386,26 @@ uc_vm_insn_update_var(uc_vm *vm, enum insn_type insn) val = uc_vm_value_arith(vm, vm->arg.u32 >> 24, val, inc); - json_object_object_add(scope->header.jso, json_object_get_string(name), uc_value_get(val)); + ucv_object_add(scope, ucv_string_get(name), ucv_get(val)); uc_vm_stack_push(vm, val); - uc_value_put(name); - uc_value_put(inc); + ucv_put(name); + ucv_put(inc); } static void uc_vm_insn_update_val(uc_vm *vm, enum insn_type insn) { - json_object *inc = uc_vm_stack_pop(vm); - json_object *k = uc_vm_stack_pop(vm); - json_object *v = uc_vm_stack_pop(vm); - json_object *val = NULL; + uc_value_t *inc = uc_vm_stack_pop(vm); + uc_value_t *k = uc_vm_stack_pop(vm); + uc_value_t *v = uc_vm_stack_pop(vm); + uc_value_t *val = NULL; - switch (json_object_get_type(v)) { - case json_type_object: - case json_type_array: - val = uc_getval(v, k); - uc_vm_stack_push(vm, uc_setval(v, k, uc_vm_value_arith(vm, vm->arg.u8, val, inc))); + switch (ucv_type(v)) { + case UC_OBJECT: + case UC_ARRAY: + val = uc_getval(vm, v, k); + uc_vm_stack_push(vm, uc_setval(vm, v, k, uc_vm_value_arith(vm, vm->arg.u8, val, inc))); break; default: @@ -1374,10 +1416,10 @@ uc_vm_insn_update_val(uc_vm *vm, enum insn_type insn) break; } - uc_value_put(val); - uc_value_put(inc); - uc_value_put(v); - uc_value_put(k); + ucv_put(val); + ucv_put(inc); + ucv_put(v); + ucv_put(k); } static void @@ -1385,9 +1427,9 @@ uc_vm_insn_update_upval(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); size_t slot = vm->arg.u32 & 0x00FFFFFF; - uc_upvalref *ref = frame->closure->upvals[slot]; - json_object *inc = uc_vm_stack_pop(vm); - json_object *val; + uc_upvalref_t *ref = frame->closure->upvals[slot]; + uc_value_t *inc = uc_vm_stack_pop(vm); + uc_value_t *val; if (ref->closed) val = ref->value; @@ -1398,14 +1440,14 @@ uc_vm_insn_update_upval(uc_vm *vm, enum insn_type insn) uc_vm_stack_push(vm, val); - uc_value_put(inc); + ucv_put(inc); if (ref->closed) { - uc_value_put(ref->value); - ref->value = uc_value_get(uc_vm_stack_peek(vm, 0)); + ucv_put(ref->value); + ref->value = ucv_get(uc_vm_stack_peek(vm, 0)); } else { - uc_vm_stack_set(vm, ref->slot, uc_value_get(uc_vm_stack_peek(vm, 0))); + uc_vm_stack_set(vm, ref->slot, ucv_get(uc_vm_stack_peek(vm, 0))); } } @@ -1414,22 +1456,22 @@ uc_vm_insn_update_local(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); size_t slot = vm->arg.u32 & 0x00FFFFFF; - json_object *inc = uc_vm_stack_pop(vm); - json_object *val; + uc_value_t *inc = uc_vm_stack_pop(vm); + uc_value_t *val; val = uc_vm_value_arith(vm, vm->arg.u32 >> 24, vm->stack.entries[frame->stackframe + slot], inc); uc_vm_stack_push(vm, val); - uc_value_put(inc); - uc_vm_stack_set(vm, frame->stackframe + slot, uc_value_get(uc_vm_stack_peek(vm, 0))); + ucv_put(inc); + uc_vm_stack_set(vm, frame->stackframe + slot, ucv_get(uc_vm_stack_peek(vm, 0))); } static void uc_vm_insn_narr(uc_vm *vm, enum insn_type insn) { - json_object *arr = xjs_new_array_size(vm->arg.u32); + uc_value_t *arr = ucv_array_new_length(vm, vm->arg.u32); uc_vm_stack_push(vm, arr); } @@ -1437,11 +1479,11 @@ uc_vm_insn_narr(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_parr(uc_vm *vm, enum insn_type insn) { - json_object *arr = uc_vm_stack_peek(vm, vm->arg.u32); + uc_value_t *arr = uc_vm_stack_peek(vm, vm->arg.u32); size_t idx; for (idx = 0; idx < vm->arg.u32; idx++) - json_object_array_add(arr, uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1)); + ucv_array_push(arr, uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1)); for (idx = 0; idx < vm->arg.u32; idx++) uc_vm_stack_pop(vm); @@ -1452,79 +1494,81 @@ uc_vm_insn_parr(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_marr(uc_vm *vm, enum insn_type insn) { - json_object *src = uc_vm_stack_pop(vm); - json_object *dst = uc_vm_stack_peek(vm, 0); + uc_value_t *src = uc_vm_stack_pop(vm); + uc_value_t *dst = uc_vm_stack_peek(vm, 0); size_t i; + char *s; - if (!json_object_is_type(src, json_type_array)) { - uc_vm_raise_exception(vm, EXCEPTION_TYPE, - "(%s) is not iterable", - json_object_to_json_string(src)); + if (ucv_type(src) != UC_ARRAY) { + s = ucv_to_string(vm, src); + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "(%s) is not iterable", s); + ucv_put(src); + free(s); return; } - for (i = 0; i < json_object_array_length(src); i++) - json_object_array_add(dst, uc_value_get(json_object_array_get_idx(src, i))); + for (i = 0; i < ucv_array_length(src); i++) + ucv_array_push(dst, ucv_get(ucv_array_get(src, i))); - uc_value_put(src); + ucv_put(src); } static void uc_vm_insn_nobj(uc_vm *vm, enum insn_type insn) { - json_object *arr = xjs_new_object(); + uc_value_t *obj = ucv_object_new(vm); - uc_vm_stack_push(vm, arr); + uc_vm_stack_push(vm, obj); } static void uc_vm_insn_sobj(uc_vm *vm, enum insn_type insn) { - json_object *obj = uc_vm_stack_peek(vm, vm->arg.u32); + uc_value_t *obj = uc_vm_stack_peek(vm, vm->arg.u32); size_t idx; for (idx = 0; idx < vm->arg.u32; idx += 2) { - json_object_object_add(obj, - json_object_get_string(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1)), - uc_value_get(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 2))); + ucv_object_add(obj, + ucv_string_get(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1)), + ucv_get(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 2))); } for (idx = 0; idx < vm->arg.u32; idx++) - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); } static void uc_vm_insn_mobj(uc_vm *vm, enum insn_type insn) { - json_object *src = uc_vm_stack_pop(vm); - json_object *dst = uc_vm_stack_peek(vm, 0); - char *istr; + uc_value_t *src = uc_vm_stack_pop(vm); + uc_value_t *dst = uc_vm_stack_peek(vm, 0); size_t i; + char *s; - switch (json_object_get_type(src)) { - case json_type_object: + switch (ucv_type(src)) { + case UC_OBJECT: ; /* a label can only be part of a statement and a declaration is not a statement */ - json_object_object_foreach(src, k, v) - json_object_object_add(dst, k, uc_value_get(v)); + ucv_object_foreach(src, k, v) + ucv_object_add(dst, k, ucv_get(v)); - uc_value_put(src); + ucv_put(src); break; case json_type_array: - for (i = 0; i < json_object_array_length(src); i++) { - xasprintf(&istr, "%zu", i); - json_object_object_add(dst, istr, uc_value_get(json_object_array_get_idx(src, i))); - free(istr); + for (i = 0; i < ucv_array_length(src); i++) { + xasprintf(&s, "%zu", i); + ucv_object_add(dst, s, ucv_get(ucv_array_get(src, i))); + free(s); } - uc_value_put(src); + ucv_put(src); break; default: - uc_vm_raise_exception(vm, EXCEPTION_TYPE, - "Value (%s) is not iterable", - json_object_to_json_string(src)); + s = ucv_to_string(vm, src); + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Value (%s) is not iterable", s); + free(s); break; } @@ -1533,14 +1577,14 @@ uc_vm_insn_mobj(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_arith(uc_vm *vm, enum insn_type insn) { - json_object *r2 = uc_vm_stack_pop(vm); - json_object *r1 = uc_vm_stack_pop(vm); - json_object *rv; + uc_value_t *r2 = uc_vm_stack_pop(vm); + uc_value_t *r1 = uc_vm_stack_pop(vm); + uc_value_t *rv; rv = uc_vm_value_arith(vm, insn, r1, r2); - uc_value_put(r1); - uc_value_put(r2); + ucv_put(r1); + ucv_put(r2); uc_vm_stack_push(vm, rv); } @@ -1548,23 +1592,23 @@ uc_vm_insn_arith(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_plus_minus(uc_vm *vm, enum insn_type insn) { - struct json_object *v = uc_vm_stack_pop(vm); + uc_value_t *v = uc_vm_stack_pop(vm); bool is_sub = (insn == I_MINUS); - enum json_type t; + uc_type_t t; int64_t n; double d; t = uc_cast_number(v, &n, &d); - json_object_put(v); + ucv_put(v); switch (t) { - case json_type_int: - uc_vm_stack_push(vm, xjs_new_int64(is_sub ? -n : n)); + case UC_INTEGER: + uc_vm_stack_push(vm, ucv_int64_new(is_sub ? -n : n)); break; default: - uc_vm_stack_push(vm, uc_double_new(is_sub ? -d : d)); + uc_vm_stack_push(vm, ucv_double_new(is_sub ? -d : d)); break; } } @@ -1572,14 +1616,14 @@ uc_vm_insn_plus_minus(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_bitop(uc_vm *vm, enum insn_type insn) { - json_object *r2 = uc_vm_stack_pop(vm); - json_object *r1 = uc_vm_stack_pop(vm); - json_object *rv; + uc_value_t *r2 = uc_vm_stack_pop(vm); + uc_value_t *r1 = uc_vm_stack_pop(vm); + uc_value_t *rv; rv = uc_vm_value_bitop(vm, insn, r1, r2); - uc_value_put(r1); - uc_value_put(r2); + ucv_put(r1); + ucv_put(r2); uc_vm_stack_push(vm, rv); } @@ -1587,23 +1631,23 @@ uc_vm_insn_bitop(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_complement(uc_vm *vm, enum insn_type insn) { - struct json_object *v = uc_vm_stack_pop(vm); + uc_value_t *v = uc_vm_stack_pop(vm); int64_t n; double d; - if (uc_cast_number(v, &n, &d) == json_type_double) + if (uc_cast_number(v, &n, &d) == UC_DOUBLE) n = isnan(d) ? 0 : (int64_t)d; - json_object_put(v); + ucv_put(v); - uc_vm_stack_push(vm, xjs_new_int64(~n)); + uc_vm_stack_push(vm, ucv_int64_new(~n)); } static void uc_vm_insn_rel(uc_vm *vm, enum insn_type insn) { - json_object *r2 = uc_vm_stack_pop(vm); - json_object *r1 = uc_vm_stack_pop(vm); + uc_value_t *r2 = uc_vm_stack_pop(vm); + uc_value_t *r1 = uc_vm_stack_pop(vm); bool res = false; switch (insn) { @@ -1627,27 +1671,27 @@ uc_vm_insn_rel(uc_vm *vm, enum insn_type insn) break; } - uc_value_put(r1); - uc_value_put(r2); + ucv_put(r1); + ucv_put(r2); - uc_vm_stack_push(vm, xjs_new_boolean(res)); + uc_vm_stack_push(vm, ucv_boolean_new(res)); } static void uc_vm_insn_in(uc_vm *vm, enum insn_type insn) { - json_object *r2 = uc_vm_stack_pop(vm); - json_object *r1 = uc_vm_stack_pop(vm); - json_object *item; + uc_value_t *r2 = uc_vm_stack_pop(vm); + uc_value_t *r1 = uc_vm_stack_pop(vm); + uc_value_t *item; size_t arrlen, arridx; bool found = false; - const char *key; + char *key; - switch (json_object_get_type(r2)) { - case json_type_array: - for (arridx = 0, arrlen = json_object_array_length(r2); + switch (ucv_type(r2)) { + case UC_ARRAY: + for (arridx = 0, arrlen = ucv_array_length(r2); arridx < arrlen; arridx++) { - item = json_object_array_get_idx(r2, arridx); + item = ucv_array_get(r2, arridx); if (uc_cmp(TK_EQ, r1, item)) { found = true; @@ -1657,41 +1701,53 @@ uc_vm_insn_in(uc_vm *vm, enum insn_type insn) break; - case json_type_object: - key = r1 ? json_object_get_string(r1) : "null"; - found = json_object_object_get_ex(r2, key, NULL); + case UC_OBJECT: + if (ucv_type(r1) == UC_STRING) { + ucv_object_get(r2, ucv_string_get(r1), &found); + } + else { + key = ucv_to_string(vm, r1); + ucv_object_get(r2, key, &found); + free(key); + } + break; default: found = false; } - uc_value_put(r1); - uc_value_put(r2); + ucv_put(r1); + ucv_put(r2); - uc_vm_stack_push(vm, xjs_new_boolean(found)); + uc_vm_stack_push(vm, ucv_boolean_new(found)); } static void uc_vm_insn_equality(uc_vm *vm, enum insn_type insn) { - json_object *r2 = uc_vm_stack_pop(vm); - json_object *r1 = uc_vm_stack_pop(vm); - bool equal = uc_eq(r1, r2); + uc_value_t *r2 = uc_vm_stack_pop(vm); + uc_value_t *r1 = uc_vm_stack_pop(vm); + bool equal; + + if (ucv_is_scalar(r1) && ucv_is_scalar(r2)) + equal = ucv_equal(r1, r2); + else + equal = (r1 == r2); - uc_value_put(r1); - uc_value_put(r2); + ucv_put(r1); + ucv_put(r2); - uc_vm_stack_push(vm, xjs_new_boolean((insn == I_EQS) ? equal : !equal)); + uc_vm_stack_push(vm, ucv_boolean_new((insn == I_EQS) ? equal : !equal)); } static void uc_vm_insn_not(uc_vm *vm, enum insn_type insn) { - json_object *r1 = uc_vm_stack_pop(vm); + uc_value_t *r1 = uc_vm_stack_pop(vm); - uc_vm_stack_push(vm, xjs_new_boolean(!uc_val_is_truish(r1))); - uc_value_put(r1); + uc_vm_stack_push(vm, ucv_boolean_new(!uc_val_is_truish(r1))); + ucv_put(r1); } static void @@ -1718,7 +1774,7 @@ uc_vm_insn_jmpz(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); uc_chunk *chunk = uc_vm_frame_chunk(frame); - json_object *v = uc_vm_stack_pop(vm); + uc_value_t *v = uc_vm_stack_pop(vm); int32_t addr = vm->arg.s32; /* ip already has been incremented */ @@ -1733,56 +1789,64 @@ uc_vm_insn_jmpz(uc_vm *vm, enum insn_type insn) if (!uc_val_is_truish(v)) frame->ip += addr; - uc_value_put(v); + ucv_put(v); } static void uc_vm_insn_next(uc_vm *vm, enum insn_type insn) { - json_object *k = uc_vm_stack_pop(vm); - json_object *v = uc_vm_stack_pop(vm); + uc_value_t *k = uc_vm_stack_pop(vm); + uc_value_t *v = uc_vm_stack_pop(vm); + void *end = (void *)~(uintptr_t)0; + uc_ressource_t *iterk; struct lh_entry *curr; - int64_t n; + uint64_t n; + + if (k != NULL && ucv_type(k) != UC_RESSOURCE) { + fprintf(stderr, "Invalid iterator value\n"); + abort(); + } + + if (k == NULL) { + k = ucv_ressource_new(NULL, NULL); + ((uc_ressource_t *)k)->type = UINT64_MAX; + } - switch (json_object_get_type(v)) { - case json_type_object: - curr = k ? json_object_get_userdata(k) : json_object_get_object(v)->head; + iterk = (uc_ressource_t *)k; - if (curr) { - if (!k) - k = xjs_new_string("[key]"); + switch (ucv_type(v)) { + case UC_OBJECT: + curr = iterk->data ? iterk->data : ((uc_object_t *)v)->table->head; - json_object_set_userdata(k, curr->next, NULL); + if (curr != NULL && curr != end) { + iterk->data = curr->next ? curr->next : end; - uc_vm_stack_push(vm, xjs_new_string(curr->k)); + uc_vm_stack_push(vm, ucv_string_new(curr->k)); if (insn == I_NEXTKV) - uc_vm_stack_push(vm, uc_value_get((json_object *)curr->v)); + uc_vm_stack_push(vm, ucv_get((uc_value_t *)curr->v)); uc_vm_stack_push(vm, k); - uc_value_put(v); + ucv_put(v); return; } break; - case json_type_array: - if (!k) - k = xjs_new_int64(0); - - n = json_object_get_int64(k); + case UC_ARRAY: + n = (uintptr_t)iterk->data; - if (json_object_is_type(k, json_type_int) && n < json_object_array_length(v)) { - json_object_int_inc(k, 1); + if (n < ucv_array_length(v)) { + iterk->data = (void *)(n + 1); if (insn == I_NEXTKV) - uc_vm_stack_push(vm, xjs_new_int64(n)); + uc_vm_stack_push(vm, ucv_uint64_new(n)); - uc_vm_stack_push(vm, uc_value_get(json_object_array_get_idx(v, n))); + uc_vm_stack_push(vm, ucv_get(ucv_array_get(v, n))); uc_vm_stack_push(vm, k); - uc_value_put(v); + ucv_put(v); return; } @@ -1799,87 +1863,83 @@ uc_vm_insn_next(uc_vm *vm, enum insn_type insn) if (insn == I_NEXTKV) uc_vm_stack_push(vm, NULL); - uc_value_put(k); - uc_value_put(v); + ucv_put(k); + ucv_put(v); } static void uc_vm_insn_close_upval(uc_vm *vm, enum insn_type insn) { uc_vm_close_upvals(vm, vm->stack.count - 1); - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); } static void uc_vm_insn_call(uc_vm *vm, enum insn_type insn) { - json_object *fno = uc_value_get(uc_vm_stack_peek(vm, vm->arg.u32 & 0xffff)); - json_object *ctx = NULL; + uc_value_t *fno = ucv_get(uc_vm_stack_peek(vm, vm->arg.u32 & 0xffff)); + uc_value_t *ctx = NULL; - if (!uc_object_is_type(fno, UC_OBJ_CLOSURE) || !uc_object_as_closure(fno)->is_arrow) + if (!ucv_is_arrowfn(fno)) ctx = NULL; else if (vm->callframes.count > 0) - ctx = uc_value_get(uc_vm_current_frame(vm)->ctx); + ctx = uc_vm_current_frame(vm)->ctx; - uc_vm_call_function(vm, ctx, fno, false, vm->arg.u32); + uc_vm_call_function(vm, ucv_get(ctx), fno, false, vm->arg.u32); } static void uc_vm_insn_mcall(uc_vm *vm, enum insn_type insn) { size_t key_slot = vm->stack.count - (vm->arg.u32 & 0xffff) - 1; - json_object *ctx = vm->stack.entries[key_slot - 1]; - json_object *key = vm->stack.entries[key_slot]; - json_object *fno = uc_getval(ctx, key); + uc_value_t *ctx = vm->stack.entries[key_slot - 1]; + uc_value_t *key = vm->stack.entries[key_slot]; + uc_value_t *fno = uc_getval(vm, ctx, key); uc_vm_stack_set(vm, key_slot, fno); /* arrow functions as method calls inherit the parent ctx */ - if (uc_object_is_type(fno, UC_OBJ_CLOSURE) && uc_object_as_closure(fno)->is_arrow) + if (ucv_is_arrowfn(fno)) ctx = uc_vm_current_frame(vm)->ctx; - uc_vm_call_function(vm, uc_value_get(ctx), uc_value_get(fno), true, vm->arg.u32); + uc_vm_call_function(vm, ucv_get(ctx), ucv_get(fno), true, vm->arg.u32); } static void uc_vm_insn_print(uc_vm *vm, enum insn_type insn) { - json_object *v = uc_vm_stack_pop(vm); - const char *p; - size_t len; + uc_value_t *v = uc_vm_stack_pop(vm); + char *p; - switch (json_object_get_type(v)) { - case json_type_object: - case json_type_array: - p = json_object_to_json_string_ext(v, JSON_C_TO_STRING_NOSLASHESCAPE|JSON_C_TO_STRING_SPACED); - len = strlen(p); + switch (ucv_type(v)) { + case UC_OBJECT: + case UC_ARRAY: + p = ucv_to_jsonstring(vm, v); + fwrite(p, 1, strlen(p), stdout); + free(p); break; - case json_type_string: - p = json_object_get_string(v); - len = json_object_get_string_len(v); + case UC_STRING: + fwrite(ucv_string_get(v), 1, ucv_string_length(v), stdout); break; - case json_type_null: - p = ""; - len = 0; + case UC_NULL: break; default: - p = json_object_get_string(v); - len = strlen(p); + p = ucv_to_string(vm, v); + fwrite(p, 1, strlen(p), stdout); + free(p); } - fwrite(p, 1, len, stdout); - - uc_value_put(v); + ucv_put(v); } -static json_object * +static uc_value_t * uc_vm_callframe_pop(uc_vm *vm) { uc_callframe *frame = uc_vm_current_frame(vm); - json_object *retval; + uc_value_t *retval; /* close upvalues */ uc_vm_close_upvals(vm, frame->stackframe); @@ -1891,18 +1951,18 @@ uc_vm_callframe_pop(uc_vm *vm) /* reset function stack frame */ while (vm->stack.count > frame->stackframe) - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); /* for method calls, release context as well */ if (frame->mcall) - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); /* release function */ - uc_value_put(frame->closure ? frame->closure->header.jso : NULL); - uc_value_put(frame->cfunction ? frame->cfunction->header.jso : NULL); + ucv_put((uc_value_t *)frame->closure); + ucv_put((uc_value_t *)frame->cfunction); /* release context */ - uc_value_put(frame->ctx); + ucv_put(frame->ctx); vm->callframes.count--; @@ -1920,9 +1980,9 @@ uc_vm_output_exception(uc_vm *vm) vm->exception.message); fprintf(stderr, "%s\n\n", - json_object_get_string( - json_object_object_get( - json_object_array_get_idx(vm->exception.stacktrace, 0), "context"))); + ucv_string_get( + ucv_object_get( + ucv_array_get(vm->exception.stacktrace, 0), "context", NULL))); } static uc_vm_status_t @@ -1930,7 +1990,7 @@ uc_vm_execute_chunk(uc_vm *vm) { uc_callframe *frame = uc_vm_current_frame(vm); uc_chunk *chunk = uc_vm_frame_chunk(frame); - json_object *retval; + uc_value_t *retval; enum insn_type insn; while (chunk) { @@ -1961,7 +2021,7 @@ uc_vm_execute_chunk(uc_vm *vm) break; case I_LTHIS: - uc_vm_stack_push(vm, uc_value_get(frame->ctx)); + uc_vm_stack_push(vm, ucv_get(frame->ctx)); break; case I_LVAR: @@ -2100,11 +2160,11 @@ uc_vm_execute_chunk(uc_vm *vm) break; case I_COPY: - uc_vm_stack_push(vm, uc_value_get(uc_vm_stack_peek(vm, vm->arg.u8))); + uc_vm_stack_push(vm, ucv_get(uc_vm_stack_peek(vm, vm->arg.u8))); break; case I_POP: - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); break; case I_CUPV: @@ -2127,7 +2187,7 @@ uc_vm_execute_chunk(uc_vm *vm) retval = uc_vm_callframe_pop(vm); if (vm->callframes.count == 0) { - uc_value_put(retval); + ucv_put(retval); return STATUS_OK; } @@ -2163,7 +2223,7 @@ uc_vm_execute_chunk(uc_vm *vm) return ERROR_RUNTIME; /* no exception handler in current function, pop callframe */ - uc_value_put(uc_vm_callframe_pop(vm)); + ucv_put(uc_vm_callframe_pop(vm)); /* resume execution at topmost remaining callframe */ frame = uc_vector_last(&vm->callframes); @@ -2176,25 +2236,25 @@ uc_vm_execute_chunk(uc_vm *vm) } static uc_vm_status_t -uc_vm_preload(uc_vm *vm, json_object *modules) +uc_vm_preload(uc_vm *vm, uc_value_t *modules) { - json_object *requirefn, *module, *name; + uc_value_t *requirefn, *module, *name; uc_exception_type_t ex; size_t i; - if (!json_object_is_type(modules, json_type_array)) + if (ucv_type(modules) != UC_ARRAY) return STATUS_OK; - requirefn = uc_prototype_lookup(vm->globals, "require"); + requirefn = ucv_property_get(vm->globals, "require"); - if (!uc_object_is_type(requirefn, UC_OBJ_CFUNCTION)) + if (ucv_type(requirefn) != UC_CFUNCTION) return STATUS_OK; - for (i = 0; i < json_object_array_length(modules); i++) { - name = json_object_array_get_idx(modules, i); + for (i = 0; i < ucv_array_length(modules); i++) { + name = ucv_array_get(modules, i); - uc_vm_stack_push(vm, uc_value_get(requirefn)); - uc_vm_stack_push(vm, uc_value_get(name)); + uc_vm_stack_push(vm, ucv_get(requirefn)); + uc_vm_stack_push(vm, ucv_get(name)); ex = uc_vm_call(vm, false, 1); @@ -2203,21 +2263,22 @@ uc_vm_preload(uc_vm *vm, json_object *modules) module = uc_vm_stack_pop(vm); - uc_value_put(uc_setval(vm->globals->header.jso, name, module)); + ucv_put(uc_setval(vm, vm->globals, name, module)); } return STATUS_OK; } uc_vm_status_t -uc_vm_execute(uc_vm *vm, uc_function *fn, uc_prototype *globals, json_object *modules) +uc_vm_execute(uc_vm *vm, uc_function_t *fn, uc_value_t *globals, uc_value_t *modules) { - uc_closure *closure = uc_closure_new(fn, false); + uc_closure_t *closure = (uc_closure_t *)ucv_closure_new(vm, fn, false); uc_callframe *frame; + uc_stringbuf_t *buf; uc_vm_status_t rv; vm->globals = globals; - uc_value_get(globals ? globals->header.jso : NULL); + ucv_get(globals); uc_vector_grow(&vm->callframes); @@ -2227,14 +2288,12 @@ uc_vm_execute(uc_vm *vm, uc_function *fn, uc_prototype *globals, json_object *mo frame->ip = uc_vm_frame_chunk(frame)->entries; if (vm->trace) { - size_t msglen = 0; - char *msg = NULL; + buf = xprintbuf_new(); - format_source_context(&msg, &msglen, - fn->source, 0, true); + format_source_context(buf, fn->source, 0, true); - fprintf(stderr, "%s", msg); - free(msg); + fwrite(buf->buf, 1, printbuf_length(buf), stderr); + printbuf_free(buf); uc_vm_frame_dump(vm, frame); } @@ -2249,7 +2308,7 @@ uc_vm_execute(uc_vm *vm, uc_function *fn, uc_prototype *globals, json_object *mo else rv = uc_vm_execute_chunk(vm); - uc_value_put(vm->globals->header.jso); + ucv_put(vm->globals); vm->globals = NULL; return rv; @@ -2258,11 +2317,11 @@ uc_vm_execute(uc_vm *vm, uc_function *fn, uc_prototype *globals, json_object *mo uc_exception_type_t uc_vm_call(uc_vm *vm, bool mcall, size_t nargs) { - json_object *ctx = mcall ? uc_value_get(uc_vm_stack_peek(vm, nargs - 1)) : NULL; - json_object *fno = uc_value_get(uc_vm_stack_peek(vm, nargs)); + uc_value_t *ctx = mcall ? ucv_get(uc_vm_stack_peek(vm, nargs + 1)) : NULL; + uc_value_t *fno = ucv_get(uc_vm_stack_peek(vm, nargs)); if (uc_vm_call_function(vm, ctx, fno, mcall, nargs & 0xffff)) { - if (!uc_object_is_type(fno, UC_OBJ_CFUNCTION)) + if (ucv_type(fno) != UC_CFUNCTION) uc_vm_execute_chunk(vm); } -- cgit v1.2.3 From 28825acae8ee95543d4dc4f2c38e9711d4d4a420 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Mon, 26 Apr 2021 13:46:26 +0200 Subject: types: support creating ressource values without associated type Signed-off-by: Jo-Philipp Wich --- types.c | 4 ++-- vm.c | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'vm.c') diff --git a/types.c b/types.c index 1247268..4e17025 100644 --- a/types.c +++ b/types.c @@ -963,7 +963,7 @@ ucv_ressource_type_add(const char *name, uc_value_t *proto, void (*freefn)(void static uc_ressource_type_t * ucv_ressource_type_get(size_t type) { - return (type < res_types.count) ? &res_types.entries[type] : NULL; + return (type > 0 && type <= res_types.count) ? &res_types.entries[type - 1] : NULL; } uc_ressource_type_t * @@ -987,7 +987,7 @@ ucv_ressource_new(uc_ressource_type_t *type, void *data) res = xalloc(sizeof(*res)); res->header.type = UC_RESSOURCE; res->header.refcount = 1; - res->type = type - res_types.entries; + res->type = type ? (type - res_types.entries) + 1 : 0; res->data = data; return &res->header; diff --git a/vm.c b/vm.c index 10e3286..88c537c 100644 --- a/vm.c +++ b/vm.c @@ -1807,10 +1807,8 @@ uc_vm_insn_next(uc_vm *vm, enum insn_type insn) abort(); } - if (k == NULL) { + if (k == NULL) k = ucv_ressource_new(NULL, NULL); - ((uc_ressource_t *)k)->type = UINT64_MAX; - } iterk = (uc_ressource_t *)k; -- cgit v1.2.3 From d5dd183f3622002fbc4ae175045a3ebce4eeeb05 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Mon, 26 Apr 2021 14:16:25 +0200 Subject: treewide: address various sign-compare warnings Signed-off-by: Jo-Philipp Wich --- lib.c | 4 ++-- types.c | 4 ++-- value.c | 8 ++++---- vm.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'vm.c') diff --git a/lib.c b/lib.c index 5733646..80c1386 100644 --- a/lib.c +++ b/lib.c @@ -888,7 +888,7 @@ uc_splice(uc_vm *vm, size_t nargs) if (remlen < 0) remlen = 0; } - else if ((uint64_t)remlen > arrlen - ofs) { + else if ((uint64_t)remlen > arrlen - (uint64_t)ofs) { remlen = arrlen - ofs; } @@ -1025,7 +1025,7 @@ uc_substr(uc_vm *vm, size_t nargs) if (sublen < 0) sublen = 0; } - else if ((uint64_t)sublen > len - ofs) { + else if ((uint64_t)sublen > len - (uint64_t)ofs) { sublen = len - ofs; } diff --git a/types.c b/types.c index 4e17025..e786fb1 100644 --- a/types.c +++ b/types.c @@ -356,7 +356,7 @@ ucv_stringbuf_new(void) } }; - printbuf_memappend_fast(sb, (char *)&ustr, sizeof(ustr)); + printbuf_memappend_fast(sb, (char *)&ustr, (int)sizeof(ustr)); return sb; } @@ -1397,7 +1397,7 @@ ucv_call_tostring(uc_vm *vm, uc_stringbuf_t *pb, uc_value_t *uv, bool json) void _ucv_stringbuf_append(uc_stringbuf_t *pb, const char *str, size_t len) { - printbuf_memappend_fast(pb, str, len); + printbuf_memappend_fast(pb, str, (int)len); } void diff --git a/value.c b/value.c index 5fafefa..e53e317 100644 --- a/value.c +++ b/value.c @@ -348,7 +348,7 @@ add_num(uc_value_list *list, int64_t n) list->index[list->isize++] = (TAG_TYPE)(TAG_NUM | TAG_SET_NV(n)); } else { - if (list->dsize + sz > TAG_MASK) { + if ((TAG_TYPE)list->dsize + sz > TAG_MASK) { fprintf(stderr, "Constant data too large\n"); abort(); } @@ -400,7 +400,7 @@ add_dbl(uc_value_list *list, double d) { size_t sz = TAG_ALIGN(sizeof(d)); - if (list->dsize + sz > TAG_MASK) { + if ((TAG_TYPE)list->dsize + sz > TAG_MASK) { fprintf(stderr, "Constant data too large\n"); abort(); } @@ -450,7 +450,7 @@ add_str(uc_value_list *list, const char *s, size_t slen) sz = TAG_ALIGN(sizeof(uint32_t) + slen); - if (list->dsize + sz > TAG_MASK) { + if ((TAG_TYPE)list->dsize + sz > TAG_MASK) { fprintf(stderr, "Constant data too large\n"); abort(); } @@ -528,7 +528,7 @@ add_ptr(uc_value_list *list, void *ptr) { size_t sz = TAG_ALIGN(sizeof(ptr)); - if (list->dsize + sz > TAG_MASK) { + if ((TAG_TYPE)list->dsize + sz > TAG_MASK) { fprintf(stderr, "Constant data too large\n"); abort(); } diff --git a/vm.c b/vm.c index 88c537c..f7d2e09 100644 --- a/vm.c +++ b/vm.c @@ -1836,7 +1836,7 @@ uc_vm_insn_next(uc_vm *vm, enum insn_type insn) n = (uintptr_t)iterk->data; if (n < ucv_array_length(v)) { - iterk->data = (void *)(n + 1); + iterk->data = (void *)(uintptr_t)(n + 1); if (insn == I_NEXTKV) uc_vm_stack_push(vm, ucv_uint64_new(n)); -- cgit v1.2.3 From 9ef693edd6c9572c0ab0b1381fe5e65a8430e8fb Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Mon, 26 Apr 2021 20:05:51 +0200 Subject: vm: improve context for early errors Print "Before start of program" for errors that are raised before entering main(), e.g. on module preloading failure. Signed-off-by: Jo-Philipp Wich --- tests/cram/test_basic.t | 4 ++-- vm.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'vm.c') diff --git a/tests/cram/test_basic.t b/tests/cram/test_basic.t index 5061d37..982d58a 100644 --- a/tests/cram/test_basic.t +++ b/tests/cram/test_basic.t @@ -37,13 +37,13 @@ check that ucode provides proper error messages: $ ucode -m foo -s '' Runtime error: No module named 'foo' could be found - At offset 0 + At start of program [1] $ touch moo; ucode -m foo -i moo Runtime error: No module named 'foo' could be found - At offset 0 + At start of program [1] diff --git a/vm.c b/vm.c index f7d2e09..7d60805 100644 --- a/vm.c +++ b/vm.c @@ -842,8 +842,10 @@ uc_vm_get_error_context(uc_vm *vm) if (offset) format_error_context(buf, frame->closure->function->source, stacktrace, offset); + else if (frame->ip != chunk->entries) + ucv_stringbuf_printf(buf, "At instruction %zu", (frame->ip - chunk->entries) - 1); else - ucv_stringbuf_printf(buf, "At offset %zu", (frame->ip - chunk->entries) - 1); + ucv_stringbuf_append(buf, "At start of program"); ucv_object_add(ucv_array_get(stacktrace, 0), "context", ucv_stringbuf_finish(buf)); -- cgit v1.2.3 From 64eec7f90e945696572ee076b75d1f35e8f2248a Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Tue, 27 Apr 2021 00:35:20 +0200 Subject: treewide: ISO C / pedantic compliance - Shuffle typedefs to avoid need for non-compliant forward declarations - Fix non-compliant empty struct initializers - Remove use of braced expressions - Remove use of anonymous unions - Avoid `void *` pointer arithmetic - Fix several warnings reported by gcc -pedantic mode and clang 11 compilation Signed-off-by: Jo-Philipp Wich --- CMakeLists.txt | 5 +- chunk.h | 28 +--------- compiler.c | 33 ++++++----- lexer.c | 77 +++++++++++++------------- lexer.h | 6 -- lib.c | 52 +++++++++++------ lib/uci.c | 14 ++--- main.c | 9 ++- source.h | 10 +--- tests/cram/test_basic.t | 5 +- types.c | 11 ++-- types.h | 144 +++++++++++++++++++++++++++++++++++++++++++----- util.h | 2 + value.c | 2 +- value.h | 15 +---- vm.c | 37 +++++++------ vm.h | 49 +--------------- 17 files changed, 278 insertions(+), 221 deletions(-) (limited to 'vm.c') diff --git a/CMakeLists.txt b/CMakeLists.txt index c6bfec9..0d5fe54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,8 +107,9 @@ IF(UNIT_TESTING) LIST(APPEND CMAKE_CTEST_ARGUMENTS "--output-on-failure") IF(CMAKE_C_COMPILER_ID STREQUAL "Clang") - ADD_EXECUTABLE(ucode-san ${UCODE_SOURCES}) - TARGET_LINK_LIBRARIES(ucode-san ${json}) + ADD_EXECUTABLE(ucode-san ${UCODE_SOURCES}) + SET_PROPERTY(TARGET ucode-san PROPERTY ENABLE_EXPORTS 1) + TARGET_LINK_LIBRARIES(ucode-san ${json}) TARGET_COMPILE_OPTIONS(ucode-san PRIVATE -g -fno-omit-frame-pointer -fsanitize=undefined,address,leak -fno-sanitize-recover=all) TARGET_LINK_OPTIONS(ucode-san PRIVATE -fsanitize=undefined,address,leak) ENDIF() diff --git a/chunk.h b/chunk.h index cad00f7..2a8fa3a 100644 --- a/chunk.h +++ b/chunk.h @@ -22,38 +22,12 @@ #include "value.h" #include "util.h" - - -typedef struct { - size_t from, to, target, slot; -} uc_ehrange; - -typedef struct { - size_t from, to, slot, nameidx; -} uc_varrange; - -uc_declare_vector(uc_ehranges, uc_ehrange); -uc_declare_vector(uc_variables, uc_varrange); -uc_declare_vector(uc_offsetinfo, uint8_t); - -typedef struct { - size_t count; - uint8_t *entries; - uc_value_list constants; - uc_ehranges ehranges; - struct { - uc_variables variables; - uc_value_list varnames; - uc_offsetinfo offsets; - } debuginfo; -} uc_chunk; +#include "types.h" void uc_chunk_init(uc_chunk *chunk); void uc_chunk_free(uc_chunk *chunk); size_t uc_chunk_add(uc_chunk *chunk, uint8_t byte, size_t line); -typedef struct uc_value_t uc_value_t; - ssize_t uc_chunk_add_constant(uc_chunk *chunk, uc_value_t *value); uc_value_t *uc_chunk_get_constant(uc_chunk *chunk, size_t idx); void uc_chunk_pop(uc_chunk *chunk); diff --git a/compiler.c b/compiler.c index 04ff8ee..fd5b3af 100644 --- a/compiler.c +++ b/compiler.c @@ -468,7 +468,12 @@ uc_compiler_emit_s32(uc_compiler *compiler, size_t srcpos, int32_t n) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t lineoff = uc_compiler_set_srcpos(compiler, srcpos); - uint32_t v = n + 0x7fffffff; + uint32_t v; + + if (n <= 0) + v = n + 0x7fffffff; + else + v = (uint32_t)n + 0x7fffffff; uc_chunk_add(chunk, v / 0x1000000, lineoff); uc_chunk_add(chunk, (v / 0x10000) % 0x100, 0); @@ -555,9 +560,9 @@ uc_compiler_get_jmpaddr(uc_compiler *compiler, size_t off) assert(off + 4 < chunk->count); return ( - chunk->entries[off + 1] * 0x1000000 + - chunk->entries[off + 2] * 0x10000 + - chunk->entries[off + 3] * 0x100 + + chunk->entries[off + 1] * 0x1000000UL + + chunk->entries[off + 2] * 0x10000UL + + chunk->entries[off + 3] * 0x100UL + chunk->entries[off + 4] ) - 0x7fffffff; } @@ -1065,7 +1070,7 @@ static bool uc_compiler_compile_arrowfn(uc_compiler *compiler, uc_value_t *args, bool restarg) { bool array = (ucv_type(args) == UC_ARRAY); - uc_compiler fncompiler = {}; + uc_compiler fncompiler = { 0 }; size_t i, pos, load_off; uc_function_t *fn; ssize_t slot; @@ -1283,7 +1288,7 @@ static void uc_compiler_compile_call(uc_compiler *compiler, bool assignable) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); - uc_jmplist spreads = {}; + uc_jmplist spreads = { 0 }; enum insn_type type; size_t i, nargs = 0; @@ -1422,7 +1427,7 @@ uc_compiler_compile_delimitted_block(uc_compiler *compiler, uc_tokentype_t endty static void uc_compiler_compile_function(uc_compiler *compiler, bool assignable) { - uc_compiler fncompiler = {}; + uc_compiler fncompiler = { 0 }; uc_value_t *name = NULL; ssize_t slot = -1, pos; uc_tokentype_t type; @@ -1891,7 +1896,7 @@ uc_compiler_compile_if(uc_compiler *compiler) uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t jmpz_off, jmp_off, i; bool expect_endif = false; - uc_jmplist elifs = {}; + uc_jmplist elifs = { 0 }; uc_tokentype_t type; /* parse & compile condition expression */ @@ -1996,7 +2001,7 @@ uc_compiler_compile_while(uc_compiler *compiler) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t cond_off, jmpz_off, end_off; - uc_patchlist p = {}; + uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2044,7 +2049,7 @@ uc_compiler_compile_for_in(uc_compiler *compiler, bool local, uc_token *kvar, uc { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t skip_jmp, test_jmp, key_slot, val_slot; - uc_patchlist p = {}; + uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2154,7 +2159,7 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t test_off = 0, incr_off, skip_off, cond_off = 0; - uc_patchlist p = {}; + uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2254,7 +2259,7 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var) static void uc_compiler_compile_for(uc_compiler *compiler) { - uc_token keyvar = {}, valvar = {}; + uc_token keyvar = { 0 }, valvar = { 0 }; bool local; uc_compiler_parse_consume(compiler, TK_LPAREN); @@ -2309,8 +2314,8 @@ uc_compiler_compile_switch(uc_compiler *compiler) size_t i, test_jmp, skip_jmp, next_jmp, value_slot, default_off = 0; uc_chunk *chunk = uc_compiler_current_chunk(compiler); uc_locals *locals = &compiler->locals; - uc_jmplist cases = {}; - uc_patchlist p = {}; + uc_jmplist cases = { 0 }; + uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; diff --git a/lexer.c b/lexer.c index 74e0c4d..aaba314 100644 --- a/lexer.c +++ b/lexer.c @@ -38,7 +38,7 @@ struct keyword { union { double d; bool b; - }; + } u; }; struct token { @@ -46,7 +46,7 @@ struct token { union { uint32_t patn; char pat[4]; - }; + } u; unsigned plen; uc_token *(*parse)(uc_lexer *, bool); }; @@ -135,33 +135,33 @@ static const struct token tokens[] = { }; static const struct keyword reserved_words[] = { - { TK_ENDFUNC, "endfunction", 11, {} }, + { TK_ENDFUNC, "endfunction", 11, { 0 } }, { TK_DOUBLE, "Infinity", 8, { .d = INFINITY } }, - { TK_CONTINUE, "continue", 8, {} }, - { TK_ENDWHILE, "endwhile", 8, {} }, - { TK_FUNC, "function", 8, {} }, - { TK_DEFAULT, "default", 7, {} }, - { TK_RETURN, "return", 6, {} }, - { TK_ENDFOR, "endfor", 6, {} }, - { TK_SWITCH, "switch", 6, {} }, - { TK_LOCAL, "local", 5, {} }, - { TK_ENDIF, "endif", 5, {} }, - { TK_WHILE, "while", 5, {} }, - { TK_BREAK, "break", 5, {} }, - { TK_CATCH, "catch", 5, {} }, + { TK_CONTINUE, "continue", 8, { 0 } }, + { TK_ENDWHILE, "endwhile", 8, { 0 } }, + { TK_FUNC, "function", 8, { 0 } }, + { TK_DEFAULT, "default", 7, { 0 } }, + { TK_RETURN, "return", 6, { 0 } }, + { TK_ENDFOR, "endfor", 6, { 0 } }, + { TK_SWITCH, "switch", 6, { 0 } }, + { TK_LOCAL, "local", 5, { 0 } }, + { TK_ENDIF, "endif", 5, { 0 } }, + { TK_WHILE, "while", 5, { 0 } }, + { TK_BREAK, "break", 5, { 0 } }, + { TK_CATCH, "catch", 5, { 0 } }, { TK_BOOL, "false", 5, { .b = false } }, { TK_BOOL, "true", 4, { .b = true } }, - { TK_ELIF, "elif", 4, {} }, - { TK_ELSE, "else", 4, {} }, - { TK_THIS, "this", 4, {} }, - { TK_NULL, "null", 4, {} }, - { TK_CASE, "case", 4, {} }, + { TK_ELIF, "elif", 4, { 0 } }, + { TK_ELSE, "else", 4, { 0 } }, + { TK_THIS, "this", 4, { 0 } }, + { TK_NULL, "null", 4, { 0 } }, + { TK_CASE, "case", 4, { 0 } }, { TK_DOUBLE, "NaN", 3, { .d = NAN } }, - { TK_TRY, "try", 3, {} }, - { TK_FOR, "for", 3, {} }, - { TK_LOCAL, "let", 3, {} }, - { TK_IF, "if", 2, {} }, - { TK_IN, "in", 2, {} }, + { TK_TRY, "try", 3, { 0 } }, + { TK_FOR, "for", 3, { 0 } }, + { TK_LOCAL, "let", 3, { 0 } }, + { TK_IF, "if", 2, { 0 } }, + { TK_IN, "in", 2, { 0 } }, }; @@ -362,7 +362,7 @@ parse_comment(uc_lexer *lex, bool no_regexp) if (!buf_remaining(lex)) return emit_op(lex, lex->lastoff, TK_ERROR, ucv_string_new("Unterminated comment")); - if (!strcmp(tok->pat, "//")) { + if (!strcmp(tok->u.pat, "//")) { end = "\n"; elen = 1; } @@ -400,7 +400,7 @@ static uc_token * parse_string(uc_lexer *lex, bool no_regexp) { const struct token *tok = lex->tok; - char q = tok->pat[0]; + char q = tok->u.pat[0]; char *ptr, *c; uc_token *rv; int code; @@ -438,7 +438,7 @@ parse_string(uc_lexer *lex, bool no_regexp) default: lex->is_escape = false; - c = strchr("a\ab\be\ef\fn\nr\rt\tv\v", *ptr); + c = strchr("a\ab\be\033f\fn\nr\rt\tv\v", *ptr); if (c && *c >= 'a') { lookbehind_append(lex, c + 1, 1); @@ -725,7 +725,7 @@ parse_label(uc_lexer *lex, bool no_regexp) size_t i; if (!lex->lookbehind && tok->plen) - lookbehind_append(lex, tok->pat, tok->plen); + lookbehind_append(lex, tok->u.pat, tok->plen); if (!buf_remaining(lex) || (lex->bufstart[0] != '_' && !isalnum(lex->bufstart[0]))) { for (i = 0, word = &reserved_words[0]; i < ARRAY_SIZE(reserved_words); i++, word = &reserved_words[i]) { @@ -734,11 +734,11 @@ parse_label(uc_lexer *lex, bool no_regexp) switch (word->type) { case TK_DOUBLE: - rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_double_new(word->d)); + rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_double_new(word->u.d)); break; case TK_BOOL: - rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_boolean_new(word->b)); + rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_boolean_new(word->u.b)); break; default: @@ -803,7 +803,7 @@ parse_number(uc_lexer *lex, bool no_regexp) if (*e == '.' || *e == 'e' || *e == 'E') { d = strtod(lex->lookbehind, &e); - if (tok->pat[0] == '-') + if (tok->u.pat[0] == '-') d = -d; if (e > lex->lookbehind && *e == 0) @@ -812,7 +812,7 @@ parse_number(uc_lexer *lex, bool no_regexp) rv = emit_op(lex, lex->source->off - (lex->lookbehindlen - (e - lex->lookbehind) - 1), TK_ERROR, ucv_string_new("Invalid number literal")); } else if (*e == 0) { - if (tok->pat[0] == '-') + if (tok->u.pat[0] == '-') n = (errno == ERANGE) ? INT64_MIN : -n; rv = emit_op(lex, lex->source->off - (e - lex->lookbehind), TK_NUMBER, ucv_int64_new(n)); @@ -857,7 +857,8 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp) rem = lex->bufend - lex->bufstart; - memcpy(lex->buf, lex->bufstart, rem); + if (rem) + memcpy(lex->buf, lex->bufstart, rem); rlen = fread(lex->buf + rem, 1, lex->buflen - rem, fp); @@ -1042,8 +1043,8 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp) c = buf_remaining(lex) ? lex->bufstart[0] : 0; - if (tok->plen ? ((search.n & masks[tok->plen]) == tok->patn) - : (c >= tok->pat[0] && c <= tok->pat[1])) { + if (tok->plen ? ((search.n & masks[tok->plen]) == tok->u.patn) + : (c >= tok->u.pat[0] && c <= tok->u.pat[1])) { lex->lastoff = lex->source->off; /* token has a parse method, switch state */ @@ -1067,7 +1068,7 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp) else if ((lex->block == STATEMENTS && tok->type == TK_RSTM) || (lex->block == EXPRESSION && tok->type == TK_REXP)) { /* strip whitespace after block */ - if (tok->pat[0] == '-') + if (tok->u.pat[0] == '-') lex->modifier = MINUS; /* strip newline after statement block */ @@ -1207,7 +1208,7 @@ uc_get_tokenname(unsigned type) if (tokens[i].type != type) continue; - snprintf(buf, sizeof(buf), "'%s'", tokens[i].pat); + snprintf(buf, sizeof(buf), "'%s'", tokens[i].u.pat); return buf; } diff --git a/lexer.h b/lexer.h index f023fb6..069e9e0 100644 --- a/lexer.h +++ b/lexer.h @@ -126,12 +126,6 @@ typedef struct { size_t pos; } uc_token; -typedef struct { - bool lstrip_blocks; - bool trim_blocks; - bool strict_declarations; -} uc_parse_config; - typedef struct { uc_lex_state_t state; uc_parse_config *config; diff --git a/lib.c b/lib.c index 80c1386..5d6235d 100644 --- a/lib.c +++ b/lib.c @@ -35,6 +35,7 @@ #include "compiler.h" #include "vm.h" #include "lib.h" +#include "source.h" static void format_context_line(uc_stringbuf_t *buf, const char *line, size_t off, bool compact) @@ -454,9 +455,11 @@ static uc_value_t * uc_delete(uc_vm *vm, size_t nargs) { uc_value_t *obj = uc_get_arg(0); + uc_value_t *key = NULL; uc_value_t *rv = NULL; - const char *key; + bool freeable; size_t i; + char *k; if (ucv_type(obj) != UC_OBJECT) return NULL; @@ -464,10 +467,14 @@ uc_delete(uc_vm *vm, size_t nargs) for (i = 1; i < nargs; i++) { ucv_put(rv); - key = ucv_string_get(uc_get_arg(i)); - rv = ucv_get(ucv_object_get(obj, key ? key : "null", NULL)); + key = uc_get_arg(i); + k = uc_cast_string(vm, &key, &freeable); + rv = ucv_get(ucv_object_get(obj, k, NULL)); + + ucv_object_delete(obj, k); - ucv_object_delete(obj, key ? key : "null"); + if (freeable) + free(k); } return rv; @@ -482,7 +489,7 @@ uc_die(uc_vm *vm, size_t nargs) s = msg ? uc_cast_string(vm, &msg, &freeable) : "Died"; - uc_vm_raise_exception(vm, EXCEPTION_USER, s); + uc_vm_raise_exception(vm, EXCEPTION_USER, "%s", s); if (freeable) free(s); @@ -494,13 +501,19 @@ static uc_value_t * uc_exists(uc_vm *vm, size_t nargs) { uc_value_t *obj = uc_get_arg(0); - const char *key = ucv_string_get(uc_get_arg(1)); - bool found; + uc_value_t *key = uc_get_arg(1); + bool found, freeable; + char *k; if (ucv_type(obj) != UC_OBJECT) return false; - ucv_object_get(obj, key ? key : "null", &found); + k = uc_cast_string(vm, &key, &freeable); + + ucv_object_get(obj, k, &found); + + if (freeable) + free(k); return ucv_boolean_new(found); } @@ -516,8 +529,9 @@ uc_exit(uc_vm *vm, size_t nargs) static uc_value_t * uc_getenv(uc_vm *vm, size_t nargs) { - const char *key = ucv_string_get(uc_get_arg(0)); - char *val = key ? getenv(key) : NULL; + uc_value_t *key = uc_get_arg(0); + char *k = ucv_string_get(key); + char *val = k ? getenv(k) : NULL; return val ? ucv_string_new(val) : NULL; } @@ -562,16 +576,18 @@ uc_filter(uc_vm *vm, size_t nargs) static uc_value_t * uc_hex(uc_vm *vm, size_t nargs) { - const char *val = ucv_string_get(uc_get_arg(0)); + uc_value_t *val = uc_get_arg(0); + char *e, *v; int64_t n; - char *e; - if (!val || !isxdigit(*val)) + v = ucv_string_get(val); + + if (!v || !isxdigit(*v)) return ucv_double_new(NAN); - n = strtoll(val, &e, 16); + n = strtoll(v, &e, 16); - if (e == val || *e) + if (e == v || *e) return ucv_double_new(NAN); return ucv_int64_new(n); @@ -622,8 +638,10 @@ uc_keys(uc_vm *vm, size_t nargs) arr = ucv_array_new(vm); - ucv_object_foreach(obj, key, val) + ucv_object_foreach(obj, key, val) { + (void)val; ucv_array_push(arr, ucv_string_new(key)); + } return arr; } @@ -1423,7 +1441,7 @@ uc_require_so(uc_vm *vm, const char *path, uc_value_t **res) return true; } - init = dlsym(dlh, "uc_module_entry"); + *(void **)(&init) = dlsym(dlh, "uc_module_entry"); if (!init) { uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, diff --git a/lib/uci.c b/lib/uci.c index fba7dad..00a451c 100644 --- a/lib/uci.c +++ b/lib/uci.c @@ -255,7 +255,7 @@ uc_uci_get_any(uc_vm *vm, size_t nargs, bool all) uc_value_t *conf = uc_get_arg(0); uc_value_t *sect = uc_get_arg(1); uc_value_t *opt = uc_get_arg(2); - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; int rv; if (!c || !*c) @@ -330,7 +330,7 @@ uc_uci_get_first(uc_vm *vm, size_t nargs) struct uci_package *p = NULL; struct uci_section *sc; struct uci_element *e; - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; int rv; if (ucv_type(conf) != UC_STRING || @@ -465,7 +465,7 @@ uc_uci_set(uc_vm *vm, size_t nargs) uc_value_t *conf = uc_get_arg(0); uc_value_t *sect = uc_get_arg(1); uc_value_t *opt = NULL, *val = NULL; - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; bool is_list = false; size_t i; int rv; @@ -570,7 +570,7 @@ uc_uci_delete(uc_vm *vm, size_t nargs) uc_value_t *conf = uc_get_arg(0); uc_value_t *sect = uc_get_arg(1); uc_value_t *opt = uc_get_arg(2); - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; int rv; if (ucv_type(conf) != UC_STRING || @@ -605,7 +605,7 @@ uc_uci_rename(uc_vm *vm, size_t nargs) uc_value_t *conf = uc_get_arg(0); uc_value_t *sect = uc_get_arg(1); uc_value_t *opt = NULL, *val = NULL; - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; int rv; if (ucv_type(conf) != UC_STRING || @@ -665,7 +665,7 @@ uc_uci_reorder(uc_vm *vm, size_t nargs) uc_value_t *conf = uc_get_arg(0); uc_value_t *sect = uc_get_arg(1); uc_value_t *val = uc_get_arg(2); - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; int64_t n; int rv; @@ -705,7 +705,7 @@ uc_uci_pkg_command(uc_vm *vm, size_t nargs, enum pkg_cmd cmd) uc_value_t *conf = uc_get_arg(0); struct uci_element *e, *tmp; struct uci_package *p; - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; int rv, res = UCI_OK; if (cmd != CMD_REVERT && conf) diff --git a/main.c b/main.c index 618d5e4..d291447 100644 --- a/main.c +++ b/main.c @@ -98,7 +98,7 @@ parse(uc_parse_config *config, uc_source *src, { uc_value_t *globals = NULL; uc_function_t *entry; - uc_vm vm = {}; + uc_vm vm = { 0 }; int c, c2, rc = 0; char *err; @@ -285,7 +285,12 @@ main(int argc, char **argv) if (source) fprintf(stderr, "Options -i and -s are exclusive\n"); - source = uc_source_new_buffer("[-s argument]", xstrdup(optarg), strlen(optarg)); + c = xstrdup(optarg); + source = uc_source_new_buffer("[-s argument]", c, strlen(c)); + + if (!source) + free(c); + break; case 'S': diff --git a/source.h b/source.h index 4ca01b3..6557a48 100644 --- a/source.h +++ b/source.h @@ -22,17 +22,9 @@ #include #include "util.h" +#include "types.h" -uc_declare_vector(uc_lineinfo, uint8_t); - -typedef struct { - char *filename, *buffer; - FILE *fp; - size_t usecount, off; - uc_lineinfo lineinfo; -} uc_source; - uc_source *uc_source_new_file(const char *path); uc_source *uc_source_new_buffer(const char *name, char *buf, size_t len); diff --git a/tests/cram/test_basic.t b/tests/cram/test_basic.t index 982d58a..3d4cd9e 100644 --- a/tests/cram/test_basic.t +++ b/tests/cram/test_basic.t @@ -35,7 +35,7 @@ check that ucode provides proper error messages: One of -i or -s is required [1] - $ ucode -m foo -s '' + $ ucode -m foo -s ' ' Runtime error: No module named 'foo' could be found At start of program @@ -53,6 +53,7 @@ check that ucode can load fs module: One of -i or -s is required [1] - $ ucode -m fs -s '' + $ ucode -m fs -s ' ' + (no-eol) $ touch moo; ucode -m fs -i moo diff --git a/types.c b/types.c index e786fb1..3ed8aaa 100644 --- a/types.c +++ b/types.c @@ -927,7 +927,7 @@ ucv_closure_new(uc_vm *vm, uc_function_t *function, bool arrow_fn) closure->header.refcount = 1; closure->function = function; closure->is_arrow = arrow_fn; - closure->upvals = function->nupvals ? ((void *)closure + ALIGN(sizeof(*closure))) : NULL; + closure->upvals = function->nupvals ? (uc_upvalref_t **)((uintptr_t)closure + ALIGN(sizeof(*closure))) : NULL; if (vm) ucv_ref(&vm->values, &closure->ref); @@ -1590,8 +1590,8 @@ ucv_to_stringbuf(uc_vm *vm, uc_stringbuf_t *pb, uc_value_t *uv, bool json) ucv_stringbuf_printf(pb, "%sfunction%s%s(...) { [native code] }%s", json ? "\"" : "", - cfunction->name ? " " : "", - cfunction->name ? cfunction->name : "", + cfunction->name[0] ? " " : "", + cfunction->name[0] ? cfunction->name : "", json ? "\"" : ""); break; @@ -1739,6 +1739,7 @@ ucv_equal(uc_value_t *uv1, uc_value_t *uv2) } ucv_object_foreach(uv2, key2, val2) { + (void)val2; ucv_object_get(uv1, key2, &b1); if (!b1) @@ -1772,7 +1773,7 @@ ucv_gc(uc_vm *vm, bool final) /* unref unreachable objects */ for (ref = vm->values.next; ref != &vm->values; ref = ref->next) { - val = (void *)ref - offsetof(uc_array_t, ref); + val = (uc_value_t *)((uintptr_t)ref - offsetof(uc_array_t, ref)); if (ucv_is_marked(val)) ucv_clear_mark(val); @@ -1782,7 +1783,7 @@ ucv_gc(uc_vm *vm, bool final) /* free destroyed objects */ for (ref = vm->values.next, tmp = ref->next; ref != &vm->values; ref = tmp, tmp = tmp->next) { - val = (void *)ref - offsetof(uc_array_t, ref); + val = (uc_value_t *)((uintptr_t)ref - offsetof(uc_array_t, ref)); if (val->type == UC_NULL) { ucv_unref(ref); diff --git a/types.h b/types.h index a8962da..9dab246 100644 --- a/types.h +++ b/types.h @@ -22,8 +22,10 @@ #include #include -#include "source.h" -#include "chunk.h" +#include "util.h" + + +/* Value types and generic value header */ typedef enum uc_type_t { UC_NULL, @@ -48,6 +50,58 @@ typedef struct uc_value_t { uint32_t refcount:26; } uc_value_t; + +/* Constant list defintions */ + +typedef struct { + size_t isize; + size_t dsize; + uint64_t *index; + char *data; +} uc_value_list; + + +/* Source buffer defintions */ + +uc_declare_vector(uc_lineinfo, uint8_t); + +typedef struct { + char *filename, *buffer; + FILE *fp; + size_t usecount, off; + uc_lineinfo lineinfo; +} uc_source; + + +/* Bytecode chunk defintions */ + +typedef struct { + size_t from, to, target, slot; +} uc_ehrange; + +typedef struct { + size_t from, to, slot, nameidx; +} uc_varrange; + +uc_declare_vector(uc_ehranges, uc_ehrange); +uc_declare_vector(uc_variables, uc_varrange); +uc_declare_vector(uc_offsetinfo, uint8_t); + +typedef struct { + size_t count; + uint8_t *entries; + uc_value_list constants; + uc_ehranges ehranges; + struct { + uc_variables variables; + uc_value_list varnames; + uc_offsetinfo offsets; + } debuginfo; +} uc_chunk; + + +/* Value type structures */ + typedef struct uc_weakref_t { struct uc_weakref_t *prev; struct uc_weakref_t *next; @@ -144,6 +198,69 @@ typedef struct { uc_declare_vector(uc_ressource_types_t, uc_ressource_type_t); + +/* Parser definitions */ + +typedef struct { + bool lstrip_blocks; + bool trim_blocks; + bool strict_declarations; +} uc_parse_config; + + +/* VM definitions */ + +typedef enum { + EXCEPTION_NONE, + EXCEPTION_SYNTAX, + EXCEPTION_RUNTIME, + EXCEPTION_TYPE, + EXCEPTION_REFERENCE, + EXCEPTION_USER +} uc_exception_type_t; + +typedef struct { + uc_exception_type_t type; + uc_value_t *stacktrace; + char *message; +} uc_exception; + +typedef struct { + uint8_t *ip; + uc_closure_t *closure; + uc_cfunction_t *cfunction; + size_t stackframe; + uc_value_t *ctx; + bool mcall; +} uc_callframe; + +uc_declare_vector(uc_callframes, uc_callframe); +uc_declare_vector(uc_stack, uc_value_t *); + +struct uc_vm { + uc_stack stack; + uc_exception exception; + uc_callframes callframes; + uc_upvalref_t *open_upvals; + uc_parse_config *config; + uc_value_t *globals; + uc_source *sources; + uc_weakref_t values; + union { + uint32_t u32; + int32_t s32; + uint16_t u16; + int16_t s16; + uint8_t u8; + int8_t s8; + } arg; + size_t spread_values; + uint8_t trace; +}; + + +/* Value API */ + typedef struct printbuf uc_stringbuf_t; void ucv_free(uc_value_t *, bool); @@ -162,7 +279,7 @@ uc_value_t *ucv_string_new_length(const char *, size_t); size_t ucv_string_length(uc_value_t *); char *_ucv_string_get(uc_value_t **); -#define ucv_string_get(uv) ({ uc_value_t * volatile p = (uv); _ucv_string_get((uc_value_t **)&p); }) +#define ucv_string_get(uv) _ucv_string_get((uc_value_t **)&uv) uc_stringbuf_t *ucv_stringbuf_new(void); uc_value_t *ucv_stringbuf_finish(uc_stringbuf_t *); @@ -200,16 +317,17 @@ bool ucv_object_add(uc_value_t *, const char *, uc_value_t *); bool ucv_object_delete(uc_value_t *, const char *); size_t ucv_object_length(uc_value_t *); -#define ucv_object_foreach(obj, key, val) \ - char *key; \ - uc_value_t *val __attribute__((__unused__)); \ - for (struct lh_entry *entry ## key = (ucv_type(obj) == UC_OBJECT) ? ((uc_object_t *)obj)->table->head : NULL, *entry_next ## key = NULL; \ - ({ if (entry ## key) { \ - key = (char *)entry ## key->k; \ - val = (uc_value_t *)entry ## key->v; \ - entry_next ## key = entry ## key->next; \ - } ; entry ## key; }); \ - entry ## key = entry_next ## key) +#define ucv_object_foreach(obj, key, val) \ + char *key = NULL; \ + uc_value_t *val = NULL; \ + struct lh_entry *entry##key; \ + struct lh_entry *entry_next##key = NULL; \ + for (entry##key = (ucv_type(obj) == UC_OBJECT) ? ((uc_object_t *)obj)->table->head : NULL; \ + (entry##key ? (key = (char *)lh_entry_k(entry##key), \ + val = (uc_value_t *)lh_entry_v(entry##key), \ + entry_next##key = entry##key->next, entry##key) \ + : 0); \ + entry##key = entry_next##key) uc_value_t *ucv_function_new(const char *, size_t, uc_source *); size_t ucv_function_srcpos(uc_value_t *, size_t); diff --git a/util.h b/util.h index a62ccc4..c4ea087 100644 --- a/util.h +++ b/util.h @@ -218,6 +218,7 @@ static inline struct json_tokener *xjs_new_tokener(void) { return tok; } +__attribute__((format(printf, 2, 0))) static inline int xasprintf(char **strp, const char *fmt, ...) { va_list ap; int len; @@ -234,6 +235,7 @@ static inline int xasprintf(char **strp, const char *fmt, ...) { return len; } +__attribute__((format(printf, 2, 0))) static inline int xvasprintf(char **strp, const char *fmt, va_list ap) { int len = vasprintf(strp, fmt, ap); diff --git a/value.c b/value.c index e53e317..0827038 100644 --- a/value.c +++ b/value.c @@ -260,7 +260,7 @@ uc_cmp(int how, uc_value_t *v1, uc_value_t *v2) } else { if (t1 == t2 && !ucv_is_scalar(v1)) { - delta = (void *)v1 - (void *)v2; + delta = (intptr_t)v1 - (intptr_t)v2; } else { t1 = uc_cast_number(v1, &n1, &d1); diff --git a/value.h b/value.h index 770279e..a3abfc6 100644 --- a/value.h +++ b/value.h @@ -29,6 +29,8 @@ #include +#include "types.h" + typedef enum { TAG_INVAL = 0, TAG_NUM = 1, @@ -39,24 +41,11 @@ typedef enum { TAG_PTR = 6 } uc_value_type_t; -typedef struct { - size_t isize; - size_t dsize; - uint64_t *index; - char *data; -} uc_value_list; - -typedef struct uc_value_t uc_value_t; - bool uc_cmp(int how, uc_value_t *v1, uc_value_t *v2); bool uc_val_is_truish(uc_value_t *val); -typedef enum uc_type_t uc_type_t; -typedef struct uc_value_t uc_value_t; uc_type_t uc_cast_number(uc_value_t *v, int64_t *n, double *d); -typedef struct uc_vm uc_vm; - uc_value_t *uc_getval(uc_vm *, uc_value_t *scope, uc_value_t *key); uc_value_t *uc_setval(uc_vm *, uc_value_t *scope, uc_value_t *key, uc_value_t *val); diff --git a/vm.c b/vm.c index 7d60805..ee73265 100644 --- a/vm.c +++ b/vm.c @@ -232,9 +232,9 @@ uc_vm_decode_insn(uc_vm *vm, uc_callframe *frame, uc_chunk *chunk) case -4: vm->arg.s32 = ( - frame->ip[0] * 0x1000000 + - frame->ip[1] * 0x10000 + - frame->ip[2] * 0x100 + + frame->ip[0] * 0x1000000UL + + frame->ip[1] * 0x10000UL + + frame->ip[2] * 0x100UL + frame->ip[3] ) - 0x7fffffff; frame->ip += 4; @@ -247,9 +247,9 @@ uc_vm_decode_insn(uc_vm *vm, uc_callframe *frame, uc_chunk *chunk) case 4: vm->arg.u32 = ( - frame->ip[0] * 0x1000000 + - frame->ip[1] * 0x10000 + - frame->ip[2] * 0x100 + + frame->ip[0] * 0x1000000UL + + frame->ip[1] * 0x10000UL + + frame->ip[2] * 0x100UL + frame->ip[3] ); frame->ip += 4; @@ -307,7 +307,7 @@ uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame) ref = closure->upvals[i]; v = uc_chunk_debug_get_variable(chunk, 0, i, true); s = ucv_to_string(NULL, v); - fprintf(stderr, " [%zu] <%p> %s ", i, ref, s); + fprintf(stderr, " [%zu] <%p> %s ", i, (void *)ref, s); free(s); if (ref->closed) { @@ -588,13 +588,13 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) case -2: fprintf(stderr, " {%c0x%hx}", vm->arg.s16 < 0 ? '-' : '+', - vm->arg.s16 < 0 ? -(unsigned)vm->arg.s16 : (unsigned)vm->arg.s16); + (uint16_t)(vm->arg.s16 < 0 ? -vm->arg.s16 : vm->arg.s16)); break; case -4: fprintf(stderr, " {%c0x%x}", vm->arg.s32 < 0 ? '-' : '+', - vm->arg.s32 < 0 ? -(unsigned)vm->arg.s32 : (unsigned)vm->arg.s32); + (uint32_t)(vm->arg.s32 < 0 ? -vm->arg.s32 : vm->arg.s32)); break; case 1: @@ -1035,7 +1035,7 @@ uc_vm_capture_upval(uc_vm *vm, size_t slot) if (curr && curr->slot == slot) { if (vm->trace) { s = ucv_to_string(NULL, vm->stack.entries[slot]); - fprintf(stderr, " {+%zu} <%p> %s\n", slot, curr, s); + fprintf(stderr, " {+%zu} <%p> %s\n", slot, (void *)curr, s); free(s); } @@ -1047,7 +1047,7 @@ uc_vm_capture_upval(uc_vm *vm, size_t slot) if (vm->trace) { s = ucv_to_string(NULL, vm->stack.entries[slot]); - fprintf(stderr, " {*%zu} <%p> %s\n", slot, created, s); + fprintf(stderr, " {*%zu} <%p> %s\n", slot, (void *)created, s); free(s); } @@ -1072,7 +1072,7 @@ uc_vm_close_upvals(uc_vm *vm, size_t slot) if (vm->trace) { s = ucv_to_string(NULL, ref->value); - fprintf(stderr, " {!%zu} <%p> %s\n", ref->slot, ref, s); + fprintf(stderr, " {!%zu} <%p> %s\n", ref->slot, (void *)ref, s); free(s); } @@ -1528,11 +1528,13 @@ static void uc_vm_insn_sobj(uc_vm *vm, enum insn_type insn) { uc_value_t *obj = uc_vm_stack_peek(vm, vm->arg.u32); + uc_value_t *val; size_t idx; for (idx = 0; idx < vm->arg.u32; idx += 2) { + val = uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1); ucv_object_add(obj, - ucv_string_get(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1)), + ucv_string_get(val), ucv_get(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 2))); } @@ -1972,6 +1974,8 @@ uc_vm_callframe_pop(uc_vm *vm) static void uc_vm_output_exception(uc_vm *vm) { + uc_value_t *ctx; + if (vm->exception.type == EXCEPTION_USER) fprintf(stderr, "%s\n", vm->exception.message); else @@ -1979,10 +1983,9 @@ uc_vm_output_exception(uc_vm *vm) exception_type_strings[vm->exception.type] ? exception_type_strings[vm->exception.type] : "Error", vm->exception.message); - fprintf(stderr, "%s\n\n", - ucv_string_get( - ucv_object_get( - ucv_array_get(vm->exception.stacktrace, 0), "context", NULL))); + ctx = ucv_object_get(ucv_array_get(vm->exception.stacktrace, 0), "context", NULL); + + fprintf(stderr, "%s\n\n", ucv_string_get(ctx)); } static uc_vm_status_t diff --git a/vm.h b/vm.h index e4de4f9..0f7b805 100644 --- a/vm.h +++ b/vm.h @@ -23,6 +23,7 @@ #include "chunk.h" #include "util.h" #include "lexer.h" +#include "types.h" #define __insns \ __insn(NOOP) \ @@ -103,54 +104,6 @@ typedef struct { int8_t operand_bytes; } uc_insn_definition; -typedef enum { - EXCEPTION_NONE, - EXCEPTION_SYNTAX, - EXCEPTION_RUNTIME, - EXCEPTION_TYPE, - EXCEPTION_REFERENCE, - EXCEPTION_USER -} uc_exception_type_t; - -typedef struct { - uc_exception_type_t type; - uc_value_t *stacktrace; - char *message; -} uc_exception; - -typedef struct { - uint8_t *ip; - uc_closure_t *closure; - uc_cfunction_t *cfunction; - size_t stackframe; - uc_value_t *ctx; - bool mcall; -} uc_callframe; - -uc_declare_vector(uc_callframes, uc_callframe); -uc_declare_vector(uc_stack, uc_value_t *); - -typedef struct uc_vm { - uc_stack stack; - uc_exception exception; - uc_callframes callframes; - uc_upvalref_t *open_upvals; - uc_parse_config *config; - uc_value_t *globals; - uc_source *sources; - uc_weakref_t values; - union { - uint32_t u32; - int32_t s32; - uint16_t u16; - int16_t s16; - uint8_t u8; - int8_t s8; - } arg; - size_t spread_values; - uint8_t trace; -} uc_vm; - typedef enum { STATUS_OK, ERROR_COMPILE, -- cgit v1.2.3