diff options
Diffstat (limited to 'vm.c')
-rw-r--r-- | vm.c | 514 |
1 files changed, 304 insertions, 210 deletions
@@ -14,16 +14,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <stdlib.h> #include <stdarg.h> #include <string.h> #include <assert.h> #include <ctype.h> #include <math.h> -#include "vm.h" -#include "compiler.h" -#include "lib.h" /* format_error_context() */ +#include "ucode/vm.h" +#include "ucode/compiler.h" +#include "ucode/lib.h" /* uc_error_context_format() */ #undef __insn #define __insn(_name) #_name, @@ -77,11 +76,12 @@ static const char *exception_type_strings[] = { [EXCEPTION_TYPE] = "Type error", [EXCEPTION_REFERENCE] = "Reference error", [EXCEPTION_USER] = "Error", + [EXCEPTION_EXIT] = "Exit" }; static void -uc_vm_reset_stack(uc_vm *vm) +uc_vm_reset_stack(uc_vm_t *vm) { while (vm->stack.count > 0) { vm->stack.count--; @@ -91,24 +91,54 @@ uc_vm_reset_stack(uc_vm *vm) } static uc_value_t * -uc_vm_callframe_pop(uc_vm *vm); +uc_vm_callframe_pop(uc_vm_t *vm); static void -uc_vm_reset_callframes(uc_vm *vm) +uc_vm_reset_callframes(uc_vm_t *vm) { while (vm->callframes.count > 0) ucv_put(uc_vm_callframe_pop(vm)); } -void uc_vm_init(uc_vm *vm, uc_parse_config *config) +static uc_value_t * +uc_vm_alloc_global_scope(uc_vm_t *vm) { - char *s = getenv("TRACE"); + const char *path[] = { LIB_SEARCH_PATH }; + uc_value_t *scope, *arr; + size_t i; + + scope = ucv_object_new(vm); + + /* build default require() search path */ + arr = ucv_array_new(vm); + + for (i = 0; i < ARRAY_SIZE(path); i++) + ucv_array_push(arr, ucv_string_new(path[i])); + + /* register module related constants */ + ucv_object_add(scope, "REQUIRE_SEARCH_PATH", arr); + ucv_object_add(scope, "modules", ucv_object_new(vm)); + + /* register scope math constants */ + ucv_object_add(scope, "NaN", ucv_double_new(NAN)); + ucv_object_add(scope, "Infinity", ucv_double_new(INFINITY)); + + /* register global property */ + ucv_object_add(scope, "global", ucv_get(scope)); + + uc_vm_scope_set(vm, scope); + + return scope; +} + +static void +uc_vm_output_exception(uc_vm_t *vm, uc_exception_t *ex); +void uc_vm_init(uc_vm_t *vm, uc_parse_config_t *config) +{ vm->exception.type = EXCEPTION_NONE; vm->exception.message = NULL; - vm->trace = s ? strtoul(s, NULL, 0) : 0; - vm->config = config; vm->open_upvals = NULL; @@ -121,11 +151,18 @@ void uc_vm_init(uc_vm *vm, uc_parse_config *config) vm->output = stdout; uc_vm_reset_stack(vm); + + uc_vm_alloc_global_scope(vm); + + uc_vm_exception_handler_set(vm, uc_vm_output_exception); + + uc_vm_trace_set(vm, 0); } -void uc_vm_free(uc_vm *vm) +void uc_vm_free(uc_vm_t *vm) { - uc_upvalref_t *ref; + uc_upval_tref_t *ref; + size_t i; ucv_put(vm->exception.stacktrace); free(vm->exception.message); @@ -136,6 +173,9 @@ void uc_vm_free(uc_vm *vm) vm->open_upvals = ref; } + for (i = 0; i < vm->restypes.count; i++) + ucv_put(vm->restypes.entries[i]->proto); + uc_vm_reset_callframes(vm); uc_vm_reset_stack(vm); uc_vector_clear(&vm->stack); @@ -143,37 +183,42 @@ void uc_vm_free(uc_vm *vm) printbuf_free(vm->strbuf); - ucv_gc(vm, true); + ucv_freeall(vm); + + for (i = 0; i < vm->restypes.count; i++) + free(vm->restypes.entries[i]); + + uc_vector_clear(&vm->restypes); } -static uc_chunk * -uc_vm_frame_chunk(uc_callframe *frame) +static uc_chunk_t * +uc_vm_frame_chunk(uc_callframe_t *frame) { return frame->closure ? &frame->closure->function->chunk : NULL; } -static uc_callframe * -uc_vm_current_frame(uc_vm *vm) +static uc_callframe_t * +uc_vm_current_frame(uc_vm_t *vm) { return uc_vector_last(&vm->callframes); } -static uc_chunk * -uc_vm_current_chunk(uc_vm *vm) +static uc_chunk_t * +uc_vm_current_chunk(uc_vm_t *vm) { return uc_vm_frame_chunk(uc_vm_current_frame(vm)); } static bool -uc_vm_is_strict(uc_vm *vm) +uc_vm_is_strict(uc_vm_t *vm) { return uc_vm_current_frame(vm)->strict; } -static enum insn_type -uc_vm_decode_insn(uc_vm *vm, uc_callframe *frame, uc_chunk *chunk) +static uc_vm_insn_t +uc_vm_decode_insn(uc_vm_t *vm, uc_callframe_t *frame, uc_chunk_t *chunk) { - enum insn_type insn; + uc_vm_insn_t insn; #ifndef NDEBUG uint8_t *end = chunk->entries + chunk->count; @@ -238,7 +283,7 @@ uc_vm_decode_insn(uc_vm *vm, uc_callframe *frame, uc_chunk *chunk) static char * -uc_vm_format_val(uc_vm *vm, uc_value_t *val) +uc_vm_format_val(uc_vm_t *vm, uc_value_t *val) { if (!vm->strbuf) vm->strbuf = xprintbuf_new(); @@ -256,12 +301,12 @@ uc_vm_format_val(uc_vm *vm, uc_value_t *val) } static void -uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame) +uc_vm_frame_dump(uc_vm_t *vm, uc_callframe_t *frame) { - uc_chunk *chunk = uc_vm_frame_chunk(frame); + uc_chunk_t *chunk = uc_vm_frame_chunk(frame); uc_function_t *function; uc_closure_t *closure; - uc_upvalref_t *ref; + uc_upval_tref_t *ref; uc_value_t *v; size_t i; @@ -316,7 +361,7 @@ uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame) } void -uc_vm_stack_push(uc_vm *vm, uc_value_t *value) +uc_vm_stack_push(uc_vm_t *vm, uc_value_t *value) { uc_vector_grow(&vm->stack); @@ -333,7 +378,7 @@ uc_vm_stack_push(uc_vm *vm, uc_value_t *value) } uc_value_t * -uc_vm_stack_pop(uc_vm *vm) +uc_vm_stack_pop(uc_vm_t *vm) { uc_value_t *rv; @@ -351,13 +396,13 @@ uc_vm_stack_pop(uc_vm *vm) } uc_value_t * -uc_vm_stack_peek(uc_vm *vm, size_t offset) +uc_vm_stack_peek(uc_vm_t *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, uc_value_t *value) +uc_vm_stack_set(uc_vm_t *vm, size_t offset, uc_value_t *value) { if (vm->trace) { fprintf(stderr, " [!%zu] %s\n", @@ -370,10 +415,10 @@ uc_vm_stack_set(uc_vm *vm, size_t offset, uc_value_t *value) } static void -uc_vm_call_native(uc_vm *vm, uc_value_t *ctx, uc_cfunction_t *fptr, bool mcall, size_t nargs) +uc_vm_call_native(uc_vm_t *vm, uc_value_t *ctx, uc_cfunction_t *fptr, bool mcall, size_t nargs) { uc_value_t *res = NULL; - uc_callframe *frame; + uc_callframe_t *frame; /* add new callframe */ uc_vector_grow(&vm->callframes); @@ -401,10 +446,10 @@ uc_vm_call_native(uc_vm *vm, uc_value_t *ctx, uc_cfunction_t *fptr, bool mcall, } static bool -uc_vm_call_function(uc_vm *vm, uc_value_t *ctx, uc_value_t *fno, bool mcall, size_t argspec) +uc_vm_call_function(uc_vm_t *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); + uc_callframe_t *frame = NULL; uc_value_t *ellip, *arg; uc_function_t *function; uc_closure_t *closure; @@ -422,6 +467,8 @@ uc_vm_call_function(uc_vm *vm, uc_value_t *ctx, uc_value_t *fno, bool mcall, siz /* argument list contains spread operations, we need to reshuffle the stack */ if (nspreads > 0) { + frame = uc_vm_current_frame(vm); + /* create temporary array */ ellip = ucv_array_new_length(vm, nargs); @@ -535,24 +582,24 @@ uc_vm_call_function(uc_vm *vm, uc_value_t *ctx, uc_value_t *fno, bool mcall, siz return true; } -static uc_source *last_source = NULL; +static uc_source_t *last_source = NULL; static size_t last_srcpos = 0; static void -uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) +uc_dump_insn(uc_vm_t *vm, uint8_t *pos, uc_vm_insn_t insn) { - uc_callframe *frame = uc_vm_current_frame(vm); - uc_chunk *chunk = uc_vm_frame_chunk(frame); + uc_callframe_t *frame = uc_vm_current_frame(vm); + uc_chunk_t *chunk = uc_vm_frame_chunk(frame); uc_stringbuf_t *buf = NULL; uc_value_t *cnst = NULL; size_t srcpos; - srcpos = ucv_function_srcpos((uc_value_t *)frame->closure->function, pos - chunk->entries); + srcpos = ucv_function_srcpos(&frame->closure->function->header, pos - chunk->entries); if (last_srcpos == 0 || last_source != frame->closure->function->source || srcpos != last_srcpos) { buf = xprintbuf_new(); - format_source_context(buf, frame->closure->function->source, srcpos, true); + uc_source_context_format(buf, frame->closure->function->source, srcpos, true); fwrite(buf->buf, 1, printbuf_length(buf), stderr); printbuf_free(buf); @@ -651,9 +698,9 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) } static uc_value_t * -uc_vm_exception_tostring(uc_vm *vm, size_t nargs) +uc_vm_exception_tostring(uc_vm_t *vm, size_t nargs) { - uc_callframe *frame = uc_vm_current_frame(vm); + uc_callframe_t *frame = uc_vm_current_frame(vm); uc_value_t *message = ucv_object_get(frame->ctx, "message", NULL); return message ? ucv_get(message) : ucv_string_new("Exception"); @@ -662,7 +709,7 @@ uc_vm_exception_tostring(uc_vm *vm, size_t nargs) 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_vm_exception_new(uc_vm_t *vm, uc_exception_type_t type, const char *message, uc_value_t *stacktrace) { uc_value_t *exo; @@ -685,14 +732,17 @@ uc_vm_exception_new(uc_vm *vm, uc_exception_type_t type, const char *message, uc } static bool -uc_vm_handle_exception(uc_vm *vm) +uc_vm_handle_exception(uc_vm_t *vm) { - uc_callframe *frame = uc_vm_current_frame(vm); - uc_chunk *chunk = NULL; + uc_callframe_t *frame = NULL; + uc_chunk_t *chunk = NULL; uc_value_t *exo; size_t i, pos; - if (!frame->closure) + if (vm->callframes.count) + frame = uc_vm_current_frame(vm); + + if (!frame || !frame->closure) return false; chunk = uc_vm_frame_chunk(frame); @@ -744,11 +794,11 @@ uc_vm_handle_exception(uc_vm *vm) } static uc_value_t * -uc_vm_capture_stacktrace(uc_vm *vm, size_t i) +uc_vm_capture_stacktrace(uc_vm_t *vm, size_t i) { uc_value_t *stacktrace, *entry, *last = NULL; uc_function_t *function; - uc_callframe *frame; + uc_callframe_t *frame; size_t off, srcpos; char *name; @@ -762,7 +812,7 @@ uc_vm_capture_stacktrace(uc_vm *vm, size_t i) function = frame->closure->function; off = (frame->ip - uc_vm_frame_chunk(frame)->entries) - 1; - srcpos = ucv_function_srcpos((uc_value_t *)function, off); + srcpos = ucv_function_srcpos(&function->header, off); 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))); @@ -785,7 +835,7 @@ uc_vm_capture_stacktrace(uc_vm *vm, size_t i) ucv_object_add(entry, "function", ucv_string_new(name)); } - if (!ucv_equal(last, entry)) { + if (!ucv_is_equal(last, entry)) { ucv_array_push(stacktrace, entry); last = entry; } @@ -798,12 +848,12 @@ uc_vm_capture_stacktrace(uc_vm *vm, size_t i) } static uc_value_t * -uc_vm_get_error_context(uc_vm *vm) +uc_vm_get_error_context(uc_vm_t *vm) { uc_value_t *stacktrace; - uc_callframe *frame; + uc_callframe_t *frame; uc_stringbuf_t *buf; - uc_chunk *chunk; + uc_chunk_t *chunk; size_t offset, i; /* skip to first non-native function call frame */ @@ -817,13 +867,13 @@ uc_vm_get_error_context(uc_vm *vm) return NULL; chunk = uc_vm_frame_chunk(frame); - offset = ucv_function_srcpos((uc_value_t *)frame->closure->function, (frame->ip - chunk->entries) - 1); + offset = ucv_function_srcpos(&frame->closure->function->header, (frame->ip - chunk->entries) - 1); stacktrace = uc_vm_capture_stacktrace(vm, i); buf = ucv_stringbuf_new(); if (offset) - format_error_context(buf, frame->closure->function->source, stacktrace, offset); + uc_error_context_format(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 @@ -835,7 +885,7 @@ uc_vm_get_error_context(uc_vm *vm) } void __attribute__((format(printf, 3, 0))) -uc_vm_raise_exception(uc_vm *vm, uc_exception_type_t type, const char *fmt, ...) +uc_vm_raise_exception(uc_vm_t *vm, uc_exception_type_t type, const char *fmt, ...) { va_list ap; @@ -853,7 +903,7 @@ uc_vm_raise_exception(uc_vm *vm, uc_exception_type_t type, const char *fmt, ...) static void -uc_vm_insn_load(uc_vm *vm, enum insn_type insn) +uc_vm_insn_load(uc_vm_t *vm, uc_vm_insn_t insn) { switch (insn) { case I_LOAD: @@ -878,7 +928,7 @@ 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_vm_insn_load_regexp(uc_vm_t *vm, uc_vm_insn_t 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; @@ -910,19 +960,19 @@ uc_vm_insn_load_regexp(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_load_null(uc_vm *vm, enum insn_type insn) +uc_vm_insn_load_null(uc_vm_t *vm, uc_vm_insn_t insn) { uc_vm_stack_push(vm, NULL); } static void -uc_vm_insn_load_bool(uc_vm *vm, enum insn_type insn) +uc_vm_insn_load_bool(uc_vm_t *vm, uc_vm_insn_t insn) { 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) +uc_vm_insn_load_var(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *name, *val = NULL; uc_value_t *scope, *next; @@ -958,7 +1008,7 @@ uc_vm_insn_load_var(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_load_val(uc_vm *vm, enum insn_type insn) +uc_vm_insn_load_val(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *k = uc_vm_stack_pop(vm); uc_value_t *v = uc_vm_stack_pop(vm); @@ -966,7 +1016,7 @@ uc_vm_insn_load_val(uc_vm *vm, enum insn_type insn) switch (ucv_type(v)) { case UC_OBJECT: case UC_ARRAY: - uc_vm_stack_push(vm, uc_getval(vm, v, k)); + uc_vm_stack_push(vm, ucv_key_get(vm, v, k)); break; default: @@ -982,10 +1032,10 @@ uc_vm_insn_load_val(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_load_upval(uc_vm *vm, enum insn_type insn) +uc_vm_insn_load_upval(uc_vm_t *vm, uc_vm_insn_t insn) { - uc_callframe *frame = uc_vm_current_frame(vm); - uc_upvalref_t *ref = frame->closure->upvals[vm->arg.u32]; + uc_callframe_t *frame = uc_vm_current_frame(vm); + uc_upval_tref_t *ref = frame->closure->upvals[vm->arg.u32]; if (ref->closed) uc_vm_stack_push(vm, ucv_get(ref->value)); @@ -994,19 +1044,19 @@ uc_vm_insn_load_upval(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_load_local(uc_vm *vm, enum insn_type insn) +uc_vm_insn_load_local(uc_vm_t *vm, uc_vm_insn_t insn) { - uc_callframe *frame = uc_vm_current_frame(vm); + uc_callframe_t *frame = uc_vm_current_frame(vm); uc_vm_stack_push(vm, ucv_get(vm->stack.entries[frame->stackframe + vm->arg.u32])); } -static uc_upvalref_t * -uc_vm_capture_upval(uc_vm *vm, size_t slot) +static uc_upval_tref_t * +uc_vm_capture_upval(uc_vm_t *vm, size_t slot) { - uc_upvalref_t *curr = vm->open_upvals; - uc_upvalref_t *prev = NULL; - uc_upvalref_t *created; + uc_upval_tref_t *curr = vm->open_upvals; + uc_upval_tref_t *prev = NULL; + uc_upval_tref_t *created; char *s; while (curr && curr->slot > slot) { @@ -1024,7 +1074,7 @@ uc_vm_capture_upval(uc_vm *vm, size_t slot) return curr; } - created = (uc_upvalref_t *)ucv_upvalref_new(slot); + created = (uc_upval_tref_t *)ucv_upvalref_new(slot); created->next = curr; if (vm->trace) { @@ -1042,9 +1092,9 @@ uc_vm_capture_upval(uc_vm *vm, size_t slot) } static void -uc_vm_close_upvals(uc_vm *vm, size_t slot) +uc_vm_close_upvals(uc_vm_t *vm, size_t slot) { - uc_upvalref_t *ref; + uc_upval_tref_t *ref; while (vm->open_upvals && vm->open_upvals->slot >= slot) { ref = vm->open_upvals; @@ -1063,9 +1113,9 @@ uc_vm_close_upvals(uc_vm *vm, size_t slot) } static void -uc_vm_insn_load_closure(uc_vm *vm, enum insn_type insn) +uc_vm_insn_load_closure(uc_vm_t *vm, uc_vm_insn_t insn) { - uc_callframe *frame = uc_vm_current_frame(vm); + uc_callframe_t *frame = uc_vm_current_frame(vm); 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); @@ -1094,7 +1144,7 @@ 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) +uc_vm_insn_store_var(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *name, *v = uc_vm_stack_pop(vm); uc_value_t *scope, *next; @@ -1132,7 +1182,7 @@ uc_vm_insn_store_var(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_store_val(uc_vm *vm, enum insn_type insn) +uc_vm_insn_store_val(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *v = uc_vm_stack_pop(vm); uc_value_t *k = uc_vm_stack_pop(vm); @@ -1141,7 +1191,7 @@ uc_vm_insn_store_val(uc_vm *vm, enum insn_type insn) switch (ucv_type(o)) { case UC_OBJECT: case UC_ARRAY: - uc_vm_stack_push(vm, uc_setval(vm, o, k, v)); + uc_vm_stack_push(vm, ucv_key_set(vm, o, k, v)); break; default: @@ -1155,10 +1205,10 @@ uc_vm_insn_store_val(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_store_upval(uc_vm *vm, enum insn_type insn) +uc_vm_insn_store_upval(uc_vm_t *vm, uc_vm_insn_t insn) { - uc_callframe *frame = uc_vm_current_frame(vm); - uc_upvalref_t *ref = frame->closure->upvals[vm->arg.u32]; + uc_callframe_t *frame = uc_vm_current_frame(vm); + uc_upval_tref_t *ref = frame->closure->upvals[vm->arg.u32]; uc_value_t *val = ucv_get(uc_vm_stack_peek(vm, 0)); if (ref->closed) { @@ -1171,25 +1221,25 @@ uc_vm_insn_store_upval(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_store_local(uc_vm *vm, enum insn_type insn) +uc_vm_insn_store_local(uc_vm_t *vm, uc_vm_insn_t insn) { - uc_callframe *frame = uc_vm_current_frame(vm); + uc_callframe_t *frame = uc_vm_current_frame(vm); uc_value_t *val = ucv_get(uc_vm_stack_peek(vm, 0)); uc_vm_stack_set(vm, frame->stackframe + vm->arg.u32, val); } static uc_value_t * -uc_vm_value_bitop(uc_vm *vm, enum insn_type operation, uc_value_t *value, uc_value_t *operand) +uc_vm_value_bitop(uc_vm_t *vm, uc_vm_insn_t operation, uc_value_t *value, uc_value_t *operand) { uc_value_t *rv = NULL; int64_t n1, n2; double d; - if (uc_cast_number(value, &n1, &d) == UC_DOUBLE) + if (ucv_cast_number(value, &n1, &d) == UC_DOUBLE) n1 = isnan(d) ? 0 : (int64_t)d; - if (uc_cast_number(operand, &n2, &d) == UC_DOUBLE) + if (ucv_cast_number(operand, &n2, &d) == UC_DOUBLE) n2 = isnan(d) ? 0 : (int64_t)d; switch (operation) { @@ -1221,7 +1271,7 @@ uc_vm_value_bitop(uc_vm *vm, enum insn_type operation, uc_value_t *value, uc_val } static uc_value_t * -uc_vm_value_arith(uc_vm *vm, enum insn_type operation, uc_value_t *value, uc_value_t *operand) +uc_vm_value_arith(uc_vm_t *vm, uc_vm_insn_t operation, uc_value_t *value, uc_value_t *operand) { uc_value_t *rv = NULL; uc_type_t t1, t2; @@ -1253,8 +1303,8 @@ uc_vm_value_arith(uc_vm *vm, enum insn_type operation, uc_value_t *value, uc_val return rv; } - t1 = uc_cast_number(value, &n1, &d1); - t2 = uc_cast_number(operand, &n2, &d2); + t1 = ucv_cast_number(value, &n1, &d1); + t2 = ucv_cast_number(operand, &n2, &d2); if (t1 == UC_DOUBLE || t2 == UC_DOUBLE) { d1 = (t1 == UC_DOUBLE) ? d1 : (double)n1; @@ -1336,7 +1386,7 @@ uc_vm_value_arith(uc_vm *vm, enum insn_type operation, uc_value_t *value, uc_val } static void -uc_vm_insn_update_var(uc_vm *vm, enum insn_type insn) +uc_vm_insn_update_var(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *name, *val, *inc = uc_vm_stack_pop(vm); uc_value_t *scope, *next; @@ -1378,7 +1428,7 @@ uc_vm_insn_update_var(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_update_val(uc_vm *vm, enum insn_type insn) +uc_vm_insn_update_val(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *inc = uc_vm_stack_pop(vm); uc_value_t *k = uc_vm_stack_pop(vm); @@ -1388,8 +1438,8 @@ uc_vm_insn_update_val(uc_vm *vm, enum insn_type insn) 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))); + val = ucv_key_get(vm, v, k); + uc_vm_stack_push(vm, ucv_key_set(vm, v, k, uc_vm_value_arith(vm, vm->arg.u8, val, inc))); break; default: @@ -1407,11 +1457,11 @@ uc_vm_insn_update_val(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_update_upval(uc_vm *vm, enum insn_type insn) +uc_vm_insn_update_upval(uc_vm_t *vm, uc_vm_insn_t insn) { - uc_callframe *frame = uc_vm_current_frame(vm); + uc_callframe_t *frame = uc_vm_current_frame(vm); size_t slot = vm->arg.u32 & 0x00FFFFFF; - uc_upvalref_t *ref = frame->closure->upvals[slot]; + uc_upval_tref_t *ref = frame->closure->upvals[slot]; uc_value_t *inc = uc_vm_stack_pop(vm); uc_value_t *val; @@ -1436,9 +1486,9 @@ uc_vm_insn_update_upval(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_update_local(uc_vm *vm, enum insn_type insn) +uc_vm_insn_update_local(uc_vm_t *vm, uc_vm_insn_t insn) { - uc_callframe *frame = uc_vm_current_frame(vm); + uc_callframe_t *frame = uc_vm_current_frame(vm); size_t slot = vm->arg.u32 & 0x00FFFFFF; uc_value_t *inc = uc_vm_stack_pop(vm); uc_value_t *val; @@ -1453,7 +1503,7 @@ uc_vm_insn_update_local(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_narr(uc_vm *vm, enum insn_type insn) +uc_vm_insn_narr(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *arr = ucv_array_new_length(vm, vm->arg.u32); @@ -1461,7 +1511,7 @@ uc_vm_insn_narr(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_parr(uc_vm *vm, enum insn_type insn) +uc_vm_insn_parr(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *arr = uc_vm_stack_peek(vm, vm->arg.u32); size_t idx; @@ -1476,7 +1526,7 @@ uc_vm_insn_parr(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_marr(uc_vm *vm, enum insn_type insn) +uc_vm_insn_marr(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *src = uc_vm_stack_pop(vm); uc_value_t *dst = uc_vm_stack_peek(vm, 0); @@ -1499,7 +1549,7 @@ uc_vm_insn_marr(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_nobj(uc_vm *vm, enum insn_type insn) +uc_vm_insn_nobj(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *obj = ucv_object_new(vm); @@ -1507,7 +1557,7 @@ uc_vm_insn_nobj(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_sobj(uc_vm *vm, enum insn_type insn) +uc_vm_insn_sobj(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *obj = uc_vm_stack_peek(vm, vm->arg.u32); uc_value_t *val; @@ -1525,7 +1575,7 @@ uc_vm_insn_sobj(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_mobj(uc_vm *vm, enum insn_type insn) +uc_vm_insn_mobj(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *src = uc_vm_stack_pop(vm); uc_value_t *dst = uc_vm_stack_peek(vm, 0); @@ -1561,7 +1611,7 @@ uc_vm_insn_mobj(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_arith(uc_vm *vm, enum insn_type insn) +uc_vm_insn_arith(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *r2 = uc_vm_stack_pop(vm); uc_value_t *r1 = uc_vm_stack_pop(vm); @@ -1576,7 +1626,7 @@ 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) +uc_vm_insn_plus_minus(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *v = uc_vm_stack_pop(vm); bool is_sub = (insn == I_MINUS); @@ -1584,7 +1634,7 @@ uc_vm_insn_plus_minus(uc_vm *vm, enum insn_type insn) int64_t n; double d; - t = uc_cast_number(v, &n, &d); + t = ucv_cast_number(v, &n, &d); ucv_put(v); @@ -1600,7 +1650,7 @@ 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) +uc_vm_insn_bitop(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *r2 = uc_vm_stack_pop(vm); uc_value_t *r1 = uc_vm_stack_pop(vm); @@ -1615,13 +1665,13 @@ uc_vm_insn_bitop(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_complement(uc_vm *vm, enum insn_type insn) +uc_vm_insn_complement(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *v = uc_vm_stack_pop(vm); int64_t n; double d; - if (uc_cast_number(v, &n, &d) == UC_DOUBLE) + if (ucv_cast_number(v, &n, &d) == UC_DOUBLE) n = isnan(d) ? 0 : (int64_t)d; ucv_put(v); @@ -1630,12 +1680,12 @@ uc_vm_insn_complement(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_rel(uc_vm *vm, enum insn_type insn) +uc_vm_insn_rel(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *r2 = uc_vm_stack_pop(vm); uc_value_t *r1 = uc_vm_stack_pop(vm); - bool res = uc_cmp(insn, r1, r2); + bool res = ucv_compare(insn, r1, r2); ucv_put(r1); ucv_put(r2); @@ -1644,7 +1694,7 @@ uc_vm_insn_rel(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_in(uc_vm *vm, enum insn_type insn) +uc_vm_insn_in(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *r2 = uc_vm_stack_pop(vm); uc_value_t *r1 = uc_vm_stack_pop(vm); @@ -1659,7 +1709,7 @@ uc_vm_insn_in(uc_vm *vm, enum insn_type insn) arridx < arrlen; arridx++) { item = ucv_array_get(r2, arridx); - if (uc_cmp(I_EQ, r1, item)) { + if (ucv_compare(I_EQ, r1, item)) { found = true; break; } @@ -1690,14 +1740,14 @@ uc_vm_insn_in(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_equality(uc_vm *vm, enum insn_type insn) +uc_vm_insn_equality(uc_vm_t *vm, uc_vm_insn_t insn) { 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); + equal = ucv_is_equal(r1, r2); else equal = (r1 == r2); @@ -1708,19 +1758,19 @@ uc_vm_insn_equality(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_not(uc_vm *vm, enum insn_type insn) +uc_vm_insn_not(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *r1 = uc_vm_stack_pop(vm); - uc_vm_stack_push(vm, ucv_boolean_new(!uc_val_is_truish(r1))); + uc_vm_stack_push(vm, ucv_boolean_new(!ucv_is_truish(r1))); ucv_put(r1); } static void -uc_vm_insn_jmp(uc_vm *vm, enum insn_type insn) +uc_vm_insn_jmp(uc_vm_t *vm, uc_vm_insn_t insn) { - uc_callframe *frame = uc_vm_current_frame(vm); - uc_chunk *chunk = uc_vm_frame_chunk(frame); + uc_callframe_t *frame = uc_vm_current_frame(vm); + uc_chunk_t *chunk = uc_vm_frame_chunk(frame); int32_t addr = vm->arg.s32; /* ip already has been incremented */ @@ -1736,10 +1786,10 @@ uc_vm_insn_jmp(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_jmpz(uc_vm *vm, enum insn_type insn) +uc_vm_insn_jmpz(uc_vm_t *vm, uc_vm_insn_t insn) { - uc_callframe *frame = uc_vm_current_frame(vm); - uc_chunk *chunk = uc_vm_frame_chunk(frame); + uc_callframe_t *frame = uc_vm_current_frame(vm); + uc_chunk_t *chunk = uc_vm_frame_chunk(frame); uc_value_t *v = uc_vm_stack_pop(vm); int32_t addr = vm->arg.s32; @@ -1752,14 +1802,14 @@ uc_vm_insn_jmpz(uc_vm *vm, enum insn_type insn) return; } - if (!uc_val_is_truish(v)) + if (!ucv_is_truish(v)) frame->ip += addr; ucv_put(v); } static void -uc_vm_insn_next(uc_vm *vm, enum insn_type insn) +uc_vm_insn_next(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *k = uc_vm_stack_pop(vm); uc_value_t *v = uc_vm_stack_pop(vm); @@ -1832,14 +1882,14 @@ uc_vm_insn_next(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_close_upval(uc_vm *vm, enum insn_type insn) +uc_vm_insn_close_upval(uc_vm_t *vm, uc_vm_insn_t insn) { uc_vm_close_upvals(vm, vm->stack.count - 1); ucv_put(uc_vm_stack_pop(vm)); } static void -uc_vm_insn_call(uc_vm *vm, enum insn_type insn) +uc_vm_insn_call(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *fno = ucv_get(uc_vm_stack_peek(vm, vm->arg.u32 & 0xffff)); uc_value_t *ctx = NULL; @@ -1853,12 +1903,12 @@ uc_vm_insn_call(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_mcall(uc_vm *vm, enum insn_type insn) +uc_vm_insn_mcall(uc_vm_t *vm, uc_vm_insn_t insn) { size_t key_slot = vm->stack.count - (vm->arg.u32 & 0xffff) - 1; 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_value_t *fno = ucv_key_get(vm, ctx, key); uc_vm_stack_set(vm, key_slot, fno); @@ -1870,7 +1920,7 @@ uc_vm_insn_mcall(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_print(uc_vm *vm, enum insn_type insn) +uc_vm_insn_print(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *v = uc_vm_stack_pop(vm); char *p; @@ -1900,7 +1950,7 @@ uc_vm_insn_print(uc_vm *vm, enum insn_type insn) } static void -uc_vm_insn_delete(uc_vm *vm, enum insn_type insn) +uc_vm_insn_delete(uc_vm_t *vm, uc_vm_insn_t insn) { uc_value_t *k = uc_vm_stack_pop(vm); uc_value_t *v = uc_vm_stack_pop(vm); @@ -1908,7 +1958,7 @@ uc_vm_insn_delete(uc_vm *vm, enum insn_type insn) switch (ucv_type(v)) { case UC_OBJECT: - rv = uc_delval(vm, v, k); + rv = ucv_key_delete(vm, v, k); uc_vm_stack_push(vm, ucv_boolean_new(rv)); break; @@ -1925,9 +1975,9 @@ uc_vm_insn_delete(uc_vm *vm, enum insn_type insn) } static uc_value_t * -uc_vm_callframe_pop(uc_vm *vm) +uc_vm_callframe_pop(uc_vm_t *vm) { - uc_callframe *frame = uc_vm_current_frame(vm); + uc_callframe_t *frame = uc_vm_current_frame(vm); uc_value_t *retval; /* close upvalues */ @@ -1947,8 +1997,11 @@ uc_vm_callframe_pop(uc_vm *vm) ucv_put(uc_vm_stack_pop(vm)); /* release function */ - ucv_put((uc_value_t *)frame->closure); - ucv_put((uc_value_t *)frame->cfunction); + if (frame->closure) + ucv_put(&frame->closure->header); + + if (frame->cfunction) + ucv_put(&frame->cfunction->header); /* release context */ ucv_put(frame->ctx); @@ -1959,29 +2012,32 @@ uc_vm_callframe_pop(uc_vm *vm) } static void -uc_vm_output_exception(uc_vm *vm) +uc_vm_output_exception(uc_vm_t *vm, uc_exception_t *ex) { uc_value_t *ctx; - if (vm->exception.type == EXCEPTION_USER) - fprintf(stderr, "%s\n", vm->exception.message); + if (ex->type == EXCEPTION_USER) + fprintf(stderr, "%s\n", ex->message); else fprintf(stderr, "%s: %s\n", - exception_type_strings[vm->exception.type] ? exception_type_strings[vm->exception.type] : "Error", - vm->exception.message); + exception_type_strings[ex->type] ? exception_type_strings[ex->type] : "Error", + ex->message); + + ctx = ucv_object_get(ucv_array_get(ex->stacktrace, 0), "context", NULL); - ctx = ucv_object_get(ucv_array_get(vm->exception.stacktrace, 0), "context", NULL); + if (ctx) + fprintf(stderr, "%s\n", ucv_string_get(ctx)); - fprintf(stderr, "%s\n\n", ucv_string_get(ctx)); + fprintf(stderr, "\n"); } static uc_vm_status_t -uc_vm_execute_chunk(uc_vm *vm) +uc_vm_execute_chunk(uc_vm_t *vm, uc_value_t **retvalp) { - uc_callframe *frame = uc_vm_current_frame(vm); - uc_chunk *chunk = uc_vm_frame_chunk(frame); + uc_callframe_t *frame = uc_vm_current_frame(vm); + uc_chunk_t *chunk = uc_vm_frame_chunk(frame); uc_value_t *retval; - enum insn_type insn; + uc_vm_insn_t insn; while (chunk) { if (vm->trace) @@ -2179,7 +2235,10 @@ uc_vm_execute_chunk(uc_vm *vm) retval = uc_vm_callframe_pop(vm); if (vm->callframes.count == 0) { - ucv_put(retval); + if (retvalp) + *retvalp = retval; + else + ucv_put(retval); return STATUS_OK; } @@ -2205,11 +2264,22 @@ uc_vm_execute_chunk(uc_vm *vm) /* previous instruction raised exception */ if (vm->exception.type != EXCEPTION_NONE) { + /* VM termination was requested */ + if (vm->exception.type == EXCEPTION_EXIT) { + uc_vm_reset_callframes(vm); + + if (retvalp) + *retvalp = ucv_int64_new(vm->arg.s32); + + return STATUS_EXIT; + } + /* walk up callframes until something handles the exception or the root is reached */ while (!uc_vm_handle_exception(vm)) { /* no further callframe to pop, report unhandled exception and terminate */ - if (vm->callframes.count == 1) { - uc_vm_output_exception(vm); + if (vm->callframes.count <= 1) { + if (vm->exhandler) + vm->exhandler(vm, &vm->exception); return ERROR_RUNTIME; } @@ -2231,50 +2301,12 @@ uc_vm_execute_chunk(uc_vm *vm) return STATUS_OK; } -static uc_vm_status_t -uc_vm_preload(uc_vm *vm, uc_value_t *modules) -{ - uc_value_t *requirefn, *module, *name; - uc_exception_type_t ex; - size_t i; - - if (ucv_type(modules) != UC_ARRAY) - return STATUS_OK; - - requirefn = ucv_property_get(vm->globals, "require"); - - if (ucv_type(requirefn) != UC_CFUNCTION) - return STATUS_OK; - - for (i = 0; i < ucv_array_length(modules); i++) { - name = ucv_array_get(modules, i); - - uc_vm_stack_push(vm, ucv_get(requirefn)); - uc_vm_stack_push(vm, ucv_get(name)); - - ex = uc_vm_call(vm, false, 1); - - if (ex) - return ERROR_RUNTIME; - - module = uc_vm_stack_pop(vm); - - ucv_put(uc_setval(vm, vm->globals, name, module)); - } - - return STATUS_OK; -} - uc_vm_status_t -uc_vm_execute(uc_vm *vm, uc_function_t *fn, uc_value_t *globals, uc_value_t *modules) +uc_vm_execute(uc_vm_t *vm, uc_function_t *fn, uc_value_t **retval) { uc_closure_t *closure = (uc_closure_t *)ucv_closure_new(vm, fn, false); - uc_callframe *frame; + uc_callframe_t *frame; uc_stringbuf_t *buf; - uc_vm_status_t rv; - - vm->globals = globals; - ucv_get(globals); uc_vector_grow(&vm->callframes); @@ -2287,7 +2319,7 @@ uc_vm_execute(uc_vm *vm, uc_function_t *fn, uc_value_t *globals, uc_value_t *mod if (vm->trace) { buf = xprintbuf_new(); - format_source_context(buf, fn->source, 0, true); + uc_source_context_format(buf, fn->source, 0, true); fwrite(buf->buf, 1, printbuf_length(buf), stderr); printbuf_free(buf); @@ -2298,29 +2330,91 @@ uc_vm_execute(uc_vm *vm, uc_function_t *fn, uc_value_t *globals, uc_value_t *mod //uc_vm_stack_push(vm, closure->header.jso); uc_vm_stack_push(vm, NULL); - rv = uc_vm_preload(vm, modules); - - if (rv != STATUS_OK) - uc_vm_output_exception(vm); - else - rv = uc_vm_execute_chunk(vm); + if (retval) + *retval = NULL; - ucv_put(vm->globals); - vm->globals = NULL; - - return rv; + return uc_vm_execute_chunk(vm, retval); } uc_exception_type_t -uc_vm_call(uc_vm *vm, bool mcall, size_t nargs) +uc_vm_call(uc_vm_t *vm, bool mcall, size_t 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 (ucv_type(fno) != UC_CFUNCTION) - uc_vm_execute_chunk(vm); + uc_vm_execute_chunk(vm, NULL); } return vm->exception.type; } + +uc_value_t * +uc_vm_scope_get(uc_vm_t *vm) +{ + return vm->globals; +} + +void +uc_vm_scope_set(uc_vm_t *vm, uc_value_t *ctx) +{ + ucv_put(vm->globals); + vm->globals = ctx; +} + +uc_value_t * +uc_vm_invoke(uc_vm_t *vm, const char *fname, size_t nargs, ...) +{ + uc_exception_type_t ex; + uc_value_t *fno, *arg; + va_list ap; + size_t i; + + fno = ucv_property_get(vm->globals, fname); + + if (!ucv_is_callable(fno)) + return NULL; + + uc_vm_stack_push(vm, ucv_get(fno)); + + va_start(ap, nargs); + + for (i = 0; i < nargs; i++) { + arg = va_arg(ap, uc_value_t *); + uc_vm_stack_push(vm, ucv_get(arg)); + } + + va_end(ap); + + ex = uc_vm_call(vm, false, nargs); + + if (ex) + return NULL; + + return uc_vm_stack_pop(vm); +} + +uc_exception_handler_t * +uc_vm_exception_handler_get(uc_vm_t *vm) +{ + return vm->exhandler; +} + +void +uc_vm_exception_handler_set(uc_vm_t *vm, uc_exception_handler_t *exhandler) +{ + vm->exhandler = exhandler; +} + +uint32_t +uc_vm_trace_get(uc_vm_t *vm) +{ + return vm->trace; +} + +void +uc_vm_trace_set(uc_vm_t *vm, uint32_t level) +{ + vm->trace = level; +} |