From b63faf66a0a7d471127d9a57e6a7cb21271517ca Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Tue, 23 Jul 2019 19:42:25 +0300 Subject: [PATCH] Moving njs.c functions into njs_vm.c and njs_value.c NO functional changes. --- auto/sources | 1 - njs/njs.c | 1105 ----------------------------------------------- njs/njs_value.c | 123 ++++++ njs/njs_vm.c | 975 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1098 insertions(+), 1106 deletions(-) delete mode 100644 njs/njs.c diff --git a/auto/sources b/auto/sources index 06867db2..20e5ac87 100644 --- a/auto/sources +++ b/auto/sources @@ -29,7 +29,6 @@ NXT_TEST_SRCS=" \ " NJS_LIB_SRCS=" \ - njs/njs.c \ njs/njs_value.c \ njs/njs_vm.c \ njs/njs_vmcode.c \ diff --git a/njs/njs.c b/njs/njs.c deleted file mode 100644 index 25fecca0..00000000 --- a/njs/njs.c +++ /dev/null @@ -1,1105 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include -#include -#include - - -static nxt_int_t njs_vm_init(njs_vm_t *vm); -static nxt_int_t njs_vm_handle_events(njs_vm_t *vm); - - -static void * -njs_alloc(void *mem, size_t size) -{ - return nxt_malloc(size); -} - - -static void * -njs_zalloc(void *mem, size_t size) -{ - void *p; - - p = nxt_malloc(size); - - if (p != NULL) { - nxt_memzero(p, size); - } - - return p; -} - - -static void * -njs_align(void *mem, size_t alignment, size_t size) -{ - return nxt_memalign(alignment, size); -} - - -static void -njs_free(void *mem, void *p) -{ - nxt_free(p); -} - - -const nxt_mem_proto_t njs_vm_mp_proto = { - njs_alloc, - njs_zalloc, - njs_align, - NULL, - njs_free, - NULL, - NULL, -}; - - -static void * -njs_array_mem_alloc(void *mem, size_t size) -{ - return nxt_mp_alloc(mem, size); -} - - -static void -njs_array_mem_free(void *mem, void *p) -{ - nxt_mp_free(mem, p); -} - - -const nxt_mem_proto_t njs_array_mem_proto = { - njs_array_mem_alloc, - NULL, - NULL, - NULL, - njs_array_mem_free, - NULL, - NULL, -}; - - -njs_vm_t * -njs_vm_create(njs_vm_opt_t *options) -{ - nxt_mp_t *mp; - njs_vm_t *vm; - nxt_int_t ret; - nxt_array_t *debug; - njs_regexp_pattern_t *pattern; - - mp = nxt_mp_create(&njs_vm_mp_proto, NULL, NULL, 2 * nxt_pagesize(), - 128, 512, 16); - if (nxt_slow_path(mp == NULL)) { - return NULL; - } - - vm = nxt_mp_zalign(mp, sizeof(njs_value_t), sizeof(njs_vm_t)); - - if (nxt_fast_path(vm != NULL)) { - vm->mem_pool = mp; - - ret = njs_regexp_init(vm); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - vm->options = *options; - - if (options->shared != NULL) { - vm->shared = options->shared; - - } else { - vm->shared = nxt_mp_zalloc(mp, sizeof(njs_vm_shared_t)); - if (nxt_slow_path(vm->shared == NULL)) { - return NULL; - } - - options->shared = vm->shared; - - nxt_lvlhsh_init(&vm->shared->keywords_hash); - - ret = njs_lexer_keywords_init(mp, &vm->shared->keywords_hash); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - nxt_lvlhsh_init(&vm->shared->values_hash); - - pattern = njs_regexp_pattern_create(vm, (u_char *) "(?:)", - nxt_length("(?:)"), 0); - if (nxt_slow_path(pattern == NULL)) { - return NULL; - } - - vm->shared->empty_regexp_pattern = pattern; - - nxt_lvlhsh_init(&vm->modules_hash); - - ret = njs_builtin_objects_create(vm); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - } - - nxt_lvlhsh_init(&vm->values_hash); - - vm->external = options->external; - - vm->external_objects = nxt_array_create(4, sizeof(void *), - &njs_array_mem_proto, - vm->mem_pool); - if (nxt_slow_path(vm->external_objects == NULL)) { - return NULL; - } - - nxt_lvlhsh_init(&vm->externals_hash); - nxt_lvlhsh_init(&vm->external_prototypes_hash); - - vm->trace.level = NXT_LEVEL_TRACE; - vm->trace.size = 2048; - vm->trace.handler = njs_parser_trace_handler; - vm->trace.data = vm; - - if (options->backtrace) { - debug = nxt_array_create(4, sizeof(njs_function_debug_t), - &njs_array_mem_proto, vm->mem_pool); - if (nxt_slow_path(debug == NULL)) { - return NULL; - } - - vm->debug = debug; - } - - if (options->accumulative) { - ret = njs_vm_init(vm); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - } - } - - return vm; -} - - -void -njs_vm_destroy(njs_vm_t *vm) -{ - njs_event_t *event; - nxt_lvlhsh_each_t lhe; - - if (njs_waiting_events(vm)) { - nxt_lvlhsh_each_init(&lhe, &njs_event_hash_proto); - - for ( ;; ) { - event = nxt_lvlhsh_each(&vm->events_hash, &lhe); - - if (event == NULL) { - break; - } - - njs_del_event(vm, event, NJS_EVENT_RELEASE); - } - } - - nxt_mp_destroy(vm->mem_pool); -} - - -nxt_int_t -njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end) -{ - nxt_int_t ret; - njs_lexer_t lexer; - njs_parser_t *parser, *prev; - njs_generator_t generator; - njs_parser_scope_t *scope; - - if (vm->parser != NULL && !vm->options.accumulative) { - return NJS_ERROR; - } - - if (vm->modules != NULL && vm->options.accumulative) { - njs_module_reset(vm); - } - - parser = nxt_mp_zalloc(vm->mem_pool, sizeof(njs_parser_t)); - if (nxt_slow_path(parser == NULL)) { - return NJS_ERROR; - } - - prev = vm->parser; - vm->parser = parser; - - ret = njs_lexer_init(vm, &lexer, &vm->options.file, *start, end); - if (nxt_slow_path(ret != NXT_OK)) { - return NJS_ERROR; - } - - parser->lexer = &lexer; - - if (vm->backtrace != NULL) { - nxt_array_reset(vm->backtrace); - } - - vm->retval = njs_value_undefined; - - ret = njs_parser(vm, parser, prev); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - parser->lexer = NULL; - - scope = parser->scope; - - ret = njs_variables_scope_reference(vm, scope); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - *start = lexer.start; - - /* - * Reset the code array to prevent it from being disassembled - * again in the next iteration of the accumulative mode. - */ - vm->code = NULL; - - nxt_memzero(&generator, sizeof(njs_generator_t)); - - ret = njs_generate_scope(vm, &generator, scope, &njs_entry_main); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - vm->current = generator.code_start; - vm->global_scope = generator.local_scope; - vm->scope_size = generator.scope_size; - - vm->variables_hash = scope->variables; - - if (vm->options.init) { - ret = njs_vm_init(vm); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - } - - return NJS_OK; - -fail: - - vm->parser = prev; - - return NXT_ERROR; -} - - -njs_vm_t * -njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external) -{ - nxt_mp_t *nmp; - njs_vm_t *nvm; - uint32_t items; - nxt_int_t ret; - nxt_array_t *externals; - - nxt_thread_log_debug("CLONE:"); - - if (vm->options.accumulative) { - return NULL; - } - - nmp = nxt_mp_create(&njs_vm_mp_proto, NULL, NULL, 2 * nxt_pagesize(), - 128, 512, 16); - if (nxt_slow_path(nmp == NULL)) { - return NULL; - } - - nvm = nxt_mp_zalign(nmp, sizeof(njs_value_t), sizeof(njs_vm_t)); - - if (nxt_fast_path(nvm != NULL)) { - nvm->mem_pool = nmp; - - nvm->shared = vm->shared; - - nvm->trace = vm->trace; - nvm->trace.data = nvm; - - nvm->variables_hash = vm->variables_hash; - nvm->values_hash = vm->values_hash; - - nvm->modules = vm->modules; - nvm->modules_hash = vm->modules_hash; - - nvm->externals_hash = vm->externals_hash; - nvm->external_prototypes_hash = vm->external_prototypes_hash; - - items = vm->external_objects->items; - externals = nxt_array_create(items + 4, sizeof(void *), - &njs_array_mem_proto, nvm->mem_pool); - - if (nxt_slow_path(externals == NULL)) { - return NULL; - } - - if (items > 0) { - memcpy(externals->start, vm->external_objects->start, - items * sizeof(void *)); - externals->items = items; - } - - nvm->external_objects = externals; - - nvm->options = vm->options; - - nvm->current = vm->current; - - nvm->external = external; - - nvm->global_scope = vm->global_scope; - nvm->scope_size = vm->scope_size; - - nvm->debug = vm->debug; - - ret = njs_vm_init(nvm); - if (nxt_slow_path(ret != NXT_OK)) { - goto fail; - } - - return nvm; - } - -fail: - - nxt_mp_destroy(nmp); - - return NULL; -} - - -static nxt_int_t -njs_vm_init(njs_vm_t *vm) -{ - size_t size, scope_size; - u_char *values; - nxt_int_t ret; - njs_frame_t *frame; - nxt_array_t *backtrace; - - scope_size = vm->scope_size + NJS_INDEX_GLOBAL_OFFSET; - - size = NJS_GLOBAL_FRAME_SIZE + scope_size + NJS_FRAME_SPARE_SIZE; - size = nxt_align_size(size, NJS_FRAME_SPARE_SIZE); - - frame = nxt_mp_align(vm->mem_pool, sizeof(njs_value_t), size); - if (nxt_slow_path(frame == NULL)) { - return NXT_ERROR; - } - - nxt_memzero(frame, NJS_GLOBAL_FRAME_SIZE); - - vm->top_frame = &frame->native; - vm->active_frame = frame; - - frame->native.size = size; - frame->native.free_size = size - (NJS_GLOBAL_FRAME_SIZE + scope_size); - - values = (u_char *) frame + NJS_GLOBAL_FRAME_SIZE; - - frame->native.free = values + scope_size; - - vm->scopes[NJS_SCOPE_GLOBAL] = (njs_value_t *) values; - memcpy(values + NJS_INDEX_GLOBAL_OFFSET, vm->global_scope, - vm->scope_size); - - ret = njs_regexp_init(vm); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - ret = njs_builtin_objects_clone(vm); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - - nxt_lvlhsh_init(&vm->events_hash); - nxt_queue_init(&vm->posted_events); - - if (vm->debug != NULL) { - backtrace = nxt_array_create(4, sizeof(njs_backtrace_entry_t), - &njs_array_mem_proto, vm->mem_pool); - if (nxt_slow_path(backtrace == NULL)) { - return NXT_ERROR; - } - - vm->backtrace = backtrace; - } - - if (njs_is_null(&vm->retval)) { - vm->retval = njs_value_undefined; - } - - return NXT_OK; -} - - -nxt_int_t -njs_vm_call(njs_vm_t *vm, njs_function_t *function, const njs_value_t *args, - nxt_uint_t nargs) -{ - return njs_vm_invoke(vm, function, args, nargs, (njs_index_t) &vm->retval); -} - - -nxt_int_t -njs_vm_invoke(njs_vm_t *vm, njs_function_t *function, const njs_value_t *args, - nxt_uint_t nargs, njs_index_t retval) -{ - njs_ret_t ret; - njs_value_t *this; - - this = (njs_value_t *) &njs_value_undefined; - - ret = njs_function_frame(vm, function, this, (njs_value_t *) args, nargs, - 0); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - return njs_function_frame_invoke(vm, retval); -} - - -njs_vm_event_t -njs_vm_add_event(njs_vm_t *vm, njs_function_t *function, nxt_uint_t once, - njs_host_event_t host_ev, njs_event_destructor_t destructor) -{ - njs_event_t *event; - - event = nxt_mp_alloc(vm->mem_pool, sizeof(njs_event_t)); - if (nxt_slow_path(event == NULL)) { - return NULL; - } - - event->host_event = host_ev; - event->destructor = destructor; - event->function = function; - event->once = once; - event->posted = 0; - event->nargs = 0; - event->args = NULL; - - if (njs_add_event(vm, event) != NJS_OK) { - return NULL; - } - - return event; -} - - -void -njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event) -{ - njs_event_t *event; - - event = (njs_event_t *) vm_event; - - njs_del_event(vm, event, NJS_EVENT_RELEASE | NJS_EVENT_DELETE); -} - - -nxt_int_t -njs_vm_waiting(njs_vm_t *vm) -{ - return njs_waiting_events(vm); -} - - -nxt_int_t -njs_vm_posted(njs_vm_t *vm) -{ - return njs_posted_events(vm); -} - - -nxt_int_t -njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, - const njs_value_t *args, nxt_uint_t nargs) -{ - njs_event_t *event; - - event = (njs_event_t *) vm_event; - - if (nargs != 0 && !event->posted) { - event->nargs = nargs; - event->args = nxt_mp_alloc(vm->mem_pool, sizeof(njs_value_t) * nargs); - if (nxt_slow_path(event->args == NULL)) { - return NJS_ERROR; - } - - memcpy(event->args, args, sizeof(njs_value_t) * nargs); - } - - if (!event->posted) { - event->posted = 1; - nxt_queue_insert_tail(&vm->posted_events, &event->link); - } - - return NJS_OK; -} - - -nxt_int_t -njs_vm_run(njs_vm_t *vm) -{ - if (nxt_slow_path(vm->backtrace != NULL)) { - nxt_array_reset(vm->backtrace); - } - - return njs_vm_handle_events(vm); -} - - -nxt_int_t -njs_vm_start(njs_vm_t *vm) -{ - njs_ret_t ret; - - ret = njs_module_load(vm); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - ret = njs_vmcode_interpreter(vm); - - if (ret == NJS_STOP) { - ret = NJS_OK; - } - - return ret; -} - - -static nxt_int_t -njs_vm_handle_events(njs_vm_t *vm) -{ - nxt_int_t ret; - njs_event_t *ev; - nxt_queue_t *events; - nxt_queue_link_t *link; - - events = &vm->posted_events; - - for ( ;; ) { - link = nxt_queue_first(events); - - if (link == nxt_queue_tail(events)) { - break; - } - - ev = nxt_queue_link_data(link, njs_event_t, link); - - if (ev->once) { - njs_del_event(vm, ev, NJS_EVENT_RELEASE | NJS_EVENT_DELETE); - - } else { - ev->posted = 0; - nxt_queue_remove(&ev->link); - } - - ret = njs_vm_call(vm, ev->function, ev->args, ev->nargs); - - if (ret == NJS_ERROR) { - return ret; - } - } - - return njs_posted_events(vm) ? NJS_AGAIN : NJS_OK; -} - - -nxt_int_t -njs_vm_add_path(njs_vm_t *vm, const nxt_str_t *path) -{ - nxt_str_t *item; - - if (vm->paths == NULL) { - vm->paths = nxt_array_create(4, sizeof(nxt_str_t), - &njs_array_mem_proto, vm->mem_pool); - if (nxt_slow_path(vm->paths == NULL)) { - return NXT_ERROR; - } - } - - item = nxt_array_add(vm->paths, &njs_array_mem_proto, vm->mem_pool); - if (nxt_slow_path(item == NULL)) { - return NXT_ERROR; - } - - *item = *path; - - return NXT_OK; -} - - -njs_value_t * -njs_vm_retval(njs_vm_t *vm) -{ - return &vm->retval; -} - - -void -njs_vm_retval_set(njs_vm_t *vm, const njs_value_t *value) -{ - vm->retval = *value; -} - - -void -njs_value_undefined_set(njs_value_t *value) -{ - njs_set_undefined(value); -} - - -void -njs_value_boolean_set(njs_value_t *value, int yn) -{ - njs_set_boolean(value, yn); -} - - -void -njs_value_number_set(njs_value_t *value, double num) -{ - njs_set_number(value, num); -} - - -void -njs_value_data_set(njs_value_t *value, void *data) -{ - njs_set_data(value, data); -} - - -njs_ret_t -njs_vm_value_string_set(njs_vm_t *vm, njs_value_t *value, const u_char *start, - uint32_t size) -{ - return njs_string_set(vm, value, start, size); -} - - -u_char * -njs_vm_value_string_alloc(njs_vm_t *vm, njs_value_t *value, uint32_t size) -{ - return njs_string_alloc(vm, value, size, 0); -} - - -nxt_noinline void -njs_vm_value_error_set(njs_vm_t *vm, njs_value_t *value, const char *fmt, ...) -{ - va_list args; - u_char buf[NXT_MAX_ERROR_STR], *p; - - p = buf; - - if (fmt != NULL) { - va_start(args, fmt); - p = nxt_vsprintf(buf, buf + sizeof(buf), fmt, args); - va_end(args); - } - - njs_error_new(vm, value, NJS_OBJECT_ERROR, buf, p - buf); -} - - -uint8_t -njs_value_bool(const njs_value_t *value) -{ - return njs_bool(value); -} - - -double -njs_value_number(const njs_value_t *value) -{ - return njs_number(value); -} - - -void * -njs_value_data(const njs_value_t *value) -{ - return njs_data(value); -} - - -njs_function_t * -njs_value_function(const njs_value_t *value) -{ - return njs_function(value); -} - - -nxt_int_t -njs_value_is_null(const njs_value_t *value) -{ - return njs_is_null(value); -} - - -nxt_int_t -njs_value_is_undefined(const njs_value_t *value) -{ - return njs_is_undefined(value); -} - - -nxt_int_t -njs_value_is_null_or_undefined(const njs_value_t *value) -{ - return njs_is_null_or_undefined(value); -} - - -nxt_int_t -njs_value_is_boolean(const njs_value_t *value) -{ - return njs_is_boolean(value); -} - - -nxt_int_t -njs_value_is_number(const njs_value_t *value) -{ - return njs_is_number(value); -} - - -nxt_int_t -njs_value_is_valid_number(const njs_value_t *value) -{ - return njs_is_number(value) - && !isnan(njs_number(value)) - && !isinf(njs_number(value)); -} - - -nxt_int_t -njs_value_is_string(const njs_value_t *value) -{ - return njs_is_string(value); -} - - -nxt_int_t -njs_value_is_object(const njs_value_t *value) -{ - return njs_is_object(value); -} - - -nxt_int_t -njs_value_is_function(const njs_value_t *value) -{ - return njs_is_function(value); -} - - -nxt_noinline void -njs_vm_memory_error(njs_vm_t *vm) -{ - njs_memory_error_set(vm, &vm->retval); -} - - -nxt_array_t * -njs_vm_backtrace(njs_vm_t *vm) -{ - if (vm->backtrace != NULL && !nxt_array_is_empty(vm->backtrace)) { - return vm->backtrace; - } - - return NULL; -} - - -static njs_ret_t -njs_vm_backtrace_dump(njs_vm_t *vm, nxt_str_t *dst, const njs_value_t *src) -{ - u_char *p, *start, *end; - size_t len, count; - nxt_uint_t i; - nxt_array_t *backtrace; - njs_backtrace_entry_t *be, *prev; - - backtrace = njs_vm_backtrace(vm); - - len = dst->length + 1; - - count = 0; - prev = NULL; - - be = backtrace->start; - - for (i = 0; i < backtrace->items; i++) { - if (i != 0 && prev->name.start == be->name.start - && prev->line == be->line) - { - count++; - - } else { - - if (count != 0) { - len += nxt_length(" repeats times\n") - + NXT_INT_T_LEN; - count = 0; - } - - len += be->name.length + nxt_length(" at ()\n"); - - if (be->line != 0) { - len += be->file.length + NXT_INT_T_LEN + 1; - - } else { - len += nxt_length("native"); - } - } - - prev = be; - be++; - } - - p = nxt_mp_alloc(vm->mem_pool, len); - if (p == NULL) { - njs_memory_error(vm); - return NXT_ERROR; - } - - start = p; - end = start + len; - - p = nxt_cpymem(p, dst->start, dst->length); - *p++ = '\n'; - - count = 0; - prev = NULL; - - be = backtrace->start; - - for (i = 0; i < backtrace->items; i++) { - if (i != 0 && prev->name.start == be->name.start - && prev->line == be->line) - { - count++; - - } else { - if (count != 0) { - p = nxt_sprintf(p, end, " repeats %uz times\n", - count); - count = 0; - } - - p = nxt_sprintf(p, end, " at %V ", &be->name); - - if (be->line != 0) { - p = nxt_sprintf(p, end, "(%V:%uD)\n", &be->file, - be->line); - - } else { - p = nxt_sprintf(p, end, "(native)\n"); - } - } - - prev = be; - be++; - } - - dst->start = start; - dst->length = p - dst->start; - - return NXT_OK; -} - - -njs_ret_t -njs_vm_value_string(njs_vm_t *vm, nxt_str_t *dst, const njs_value_t *src) -{ - njs_ret_t ret; - nxt_uint_t exception; - - if (nxt_slow_path(src->type == NJS_NUMBER - && njs_number(src) == 0 - && signbit(njs_number(src)))) - { - njs_string_get(&njs_string_minus_zero, dst); - return NXT_OK; - } - - exception = 1; - -again: - - ret = njs_vm_value_to_string(vm, dst, src); - - if (nxt_fast_path(ret == NXT_OK)) { - - if (njs_vm_backtrace(vm) != NULL) { - ret = njs_vm_backtrace_dump(vm, dst, src); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } - } - - return NXT_OK; - } - - if (exception) { - exception = 0; - - /* value evaluation threw an exception. */ - - src = &vm->retval; - goto again; - } - - dst->length = 0; - dst->start = NULL; - - return NXT_ERROR; -} - - -njs_ret_t -njs_vm_retval_string(njs_vm_t *vm, nxt_str_t *dst) -{ - if (vm->top_frame == NULL) { - /* An exception was thrown during compilation. */ - - njs_vm_init(vm); - } - - return njs_vm_value_string(vm, dst, &vm->retval); -} - - -njs_ret_t -njs_vm_retval_dump(njs_vm_t *vm, nxt_str_t *dst, nxt_uint_t indent) -{ - if (vm->top_frame == NULL) { - /* An exception was thrown during compilation. */ - - njs_vm_init(vm); - } - - return njs_vm_value_dump(vm, dst, &vm->retval, 0, 1); -} - - -njs_ret_t -njs_vm_object_alloc(njs_vm_t *vm, njs_value_t *retval, ...) -{ - va_list args; - nxt_int_t ret; - njs_ret_t rc; - njs_value_t *name, *value; - njs_object_t *object; - njs_object_prop_t *prop; - nxt_lvlhsh_query_t lhq; - - object = njs_object_alloc(vm); - if (nxt_slow_path(object == NULL)) { - return NJS_ERROR; - } - - rc = NJS_ERROR; - - va_start(args, retval); - - for ( ;; ) { - name = va_arg(args, njs_value_t *); - if (name == NULL) { - break; - } - - value = va_arg(args, njs_value_t *); - if (value == NULL) { - njs_type_error(vm, "missed value for a key"); - goto done; - } - - if (nxt_slow_path(!njs_is_string(name))) { - njs_type_error(vm, "prop name is not a string"); - goto done; - } - - lhq.replace = 0; - lhq.pool = vm->mem_pool; - lhq.proto = &njs_object_hash_proto; - - njs_string_get(name, &lhq.key); - lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); - - prop = njs_object_prop_alloc(vm, name, value, 1); - if (nxt_slow_path(prop == NULL)) { - goto done; - } - - lhq.value = prop; - - ret = nxt_lvlhsh_insert(&object->hash, &lhq); - if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, NULL); - goto done; - } - } - - rc = NJS_OK; - - njs_set_object(retval, object); - -done: - - va_end(args); - - return rc; -} - - -njs_value_t * -njs_vm_object_prop(njs_vm_t *vm, const njs_value_t *value, const nxt_str_t *key) -{ - nxt_int_t ret; - njs_object_prop_t *prop; - nxt_lvlhsh_query_t lhq; - - if (nxt_slow_path(!njs_is_object(value))) { - return NULL; - } - - lhq.key = *key; - lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); - lhq.proto = &njs_object_hash_proto; - - ret = nxt_lvlhsh_find(njs_object_hash(value), &lhq); - if (nxt_slow_path(ret != NXT_OK)) { - return NULL; - } - - prop = lhq.value; - - return &prop->value; -} diff --git a/njs/njs_value.c b/njs/njs_value.c index ac82314e..0d2203a1 100644 --- a/njs/njs_value.c +++ b/njs/njs_value.c @@ -329,3 +329,126 @@ njs_arg_type_string(uint8_t arg) return "unknown"; } } + + +void +njs_value_undefined_set(njs_value_t *value) +{ + njs_set_undefined(value); +} + + +void +njs_value_boolean_set(njs_value_t *value, int yn) +{ + njs_set_boolean(value, yn); +} + + +void +njs_value_number_set(njs_value_t *value, double num) +{ + njs_set_number(value, num); +} + + +void +njs_value_data_set(njs_value_t *value, void *data) +{ + njs_set_data(value, data); +} + + +uint8_t +njs_value_bool(const njs_value_t *value) +{ + return njs_bool(value); +} + + +double +njs_value_number(const njs_value_t *value) +{ + return njs_number(value); +} + + +void * +njs_value_data(const njs_value_t *value) +{ + return njs_data(value); +} + + +njs_function_t * +njs_value_function(const njs_value_t *value) +{ + return njs_function(value); +} + + +nxt_int_t +njs_value_is_null(const njs_value_t *value) +{ + return njs_is_null(value); +} + + +nxt_int_t +njs_value_is_undefined(const njs_value_t *value) +{ + return njs_is_undefined(value); +} + + +nxt_int_t +njs_value_is_null_or_undefined(const njs_value_t *value) +{ + return njs_is_null_or_undefined(value); +} + + +nxt_int_t +njs_value_is_boolean(const njs_value_t *value) +{ + return njs_is_boolean(value); +} + + +nxt_int_t +njs_value_is_number(const njs_value_t *value) +{ + return njs_is_number(value); +} + + +nxt_int_t +njs_value_is_valid_number(const njs_value_t *value) +{ + return njs_is_number(value) + && !isnan(njs_number(value)) + && !isinf(njs_number(value)); +} + + +nxt_int_t +njs_value_is_string(const njs_value_t *value) +{ + return njs_is_string(value); +} + + +nxt_int_t +njs_value_is_object(const njs_value_t *value) +{ + return njs_is_object(value); +} + + +nxt_int_t +njs_value_is_function(const njs_value_t *value) +{ + return njs_is_function(value); +} + + diff --git a/njs/njs_vm.c b/njs/njs_vm.c index c94c8bef..90f6cfbd 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -9,6 +9,10 @@ #include +static nxt_int_t njs_vm_init(njs_vm_t *vm); +static nxt_int_t njs_vm_handle_events(njs_vm_t *vm); + + const nxt_str_t njs_entry_main = nxt_string("main"); const nxt_str_t njs_entry_module = nxt_string("module"); const nxt_str_t njs_entry_native = nxt_string("native"); @@ -16,6 +20,472 @@ const nxt_str_t njs_entry_unknown = nxt_string("unknown"); const nxt_str_t njs_entry_anonymous = nxt_string("anonymous"); +static void * +njs_alloc(void *mem, size_t size) +{ + return nxt_malloc(size); +} + + +static void * +njs_zalloc(void *mem, size_t size) +{ + void *p; + + p = nxt_malloc(size); + + if (p != NULL) { + nxt_memzero(p, size); + } + + return p; +} + + +static void * +njs_align(void *mem, size_t alignment, size_t size) +{ + return nxt_memalign(alignment, size); +} + + +static void +njs_free(void *mem, void *p) +{ + nxt_free(p); +} + + +const nxt_mem_proto_t njs_vm_mp_proto = { + njs_alloc, + njs_zalloc, + njs_align, + NULL, + njs_free, + NULL, + NULL, +}; + + +static void * +njs_array_mem_alloc(void *mem, size_t size) +{ + return nxt_mp_alloc(mem, size); +} + + +static void +njs_array_mem_free(void *mem, void *p) +{ + nxt_mp_free(mem, p); +} + + +const nxt_mem_proto_t njs_array_mem_proto = { + njs_array_mem_alloc, + NULL, + NULL, + NULL, + njs_array_mem_free, + NULL, + NULL, +}; + + +njs_vm_t * +njs_vm_create(njs_vm_opt_t *options) +{ + nxt_mp_t *mp; + njs_vm_t *vm; + nxt_int_t ret; + nxt_array_t *debug; + njs_regexp_pattern_t *pattern; + + mp = nxt_mp_create(&njs_vm_mp_proto, NULL, NULL, 2 * nxt_pagesize(), + 128, 512, 16); + if (nxt_slow_path(mp == NULL)) { + return NULL; + } + + vm = nxt_mp_zalign(mp, sizeof(njs_value_t), sizeof(njs_vm_t)); + + if (nxt_fast_path(vm != NULL)) { + vm->mem_pool = mp; + + ret = njs_regexp_init(vm); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + + vm->options = *options; + + if (options->shared != NULL) { + vm->shared = options->shared; + + } else { + vm->shared = nxt_mp_zalloc(mp, sizeof(njs_vm_shared_t)); + if (nxt_slow_path(vm->shared == NULL)) { + return NULL; + } + + options->shared = vm->shared; + + nxt_lvlhsh_init(&vm->shared->keywords_hash); + + ret = njs_lexer_keywords_init(mp, &vm->shared->keywords_hash); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + + nxt_lvlhsh_init(&vm->shared->values_hash); + + pattern = njs_regexp_pattern_create(vm, (u_char *) "(?:)", + nxt_length("(?:)"), 0); + if (nxt_slow_path(pattern == NULL)) { + return NULL; + } + + vm->shared->empty_regexp_pattern = pattern; + + nxt_lvlhsh_init(&vm->modules_hash); + + ret = njs_builtin_objects_create(vm); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + } + + nxt_lvlhsh_init(&vm->values_hash); + + vm->external = options->external; + + vm->external_objects = nxt_array_create(4, sizeof(void *), + &njs_array_mem_proto, + vm->mem_pool); + if (nxt_slow_path(vm->external_objects == NULL)) { + return NULL; + } + + nxt_lvlhsh_init(&vm->externals_hash); + nxt_lvlhsh_init(&vm->external_prototypes_hash); + + vm->trace.level = NXT_LEVEL_TRACE; + vm->trace.size = 2048; + vm->trace.handler = njs_parser_trace_handler; + vm->trace.data = vm; + + if (options->backtrace) { + debug = nxt_array_create(4, sizeof(njs_function_debug_t), + &njs_array_mem_proto, vm->mem_pool); + if (nxt_slow_path(debug == NULL)) { + return NULL; + } + + vm->debug = debug; + } + + if (options->accumulative) { + ret = njs_vm_init(vm); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + } + } + + return vm; +} + + +void +njs_vm_destroy(njs_vm_t *vm) +{ + njs_event_t *event; + nxt_lvlhsh_each_t lhe; + + if (njs_waiting_events(vm)) { + nxt_lvlhsh_each_init(&lhe, &njs_event_hash_proto); + + for ( ;; ) { + event = nxt_lvlhsh_each(&vm->events_hash, &lhe); + + if (event == NULL) { + break; + } + + njs_del_event(vm, event, NJS_EVENT_RELEASE); + } + } + + nxt_mp_destroy(vm->mem_pool); +} + + +nxt_int_t +njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end) +{ + nxt_int_t ret; + njs_lexer_t lexer; + njs_parser_t *parser, *prev; + njs_generator_t generator; + njs_parser_scope_t *scope; + + if (vm->parser != NULL && !vm->options.accumulative) { + return NJS_ERROR; + } + + if (vm->modules != NULL && vm->options.accumulative) { + njs_module_reset(vm); + } + + parser = nxt_mp_zalloc(vm->mem_pool, sizeof(njs_parser_t)); + if (nxt_slow_path(parser == NULL)) { + return NJS_ERROR; + } + + prev = vm->parser; + vm->parser = parser; + + ret = njs_lexer_init(vm, &lexer, &vm->options.file, *start, end); + if (nxt_slow_path(ret != NXT_OK)) { + return NJS_ERROR; + } + + parser->lexer = &lexer; + + if (vm->backtrace != NULL) { + nxt_array_reset(vm->backtrace); + } + + vm->retval = njs_value_undefined; + + ret = njs_parser(vm, parser, prev); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + + parser->lexer = NULL; + + scope = parser->scope; + + ret = njs_variables_scope_reference(vm, scope); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + + *start = lexer.start; + + /* + * Reset the code array to prevent it from being disassembled + * again in the next iteration of the accumulative mode. + */ + vm->code = NULL; + + nxt_memzero(&generator, sizeof(njs_generator_t)); + + ret = njs_generate_scope(vm, &generator, scope, &njs_entry_main); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + + vm->current = generator.code_start; + vm->global_scope = generator.local_scope; + vm->scope_size = generator.scope_size; + + vm->variables_hash = scope->variables; + + if (vm->options.init) { + ret = njs_vm_init(vm); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + } + + return NJS_OK; + +fail: + + vm->parser = prev; + + return NXT_ERROR; +} + + +njs_vm_t * +njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external) +{ + nxt_mp_t *nmp; + njs_vm_t *nvm; + uint32_t items; + nxt_int_t ret; + nxt_array_t *externals; + + nxt_thread_log_debug("CLONE:"); + + if (vm->options.accumulative) { + return NULL; + } + + nmp = nxt_mp_create(&njs_vm_mp_proto, NULL, NULL, 2 * nxt_pagesize(), + 128, 512, 16); + if (nxt_slow_path(nmp == NULL)) { + return NULL; + } + + nvm = nxt_mp_zalign(nmp, sizeof(njs_value_t), sizeof(njs_vm_t)); + + if (nxt_fast_path(nvm != NULL)) { + nvm->mem_pool = nmp; + + nvm->shared = vm->shared; + + nvm->trace = vm->trace; + nvm->trace.data = nvm; + + nvm->variables_hash = vm->variables_hash; + nvm->values_hash = vm->values_hash; + + nvm->modules = vm->modules; + nvm->modules_hash = vm->modules_hash; + + nvm->externals_hash = vm->externals_hash; + nvm->external_prototypes_hash = vm->external_prototypes_hash; + + items = vm->external_objects->items; + externals = nxt_array_create(items + 4, sizeof(void *), + &njs_array_mem_proto, nvm->mem_pool); + + if (nxt_slow_path(externals == NULL)) { + return NULL; + } + + if (items > 0) { + memcpy(externals->start, vm->external_objects->start, + items * sizeof(void *)); + externals->items = items; + } + + nvm->external_objects = externals; + + nvm->options = vm->options; + + nvm->current = vm->current; + + nvm->external = external; + + nvm->global_scope = vm->global_scope; + nvm->scope_size = vm->scope_size; + + nvm->debug = vm->debug; + + ret = njs_vm_init(nvm); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + + return nvm; + } + +fail: + + nxt_mp_destroy(nmp); + + return NULL; +} + + +static nxt_int_t +njs_vm_init(njs_vm_t *vm) +{ + size_t size, scope_size; + u_char *values; + nxt_int_t ret; + njs_frame_t *frame; + nxt_array_t *backtrace; + + scope_size = vm->scope_size + NJS_INDEX_GLOBAL_OFFSET; + + size = NJS_GLOBAL_FRAME_SIZE + scope_size + NJS_FRAME_SPARE_SIZE; + size = nxt_align_size(size, NJS_FRAME_SPARE_SIZE); + + frame = nxt_mp_align(vm->mem_pool, sizeof(njs_value_t), size); + if (nxt_slow_path(frame == NULL)) { + return NXT_ERROR; + } + + nxt_memzero(frame, NJS_GLOBAL_FRAME_SIZE); + + vm->top_frame = &frame->native; + vm->active_frame = frame; + + frame->native.size = size; + frame->native.free_size = size - (NJS_GLOBAL_FRAME_SIZE + scope_size); + + values = (u_char *) frame + NJS_GLOBAL_FRAME_SIZE; + + frame->native.free = values + scope_size; + + vm->scopes[NJS_SCOPE_GLOBAL] = (njs_value_t *) values; + memcpy(values + NJS_INDEX_GLOBAL_OFFSET, vm->global_scope, + vm->scope_size); + + ret = njs_regexp_init(vm); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + ret = njs_builtin_objects_clone(vm); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + nxt_lvlhsh_init(&vm->events_hash); + nxt_queue_init(&vm->posted_events); + + if (vm->debug != NULL) { + backtrace = nxt_array_create(4, sizeof(njs_backtrace_entry_t), + &njs_array_mem_proto, vm->mem_pool); + if (nxt_slow_path(backtrace == NULL)) { + return NXT_ERROR; + } + + vm->backtrace = backtrace; + } + + if (njs_is_null(&vm->retval)) { + vm->retval = njs_value_undefined; + } + + return NXT_OK; +} + + +nxt_int_t +njs_vm_call(njs_vm_t *vm, njs_function_t *function, const njs_value_t *args, + nxt_uint_t nargs) +{ + return njs_vm_invoke(vm, function, args, nargs, (njs_index_t) &vm->retval); +} + + +nxt_int_t +njs_vm_invoke(njs_vm_t *vm, njs_function_t *function, const njs_value_t *args, + nxt_uint_t nargs, njs_index_t retval) +{ + njs_ret_t ret; + njs_value_t *this; + + this = (njs_value_t *) &njs_value_undefined; + + ret = njs_function_frame(vm, function, this, (njs_value_t *) args, nargs, + 0); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + return njs_function_frame_invoke(vm, retval); +} + + void njs_vm_scopes_restore(njs_vm_t *vm, njs_frame_t *frame, njs_native_frame_t *previous) @@ -68,6 +538,511 @@ njs_vm_scopes_restore(njs_vm_t *vm, njs_frame_t *frame, } +njs_vm_event_t +njs_vm_add_event(njs_vm_t *vm, njs_function_t *function, nxt_uint_t once, + njs_host_event_t host_ev, njs_event_destructor_t destructor) +{ + njs_event_t *event; + + event = nxt_mp_alloc(vm->mem_pool, sizeof(njs_event_t)); + if (nxt_slow_path(event == NULL)) { + return NULL; + } + + event->host_event = host_ev; + event->destructor = destructor; + event->function = function; + event->once = once; + event->posted = 0; + event->nargs = 0; + event->args = NULL; + + if (njs_add_event(vm, event) != NJS_OK) { + return NULL; + } + + return event; +} + + +void +njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event) +{ + njs_event_t *event; + + event = (njs_event_t *) vm_event; + + njs_del_event(vm, event, NJS_EVENT_RELEASE | NJS_EVENT_DELETE); +} + + +nxt_int_t +njs_vm_waiting(njs_vm_t *vm) +{ + return njs_waiting_events(vm); +} + + +nxt_int_t +njs_vm_posted(njs_vm_t *vm) +{ + return njs_posted_events(vm); +} + + +nxt_int_t +njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, + const njs_value_t *args, nxt_uint_t nargs) +{ + njs_event_t *event; + + event = (njs_event_t *) vm_event; + + if (nargs != 0 && !event->posted) { + event->nargs = nargs; + event->args = nxt_mp_alloc(vm->mem_pool, sizeof(njs_value_t) * nargs); + if (nxt_slow_path(event->args == NULL)) { + return NJS_ERROR; + } + + memcpy(event->args, args, sizeof(njs_value_t) * nargs); + } + + if (!event->posted) { + event->posted = 1; + nxt_queue_insert_tail(&vm->posted_events, &event->link); + } + + return NJS_OK; +} + + +nxt_int_t +njs_vm_run(njs_vm_t *vm) +{ + if (nxt_slow_path(vm->backtrace != NULL)) { + nxt_array_reset(vm->backtrace); + } + + return njs_vm_handle_events(vm); +} + + +nxt_int_t +njs_vm_start(njs_vm_t *vm) +{ + njs_ret_t ret; + + ret = njs_module_load(vm); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + ret = njs_vmcode_interpreter(vm); + + if (ret == NJS_STOP) { + ret = NJS_OK; + } + + return ret; +} + + +static nxt_int_t +njs_vm_handle_events(njs_vm_t *vm) +{ + nxt_int_t ret; + njs_event_t *ev; + nxt_queue_t *events; + nxt_queue_link_t *link; + + events = &vm->posted_events; + + for ( ;; ) { + link = nxt_queue_first(events); + + if (link == nxt_queue_tail(events)) { + break; + } + + ev = nxt_queue_link_data(link, njs_event_t, link); + + if (ev->once) { + njs_del_event(vm, ev, NJS_EVENT_RELEASE | NJS_EVENT_DELETE); + + } else { + ev->posted = 0; + nxt_queue_remove(&ev->link); + } + + ret = njs_vm_call(vm, ev->function, ev->args, ev->nargs); + + if (ret == NJS_ERROR) { + return ret; + } + } + + return njs_posted_events(vm) ? NJS_AGAIN : NJS_OK; +} + + +nxt_int_t +njs_vm_add_path(njs_vm_t *vm, const nxt_str_t *path) +{ + nxt_str_t *item; + + if (vm->paths == NULL) { + vm->paths = nxt_array_create(4, sizeof(nxt_str_t), + &njs_array_mem_proto, vm->mem_pool); + if (nxt_slow_path(vm->paths == NULL)) { + return NXT_ERROR; + } + } + + item = nxt_array_add(vm->paths, &njs_array_mem_proto, vm->mem_pool); + if (nxt_slow_path(item == NULL)) { + return NXT_ERROR; + } + + *item = *path; + + return NXT_OK; +} + + +njs_value_t * +njs_vm_retval(njs_vm_t *vm) +{ + return &vm->retval; +} + + +void +njs_vm_retval_set(njs_vm_t *vm, const njs_value_t *value) +{ + vm->retval = *value; +} + + +njs_ret_t +njs_vm_value_string_set(njs_vm_t *vm, njs_value_t *value, const u_char *start, + uint32_t size) +{ + return njs_string_set(vm, value, start, size); +} + + +u_char * +njs_vm_value_string_alloc(njs_vm_t *vm, njs_value_t *value, uint32_t size) +{ + return njs_string_alloc(vm, value, size, 0); +} + + +nxt_noinline void +njs_vm_value_error_set(njs_vm_t *vm, njs_value_t *value, const char *fmt, ...) +{ + va_list args; + u_char buf[NXT_MAX_ERROR_STR], *p; + + p = buf; + + if (fmt != NULL) { + va_start(args, fmt); + p = nxt_vsprintf(buf, buf + sizeof(buf), fmt, args); + va_end(args); + } + + njs_error_new(vm, value, NJS_OBJECT_ERROR, buf, p - buf); +} + + +nxt_noinline void +njs_vm_memory_error(njs_vm_t *vm) +{ + njs_memory_error_set(vm, &vm->retval); +} + + +nxt_array_t * +njs_vm_backtrace(njs_vm_t *vm) +{ + if (vm->backtrace != NULL && !nxt_array_is_empty(vm->backtrace)) { + return vm->backtrace; + } + + return NULL; +} + + +static njs_ret_t +njs_vm_backtrace_dump(njs_vm_t *vm, nxt_str_t *dst, const njs_value_t *src) +{ + u_char *p, *start, *end; + size_t len, count; + nxt_uint_t i; + nxt_array_t *backtrace; + njs_backtrace_entry_t *be, *prev; + + backtrace = njs_vm_backtrace(vm); + + len = dst->length + 1; + + count = 0; + prev = NULL; + + be = backtrace->start; + + for (i = 0; i < backtrace->items; i++) { + if (i != 0 && prev->name.start == be->name.start + && prev->line == be->line) + { + count++; + + } else { + + if (count != 0) { + len += nxt_length(" repeats times\n") + + NXT_INT_T_LEN; + count = 0; + } + + len += be->name.length + nxt_length(" at ()\n"); + + if (be->line != 0) { + len += be->file.length + NXT_INT_T_LEN + 1; + + } else { + len += nxt_length("native"); + } + } + + prev = be; + be++; + } + + p = nxt_mp_alloc(vm->mem_pool, len); + if (p == NULL) { + njs_memory_error(vm); + return NXT_ERROR; + } + + start = p; + end = start + len; + + p = nxt_cpymem(p, dst->start, dst->length); + *p++ = '\n'; + + count = 0; + prev = NULL; + + be = backtrace->start; + + for (i = 0; i < backtrace->items; i++) { + if (i != 0 && prev->name.start == be->name.start + && prev->line == be->line) + { + count++; + + } else { + if (count != 0) { + p = nxt_sprintf(p, end, " repeats %uz times\n", + count); + count = 0; + } + + p = nxt_sprintf(p, end, " at %V ", &be->name); + + if (be->line != 0) { + p = nxt_sprintf(p, end, "(%V:%uD)\n", &be->file, + be->line); + + } else { + p = nxt_sprintf(p, end, "(native)\n"); + } + } + + prev = be; + be++; + } + + dst->start = start; + dst->length = p - dst->start; + + return NXT_OK; +} + + +njs_ret_t +njs_vm_value_string(njs_vm_t *vm, nxt_str_t *dst, const njs_value_t *src) +{ + njs_ret_t ret; + nxt_uint_t exception; + + if (nxt_slow_path(src->type == NJS_NUMBER + && njs_number(src) == 0 + && signbit(njs_number(src)))) + { + njs_string_get(&njs_string_minus_zero, dst); + return NXT_OK; + } + + exception = 1; + +again: + + ret = njs_vm_value_to_string(vm, dst, src); + + if (nxt_fast_path(ret == NXT_OK)) { + + if (njs_vm_backtrace(vm) != NULL) { + ret = njs_vm_backtrace_dump(vm, dst, src); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + } + + return NXT_OK; + } + + if (exception) { + exception = 0; + + /* value evaluation threw an exception. */ + + src = &vm->retval; + goto again; + } + + dst->length = 0; + dst->start = NULL; + + return NXT_ERROR; +} + + +njs_ret_t +njs_vm_retval_string(njs_vm_t *vm, nxt_str_t *dst) +{ + if (vm->top_frame == NULL) { + /* An exception was thrown during compilation. */ + + njs_vm_init(vm); + } + + return njs_vm_value_string(vm, dst, &vm->retval); +} + + +njs_ret_t +njs_vm_retval_dump(njs_vm_t *vm, nxt_str_t *dst, nxt_uint_t indent) +{ + if (vm->top_frame == NULL) { + /* An exception was thrown during compilation. */ + + njs_vm_init(vm); + } + + return njs_vm_value_dump(vm, dst, &vm->retval, 0, 1); +} + + +njs_ret_t +njs_vm_object_alloc(njs_vm_t *vm, njs_value_t *retval, ...) +{ + va_list args; + nxt_int_t ret; + njs_ret_t rc; + njs_value_t *name, *value; + njs_object_t *object; + njs_object_prop_t *prop; + nxt_lvlhsh_query_t lhq; + + object = njs_object_alloc(vm); + if (nxt_slow_path(object == NULL)) { + return NJS_ERROR; + } + + rc = NJS_ERROR; + + va_start(args, retval); + + for ( ;; ) { + name = va_arg(args, njs_value_t *); + if (name == NULL) { + break; + } + + value = va_arg(args, njs_value_t *); + if (value == NULL) { + njs_type_error(vm, "missed value for a key"); + goto done; + } + + if (nxt_slow_path(!njs_is_string(name))) { + njs_type_error(vm, "prop name is not a string"); + goto done; + } + + lhq.replace = 0; + lhq.pool = vm->mem_pool; + lhq.proto = &njs_object_hash_proto; + + njs_string_get(name, &lhq.key); + lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); + + prop = njs_object_prop_alloc(vm, name, value, 1); + if (nxt_slow_path(prop == NULL)) { + goto done; + } + + lhq.value = prop; + + ret = nxt_lvlhsh_insert(&object->hash, &lhq); + if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, NULL); + goto done; + } + } + + rc = NJS_OK; + + njs_set_object(retval, object); + +done: + + va_end(args); + + return rc; +} + + +njs_value_t * +njs_vm_object_prop(njs_vm_t *vm, const njs_value_t *value, const nxt_str_t *key) +{ + nxt_int_t ret; + njs_object_prop_t *prop; + nxt_lvlhsh_query_t lhq; + + if (nxt_slow_path(!njs_is_object(value))) { + return NULL; + } + + lhq.key = *key; + lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); + lhq.proto = &njs_object_hash_proto; + + ret = nxt_lvlhsh_find(njs_object_hash(value), &lhq); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + + prop = lhq.value; + + return &prop->value; +} + + njs_ret_t njs_vm_value_to_string(njs_vm_t *vm, nxt_str_t *dst, const njs_value_t *src) { -- 2.47.3