From 9a9e1c0d4cd15d0b9a5fa33a51ae6e8bf4609bee Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Tue, 26 Nov 2019 15:09:45 +0300 Subject: [PATCH] Introduced njs_vm_bind(). This is a generic replacement for njs_vm_external_bind(). --- src/njs.h | 5 ++- src/njs_builtin.c | 84 ++++++--------------------------------- src/njs_extern.c | 83 -------------------------------------- src/njs_extern.h | 2 - src/njs_parser_terminal.c | 10 ----- src/njs_shell.c | 12 +++--- src/njs_variable.c | 6 --- src/njs_vm.c | 41 ++++++++++++++++++- src/njs_vm.h | 1 - src/test/njs_unit_test.c | 77 +++++++++++++++++++++++++++-------- test/njs_expect_test.exp | 11 +++-- 11 files changed, 129 insertions(+), 203 deletions(-) diff --git a/src/njs.h b/src/njs.h index 27573758..52f359c0 100644 --- a/src/njs.h +++ b/src/njs.h @@ -235,16 +235,17 @@ NJS_EXPORT const njs_extern_t *njs_vm_external_prototype(njs_vm_t *vm, njs_external_t *external); NJS_EXPORT njs_int_t njs_vm_external_create(njs_vm_t *vm, njs_value_t *value, const njs_extern_t *proto, njs_external_ptr_t object); -NJS_EXPORT njs_int_t njs_vm_external_bind(njs_vm_t *vm, - const njs_str_t *var_name, const njs_value_t *value); NJS_EXPORT njs_external_ptr_t njs_vm_external(njs_vm_t *vm, const njs_value_t *value); NJS_EXPORT void njs_disassembler(njs_vm_t *vm); NJS_EXPORT void njs_disassemble(u_char *start, u_char *end); +NJS_EXPORT njs_int_t njs_vm_bind(njs_vm_t *vm, const njs_str_t *var_name, + const njs_value_t *value, njs_bool_t shared); NJS_EXPORT const njs_value_t *njs_vm_value(njs_vm_t *vm, const njs_str_t *name); NJS_EXPORT njs_function_t *njs_vm_function(njs_vm_t *vm, const njs_str_t *name); + NJS_EXPORT njs_value_t *njs_vm_retval(njs_vm_t *vm); NJS_EXPORT void njs_vm_retval_set(njs_vm_t *vm, const njs_value_t *value); diff --git a/src/njs_builtin.c b/src/njs_builtin.c index d8aa8d32..34bf1ed8 100644 --- a/src/njs_builtin.c +++ b/src/njs_builtin.c @@ -176,6 +176,7 @@ njs_builtin_objects_create(njs_vm_t *vm) return NJS_ERROR; } + object->type = NJS_OBJECT; object->shared = 1; object->extensible = 1; @@ -260,13 +261,6 @@ njs_builtin_objects_create(njs_vm_t *vm) shared->prototypes[NJS_OBJ_TYPE_REGEXP].regexp.pattern = shared->empty_regexp_pattern; - string_object = &shared->string_object; - njs_lvlhsh_init(&string_object->hash); - string_object->shared_hash = shared->string_instance_hash; - string_object->type = NJS_OBJECT_STRING; - string_object->shared = 1; - string_object->extensible = 0; - constructor = shared->constructors; for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_MAX; i++) { @@ -286,6 +280,16 @@ njs_builtin_objects_create(njs_vm_t *vm) } } + vm->global_object = shared->objects[0]; + vm->global_object.shared = 0; + + string_object = &shared->string_object; + njs_lvlhsh_init(&string_object->hash); + string_object->shared_hash = shared->string_instance_hash; + string_object->type = NJS_OBJECT_STRING; + string_object->shared = 1; + string_object->extensible = 0; + vm->shared = shared; return NJS_OK; @@ -333,10 +337,7 @@ njs_builtin_objects_clone(njs_vm_t *vm, njs_value_t *global) vm->constructors[i].object.__proto__ = error_constructor; } - vm->global_object = vm->shared->objects[0]; vm->global_object.__proto__ = object_prototype; - vm->global_object.shared = 0; - njs_set_object(global, &vm->global_object); vm->string_object = vm->shared->string_object; @@ -452,15 +453,11 @@ njs_builtin_traverse(njs_vm_t *vm, njs_traverse_t *traverse, void *data) static njs_arr_t * njs_builtin_completions(njs_vm_t *vm) { - u_char *compl; - size_t len; njs_arr_t *array; njs_str_t *completion; njs_int_t ret; njs_keyword_t *keyword; - njs_lvlhsh_each_t lhe, lhe_prop; - njs_extern_value_t *ev; - const njs_extern_t *ext_proto, *ext_prop; + njs_lvlhsh_each_t lhe; njs_builtin_traverse_t ctx; const njs_object_prop_t *prop; @@ -516,63 +513,6 @@ njs_builtin_completions(njs_vm_t *vm) njs_string_get(&prop->name, completion); } - /* Externals completions. */ - - njs_lvlhsh_each_init(&lhe, &njs_extern_value_hash_proto); - - for ( ;; ) { - ev = njs_lvlhsh_each(&vm->externals_hash, &lhe); - - if (ev == NULL) { - break; - } - - ext_proto = ev->value.external.proto; - - njs_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto); - - len = ev->name.length + 1; - compl = njs_mp_zalloc(vm->mem_pool, len); - if (compl == NULL) { - return NULL; - } - - njs_sprintf(compl, compl + len, "%V%Z", &ev->name); - - completion = njs_arr_add(array); - if (njs_slow_path(completion == NULL)) { - return NULL; - } - - completion->length = len; - completion->start = (u_char *) compl; - - for ( ;; ) { - ext_prop = njs_lvlhsh_each(&ext_proto->hash, &lhe_prop); - - if (ext_prop == NULL) { - break; - } - - len = ev->name.length + ev->name.length + 2; - compl = njs_mp_zalloc(vm->mem_pool, len); - if (compl == NULL) { - return NULL; - } - - njs_sprintf(compl, compl + len, "%V.%V%Z", &ev->name, - &ext_prop->name); - - completion = njs_arr_add(array); - if (njs_slow_path(completion == NULL)) { - return NULL; - } - - completion->length = len; - completion->start = (u_char *) compl; - } - } - return array; } diff --git a/src/njs_extern.c b/src/njs_extern.c index 83dc3c53..793541b8 100644 --- a/src/njs_extern.c +++ b/src/njs_extern.c @@ -31,21 +31,6 @@ njs_extern_hash_test(njs_lvlhsh_query_t *lhq, void *data) } -static njs_int_t -njs_extern_value_hash_test(njs_lvlhsh_query_t *lhq, void *data) -{ - njs_extern_value_t *ev; - - ev = (njs_extern_value_t *) data; - - if (njs_strstr_eq(&lhq->key, &ev->name)) { - return NJS_OK; - } - - return NJS_DECLINED; -} - - const njs_lvlhsh_proto_t njs_extern_hash_proto njs_aligned(64) = { @@ -56,16 +41,6 @@ const njs_lvlhsh_proto_t njs_extern_hash_proto }; -const njs_lvlhsh_proto_t njs_extern_value_hash_proto - njs_aligned(64) = -{ - NJS_LVLHSH_DEFAULT, - njs_extern_value_hash_test, - njs_lvlhsh_alloc, - njs_lvlhsh_free, -}; - - static njs_extern_t * njs_vm_external_add(njs_vm_t *vm, njs_lvlhsh_t *hash, njs_external_t *external, njs_uint_t n) @@ -215,45 +190,6 @@ njs_vm_external_create(njs_vm_t *vm, njs_value_t *ext_val, } -njs_int_t -njs_vm_external_bind(njs_vm_t *vm, const njs_str_t *var_name, - const njs_value_t *value) -{ - njs_int_t ret; - njs_extern_value_t *ev; - njs_lvlhsh_query_t lhq; - - if (njs_slow_path(!njs_is_external(value))) { - return NJS_ERROR; - } - - ev = njs_mp_align(vm->mem_pool, sizeof(njs_value_t), - sizeof(njs_extern_value_t)); - if (njs_slow_path(ev == NULL)) { - njs_memory_error(vm); - return NJS_ERROR; - } - - ev->value = *value; - ev->name = *var_name; - - lhq.key = *var_name; - lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); - lhq.proto = &njs_extern_value_hash_proto; - lhq.value = ev; - lhq.replace = 0; - lhq.pool = vm->mem_pool; - - ret = njs_lvlhsh_insert(&vm->externals_hash, &lhq); - if (njs_slow_path(ret != NJS_OK)) { - njs_internal_error(vm, "lvlhsh insert failed"); - return ret; - } - - return NJS_OK; -} - - njs_external_ptr_t njs_vm_external(njs_vm_t *vm, const njs_value_t *value) { @@ -321,25 +257,6 @@ njs_extern_keys_array(njs_vm_t *vm, const njs_extern_t *external) } -njs_value_t * -njs_external_lookup(njs_vm_t *vm, njs_str_t *name, uint32_t hash) -{ - njs_lvlhsh_query_t lhq; - njs_extern_value_t *ev; - - lhq.key_hash = hash; - lhq.key = *name; - lhq.proto = &njs_extern_value_hash_proto; - - if (njs_lvlhsh_find(&vm->externals_hash, &lhq) == NJS_OK) { - ev = (njs_extern_value_t *) lhq.value; - return &ev->value; - } - - return NULL; -} - - static njs_int_t njs_external_match(njs_vm_t *vm, njs_function_native_t func, njs_extern_t *ext, njs_str_t *name, njs_extern_part_t *head, njs_extern_part_t *ppart) diff --git a/src/njs_extern.h b/src/njs_extern.h index 6a3d9ab5..4afc8df1 100644 --- a/src/njs_extern.h +++ b/src/njs_extern.h @@ -41,13 +41,11 @@ typedef struct { njs_array_t *njs_extern_keys_array(njs_vm_t *vm, const njs_extern_t *external); -njs_value_t *njs_external_lookup(njs_vm_t *vm, njs_str_t *name, uint32_t hash); njs_int_t njs_external_match_native_function(njs_vm_t *vm, njs_function_native_t func, njs_str_t *name); extern const njs_lvlhsh_proto_t njs_extern_hash_proto; -extern const njs_lvlhsh_proto_t njs_extern_value_hash_proto; #endif /* _NJS_EXTERN_H_INCLUDED_ */ diff --git a/src/njs_parser_terminal.c b/src/njs_parser_terminal.c index c8f43f4c..a8ca3f30 100644 --- a/src/njs_parser_terminal.c +++ b/src/njs_parser_terminal.c @@ -203,7 +203,6 @@ njs_parser_reference(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token, njs_str_t *name, uint32_t hash, uint32_t token_line) { njs_int_t ret; - njs_value_t *ext; njs_variable_t *var; njs_parser_node_t *node; njs_parser_scope_t *scope; @@ -291,15 +290,6 @@ njs_parser_reference(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token, node->token_line = token_line; - ext = njs_external_lookup(vm, name, hash); - - if (ext != NULL) { - node->token = NJS_TOKEN_EXTERNAL; - node->u.value = *ext; - node->index = (njs_index_t) ext; - break; - } - ret = njs_variable_reference(vm, parser->scope, node, name, hash, NJS_REFERENCE); if (njs_slow_path(ret != NJS_OK)) { diff --git a/src/njs_shell.c b/src/njs_shell.c index 899bfe00..da1f3c16 100644 --- a/src/njs_shell.c +++ b/src/njs_shell.c @@ -613,28 +613,28 @@ njs_externals_init(njs_vm_t *vm, njs_console_t *console) static const njs_str_t name = njs_str("console"); proto = njs_vm_external_prototype(vm, &njs_externals[0]); - if (proto == NULL) { + if (njs_slow_path(proto == NULL)) { njs_stderror("failed to add console proto\n"); return NJS_ERROR; } value = njs_mp_zalloc(vm->mem_pool, sizeof(njs_opaque_value_t)); - if (value == NULL) { + if (njs_slow_path(value == NULL)) { return NJS_ERROR; } ret = njs_vm_external_create(vm, value, proto, console); - if (ret != NJS_OK) { + if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } - ret = njs_vm_external_bind(vm, &name, value); - if (ret != NJS_OK) { + ret = njs_vm_bind(vm, &name, value, 1); + if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } ret = njs_console_init(vm, console); - if (ret != NJS_OK) { + if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } diff --git a/src/njs_variable.c b/src/njs_variable.c index d89f3e79..63f9e471 100644 --- a/src/njs_variable.c +++ b/src/njs_variable.c @@ -683,12 +683,6 @@ njs_vm_value(njs_vm_t *vm, const njs_str_t *name) return njs_vmcode_operand(vm, ((njs_variable_t *) lhq.value)->index); } - lhq.proto = &njs_extern_value_hash_proto; - - if (njs_lvlhsh_find(&vm->externals_hash, &lhq) == NJS_OK) { - return &((njs_extern_value_t *) lhq.value)->value; - } - return &njs_value_undefined; } diff --git a/src/njs_vm.c b/src/njs_vm.c index 19ec0e97..56661d0a 100644 --- a/src/njs_vm.c +++ b/src/njs_vm.c @@ -65,7 +65,6 @@ njs_vm_create(njs_vm_opt_t *options) return NULL; } - njs_lvlhsh_init(&vm->externals_hash); njs_lvlhsh_init(&vm->external_prototypes_hash); vm->trace.level = NJS_LEVEL_TRACE; @@ -569,6 +568,46 @@ njs_vm_retval_set(njs_vm_t *vm, const njs_value_t *value) } +njs_int_t +njs_vm_bind(njs_vm_t *vm, const njs_str_t *var_name, const njs_value_t *value, + njs_bool_t shared) +{ + njs_int_t ret; + njs_object_t *global; + njs_lvlhsh_t *hash; + njs_object_prop_t *prop; + njs_lvlhsh_query_t lhq; + + prop = njs_object_prop_alloc(vm, &njs_value_undefined, value, 1); + if (njs_slow_path(prop == NULL)) { + return NJS_ERROR; + } + + ret = njs_string_new(vm, &prop->name, var_name->start, var_name->length, 0); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + lhq.value = prop; + lhq.key = *var_name; + lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); + lhq.replace = 1; + lhq.pool = vm->mem_pool; + lhq.proto = &njs_object_hash_proto; + + global = &vm->global_object; + hash = shared ? &global->shared_hash : &global->hash; + + ret = njs_lvlhsh_insert(hash, &lhq); + if (njs_slow_path(ret != NJS_OK)) { + njs_internal_error(vm, "lvlhsh insert failed"); + return ret; + } + + return NJS_OK; +} + + njs_int_t njs_vm_value_string_set(njs_vm_t *vm, njs_value_t *value, const u_char *start, uint32_t size) diff --git a/src/njs_vm.h b/src/njs_vm.h index 748f678e..3cb98b11 100644 --- a/src/njs_vm.h +++ b/src/njs_vm.h @@ -175,7 +175,6 @@ struct njs_vm_s { njs_arr_t *external_objects; /* of njs_external_ptr_t */ - njs_lvlhsh_t externals_hash; njs_lvlhsh_t external_prototypes_hash; njs_lvlhsh_t variables_hash; diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 73fba4c4..bceb715c 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -9352,8 +9352,17 @@ static njs_unit_test_t njs_test[] = { njs_str("Object.getOwnPropertyNames(this).includes('NaN')"), njs_str("true") }, - { njs_str("Object.keys(this)"), - njs_str("njs,process") }, + { njs_str("Object.keys(this).sort()"), + njs_str("$r,$r2,$r3,njs,process") }, + + { njs_str("var r = njs.dump(this); " + "['$r', 'global', njs.version].every(v=>r.includes(v))"), + njs_str("true") }, + + { njs_str("var r = JSON.stringify(this); " + "['$r', njs.version].every(v=>r.includes(v))"), + njs_str("true") }, + { njs_str("this.a = 1; this.a"), njs_str("1") }, @@ -13842,9 +13851,6 @@ static njs_unit_test_t njs_test[] = { njs_str("this.njs = 1; njs"), njs_str("1") }, - { njs_str("njs.dump(this) === `global {njs:njs {version:'${njs.version}'},process:process {}}`"), - njs_str("true") }, - { njs_str("process === process"), njs_str("true") }, @@ -15233,6 +15239,15 @@ static njs_unit_test_t njs_shared_test[] = { njs_str("var r; for (var i = 0; i < 2**10; i++) {r = $r.create('XXX').uri;}"), njs_str("undefined") }, + + { njs_str("delete $r3.vars.p; $r3.vars.p"), + njs_str("undefined") }, + + { njs_str("var sr = $r.create('XXX'); sr.vars.p = 'a'; sr.vars.p"), + njs_str("a") }, + + { njs_str("$r.bind('XXX', 37); XXX"), + njs_str("37") }, }; @@ -15793,6 +15808,26 @@ memory_error: } +static njs_int_t +njs_unit_test_bind_external(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t unused) +{ + njs_str_t name; + njs_unit_test_req_t *r; + + r = njs_vm_external(vm, njs_arg(args, nargs, 0)); + if (njs_slow_path(r == NULL)) { + return NJS_ERROR; + } + + if (njs_vm_value_to_string(vm, &name, njs_arg(args, nargs, 1)) != NJS_OK) { + return NJS_ERROR; + } + + return njs_vm_bind(vm, &name, njs_arg(args, nargs, 2), 0); +} + + static njs_external_t njs_unit_test_r_props[] = { { njs_str("a"), @@ -15909,6 +15944,17 @@ static njs_external_t njs_unit_test_r_external[] = { njs_unit_test_create_external, 0 }, + { njs_str("bind"), + NJS_EXTERN_METHOD, + NULL, + 0, + NULL, + NULL, + NULL, + NULL, + njs_unit_test_bind_external, + 0 }, + }; @@ -15982,15 +16028,14 @@ njs_externals_init(njs_vm_t *vm) njs_unit_test_prop_t *prop; proto = njs_vm_external_prototype(vm, &njs_test_external[0]); - if (proto == NULL) { + if (njs_slow_path(proto == NULL)) { njs_printf("njs_vm_external_prototype() failed\n"); return NJS_ERROR; } - requests = njs_mp_zalloc(vm->mem_pool, - njs_nitems(njs_test_requests) + requests = njs_mp_zalloc(vm->mem_pool, njs_nitems(njs_test_requests) * sizeof(njs_unit_test_req_t)); - if (requests == NULL) { + if (njs_slow_path(requests == NULL)) { return NJS_ERROR; } @@ -16002,15 +16047,15 @@ njs_externals_init(njs_vm_t *vm) ret = njs_vm_external_create(vm, njs_value_arg(&requests[i].value), proto, &requests[i]); - if (ret != NJS_OK) { + if (njs_slow_path(ret != NJS_OK)) { njs_printf("njs_vm_external_create() failed\n"); return NJS_ERROR; } - ret = njs_vm_external_bind(vm, &njs_test_requests[i].name, - njs_value_arg(&requests[i].value)); - if (ret != NJS_OK) { - njs_printf("njs_vm_external_bind() failed\n"); + ret = njs_vm_bind(vm, &njs_test_requests[i].name, + njs_value_arg(&requests[i].value), 1); + if (njs_slow_path(ret != NJS_OK)) { + njs_printf("njs_vm_bind() failed\n"); return NJS_ERROR; } @@ -16019,13 +16064,13 @@ njs_externals_init(njs_vm_t *vm) &njs_test_requests[i].props[j].name, &njs_test_requests[i].props[j].value); - if (prop == NULL) { + if (njs_slow_path(prop == NULL)) { njs_printf("lvlhsh_unit_test_alloc() failed\n"); return NJS_ERROR; } ret = lvlhsh_unit_test_add(&requests[i], prop); - if (ret != NJS_OK) { + if (njs_slow_path(ret != NJS_OK)) { njs_printf("lvlhsh_unit_test_add() failed\n"); return NJS_ERROR; } diff --git a/test/njs_expect_test.exp b/test/njs_expect_test.exp index baeea69e..fa365a4c 100644 --- a/test/njs_expect_test.exp +++ b/test/njs_expect_test.exp @@ -87,10 +87,13 @@ njs_test { "Ma\a*th"} } -njs_test { - {"conso\t" - "conso\a*le"} -} +# FIXME: completions for external objects +# are not supported + +# njs_test { +# {"conso\t" +# "conso\a*le"} +# } # Global completions, multiple partial match njs_test { -- 2.47.3