details: http://hg.nginx.org/njs/rev/2711e84ede6a branches: changeset: 654:2711e84ede6a user: Dmitry Volyntsev <xei...@nginx.com> date: Wed Apr 04 17:38:10 2018 +0300 description: Improved handling of builtin objects.
The handling of njs_object_init_t arrays is unified across njs_builtin.c functions. diffstat: njs/njs_builtin.c | 939 +++++++++++++++++++-------------------- njs/njs_crypto.c | 12 + njs/njs_fs.c | 6 + njs/njs_module.c | 16 - njs/njs_module.h | 1 - njs/njs_shell.c | 19 +- njs/njs_vm.h | 7 - njs/test/njs_expect_test.exp | 5 + njs/test/njs_interactive_test.c | 5 + 9 files changed, 499 insertions(+), 511 deletions(-) diffs (truncated from 1323 to 1000 lines): diff -r 46632012ac03 -r 2711e84ede6a njs/njs_builtin.c --- a/njs/njs_builtin.c Wed Nov 14 18:14:49 2018 +0300 +++ b/njs/njs_builtin.c Wed Apr 04 17:38:10 2018 +0300 @@ -1,6 +1,7 @@ /* * Copyright (C) Igor Sysoev + * Copyright (C) Dmitry Volyntsev * Copyright (C) NGINX, Inc. */ @@ -23,25 +24,30 @@ typedef struct { } njs_function_init_t; -static nxt_int_t njs_builtin_completions(njs_vm_t *vm, size_t *size, - nxt_str_t *completions); +static njs_ret_t njs_prototype_function(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); static nxt_array_t *njs_vm_expression_completions(njs_vm_t *vm, nxt_str_t *expression); static nxt_array_t *njs_object_completions(njs_vm_t *vm, njs_object_t *object); + const njs_object_init_t njs_njs_object_init; +const njs_object_init_t njs_global_this_init; + const njs_object_init_t *njs_object_init[] = { - NULL, /* global this */ + &njs_global_this_init, /* global this */ &njs_njs_object_init, /* global njs object */ &njs_math_object_init, /* Math */ &njs_json_object_init, /* JSON */ + NULL }; const njs_object_init_t *njs_module_init[] = { &njs_fs_object_init, /* fs */ - &njs_crypto_object_init /* crypto */ + &njs_crypto_object_init, /* crypto */ + NULL }; @@ -64,6 +70,7 @@ const njs_object_init_t *njs_prototype_ &njs_syntax_error_prototype_init, &njs_type_error_prototype_init, &njs_uri_error_prototype_init, + NULL }; @@ -87,6 +94,7 @@ const njs_object_init_t *njs_construc &njs_type_error_constructor_init, &njs_uri_error_constructor_init, &njs_memory_error_constructor_init, + NULL }; @@ -103,7 +111,8 @@ const njs_object_init_t *njs_function &njs_decode_uri_component_function_init, &njs_require_function_init, &njs_set_timeout_function_init, - &njs_clear_timeout_function_init + &njs_clear_timeout_function_init, + NULL }; @@ -143,102 +152,95 @@ const njs_object_prop_t njs_arguments_o }; -static njs_ret_t -njs_prototype_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, - njs_index_t unused) -{ - vm->retval = njs_value_void; +const njs_function_init_t njs_native_constructors[] = { + /* SunC does not allow empty array initialization. */ + { njs_object_constructor, { 0 } }, + { njs_array_constructor, { 0 } }, + { njs_boolean_constructor, { 0 } }, + { njs_number_constructor, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, + { njs_string_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_function_constructor, { 0 } }, + { njs_regexp_constructor, + { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } }, + { njs_date_constructor, { 0 } }, + { njs_hash_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_hmac_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG, + NJS_STRING_ARG } }, + { njs_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_eval_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_internal_error_constructor, + { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_range_error_constructor, + { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_reference_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_syntax_error_constructor, + { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_type_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_uri_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_memory_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, +}; + +const njs_object_prototype_t njs_prototype_values[] = { + /* + * GCC 4 complains about uninitialized .shared field, + * if the .type field is initialized as .object.type. + */ + { .object = { .type = NJS_OBJECT } }, + { .object = { .type = NJS_ARRAY } }, - return NXT_OK; -} + /* + * The .object.type field must be initialzed after the .value field, + * otherwise SunC 5.9 treats the .value as .object.value or so. + */ + { .object_value = { .value = njs_value(NJS_BOOLEAN, 0, 0.0), + .object = { .type = NJS_OBJECT_BOOLEAN } } }, + + { .object_value = { .value = njs_value(NJS_NUMBER, 0, 0.0), + .object = { .type = NJS_OBJECT_NUMBER } } }, + + { .object_value = { .value = njs_string(""), + .object = { .type = NJS_OBJECT_STRING } } }, + + { .function = { .native = 1, + .args_offset = 1, + .u.native = njs_prototype_function, + .object = { .type = NJS_FUNCTION } } }, + + { .object = { .type = NJS_REGEXP } }, + + { .date = { .time = NAN, + .object = { .type = NJS_DATE } } }, + + { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), + .object = { .type = NJS_OBJECT } } }, + + { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), + .object = { .type = NJS_OBJECT } } }, + + { .object = { .type = NJS_OBJECT_ERROR } }, + { .object = { .type = NJS_OBJECT_EVAL_ERROR } }, + { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, + { .object = { .type = NJS_OBJECT_RANGE_ERROR } }, + { .object = { .type = NJS_OBJECT_REF_ERROR } }, + { .object = { .type = NJS_OBJECT_SYNTAX_ERROR } }, + { .object = { .type = NJS_OBJECT_TYPE_ERROR } }, + { .object = { .type = NJS_OBJECT_URI_ERROR } }, + { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, +}; + nxt_int_t njs_builtin_objects_create(njs_vm_t *vm) { - nxt_int_t ret; - nxt_uint_t i; - njs_module_t *module; - njs_object_t *objects; - njs_function_t *functions, *constructors; - nxt_lvlhsh_query_t lhq; - njs_object_prototype_t *prototypes; - - static const njs_object_prototype_t prototype_values[] = { - /* - * GCC 4 complains about uninitialized .shared field, - * if the .type field is initialized as .object.type. - */ - { .object = { .type = NJS_OBJECT } }, - { .object = { .type = NJS_ARRAY } }, - - /* - * The .object.type field must be initialzed after the .value field, - * otherwise SunC 5.9 treats the .value as .object.value or so. - */ - { .object_value = { .value = njs_value(NJS_BOOLEAN, 0, 0.0), - .object = { .type = NJS_OBJECT_BOOLEAN } } }, - - { .object_value = { .value = njs_value(NJS_NUMBER, 0, 0.0), - .object = { .type = NJS_OBJECT_NUMBER } } }, - - { .object_value = { .value = njs_string(""), - .object = { .type = NJS_OBJECT_STRING } } }, - - { .function = { .native = 1, - .args_offset = 1, - .u.native = njs_prototype_function, - .object = { .type = NJS_FUNCTION } } }, - - { .object = { .type = NJS_REGEXP } }, - - { .date = { .time = NAN, - .object = { .type = NJS_DATE } } }, - - { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), - .object = { .type = NJS_OBJECT } } }, - - { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), - .object = { .type = NJS_OBJECT } } }, - - { .object = { .type = NJS_OBJECT_ERROR } }, - { .object = { .type = NJS_OBJECT_EVAL_ERROR } }, - { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, - { .object = { .type = NJS_OBJECT_RANGE_ERROR } }, - { .object = { .type = NJS_OBJECT_REF_ERROR } }, - { .object = { .type = NJS_OBJECT_SYNTAX_ERROR } }, - { .object = { .type = NJS_OBJECT_TYPE_ERROR } }, - { .object = { .type = NJS_OBJECT_URI_ERROR } }, - { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, - }; - - static const njs_function_init_t native_constructors[] = { - /* SunC does not allow empty array initialization. */ - { njs_object_constructor, { 0 } }, - { njs_array_constructor, { 0 } }, - { njs_boolean_constructor, { 0 } }, - { njs_number_constructor, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, - { njs_string_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_function_constructor, { 0 } }, - { njs_regexp_constructor, - { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } }, - { njs_date_constructor, { 0 } }, - { njs_hash_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_hmac_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG, - NJS_STRING_ARG } }, - { njs_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_eval_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_internal_error_constructor, - { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_range_error_constructor, - { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_reference_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_syntax_error_constructor, - { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_type_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_uri_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_memory_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - }; + nxt_int_t ret; + njs_module_t *module; + njs_object_t *object; + njs_function_t *func; + nxt_lvlhsh_query_t lhq; + njs_object_prototype_t *prototype; + const njs_object_init_t *obj, **p; + const njs_function_init_t *f; static const njs_object_prop_t function_prototype_property = { .type = NJS_PROPERTY_HANDLER, @@ -246,6 +248,8 @@ njs_builtin_objects_create(njs_vm_t *vm) .value = njs_prop_handler(njs_function_prototype_create), }; + static const nxt_str_t sandbox_key = nxt_string("sandbox"); + ret = njs_object_hash_create(vm, &vm->shared->function_prototype_hash, &function_prototype_property, 1); if (nxt_slow_path(ret != NXT_OK)) { @@ -259,48 +263,57 @@ njs_builtin_objects_create(njs_vm_t *vm) return NXT_ERROR; } - objects = vm->shared->objects; + object = vm->shared->objects; + + for (p = njs_object_init; *p != NULL; p++) { + obj = *p; - for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) { - if (njs_object_init[i] != NULL) { - ret = njs_object_hash_create(vm, &objects[i].shared_hash, - njs_object_init[i]->properties, - njs_object_init[i]->items); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } + ret = njs_object_hash_create(vm, &object->shared_hash, + obj->properties, obj->items); + + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; } - objects[i].shared = 1; + object->shared = 1; + + object++; } lhq.replace = 0; - lhq.proto = &njs_modules_hash_proto; lhq.pool = vm->mem_cache_pool; - for (i = NJS_MODULE_FS; i < NJS_MODULE_MAX; i++) { - if (vm->options.sandbox && !njs_sandbox_module(i)) { - continue; - } + for (p = njs_module_init; *p != NULL; p++) { + obj = *p; module = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_module_t)); if (nxt_slow_path(module == NULL)) { return NJS_ERROR; } - module->name = njs_module_init[i]->name; - ret = njs_object_hash_create(vm, &module->object.shared_hash, - njs_module_init[i]->properties, - njs_module_init[i]->items); + obj->properties, obj->items); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } + if (vm->options.sandbox) { + lhq.key = sandbox_key; + lhq.key_hash = nxt_djb_hash(sandbox_key.start, sandbox_key.length); + lhq.proto = &njs_object_hash_proto; + + ret = nxt_lvlhsh_find(&module->object.shared_hash, &lhq); + if (nxt_fast_path(ret != NXT_OK)) { + continue; + } + } + + module->name = obj->name; module->object.shared = 1; lhq.key = module->name; lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); + lhq.proto = &njs_modules_hash_proto; lhq.value = module; ret = nxt_lvlhsh_insert(&vm->modules_hash, &lhq); @@ -309,73 +322,88 @@ njs_builtin_objects_create(njs_vm_t *vm) } } - functions = vm->shared->functions; + f = njs_native_functions; + func = vm->shared->functions; - for (i = NJS_FUNCTION_EVAL; i < NJS_FUNCTION_MAX; i++) { - if (njs_function_init[i]->items != 0) { - ret = njs_object_hash_create(vm, &functions[i].object.shared_hash, - njs_function_init[i]->properties, - njs_function_init[i]->items); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } + for (p = njs_function_init; *p != NULL; p++) { + obj = *p; + + ret = njs_object_hash_create(vm, &func->object.shared_hash, + obj->properties, obj->items); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; } - functions[i].object.shared = 1; - functions[i].object.extensible = 1; - functions[i].native = 1; - functions[i].args_offset = 1; - functions[i].u.native = njs_native_functions[i].native; - functions[i].args_types[0] = njs_native_functions[i].args_types[0]; - functions[i].args_types[1] = njs_native_functions[i].args_types[1]; - functions[i].args_types[2] = njs_native_functions[i].args_types[2]; - functions[i].args_types[3] = njs_native_functions[i].args_types[3]; - functions[i].args_types[4] = njs_native_functions[i].args_types[4]; + func->object.shared = 1; + func->object.extensible = 1; + func->native = 1; + func->args_offset = 1; + + func->u.native = f->native; + memcpy(func->args_types, f->args_types, NJS_ARGS_TYPES_MAX); + + f++; + func++; } - prototypes = vm->shared->prototypes; + prototype = vm->shared->prototypes; + memcpy(prototype, njs_prototype_values, sizeof(njs_prototype_values)); - for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) { - prototypes[i] = prototype_values[i]; + for (p = njs_prototype_init; *p != NULL; p++) { + obj = *p; - ret = njs_object_hash_create(vm, &prototypes[i].object.shared_hash, - njs_prototype_init[i]->properties, - njs_prototype_init[i]->items); + ret = njs_object_hash_create(vm, &prototype->object.shared_hash, + obj->properties, obj->items); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } + + prototype++; } - prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern = + vm->shared->prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern = vm->shared->empty_regexp_pattern; - constructors = vm->shared->constructors; + f = njs_native_constructors; + func = vm->shared->constructors; + + for (p = njs_constructor_init; *p != NULL; p++) { + obj = *p; - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { - constructors[i].object.shared = 0; - constructors[i].object.extensible = 1; - constructors[i].native = 1; - constructors[i].ctor = 1; - constructors[i].args_offset = 1; - constructors[i].u.native = native_constructors[i].native; - constructors[i].args_types[0] = native_constructors[i].args_types[0]; - constructors[i].args_types[1] = native_constructors[i].args_types[1]; - constructors[i].args_types[2] = native_constructors[i].args_types[2]; - constructors[i].args_types[3] = native_constructors[i].args_types[3]; - constructors[i].args_types[4] = native_constructors[i].args_types[4]; + func->object.shared = 0; + func->object.extensible = 1; + func->native = 1; + func->ctor = 1; + func->args_offset = 1; - ret = njs_object_hash_create(vm, &constructors[i].object.shared_hash, - njs_constructor_init[i]->properties, - njs_constructor_init[i]->items); + func->u.native = f->native; + + memcpy(func->args_types, f->args_types, NJS_ARGS_TYPES_MAX); + + ret = njs_object_hash_create(vm, &func->object.shared_hash, + obj->properties, obj->items); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } + + f++; + func++; } return NXT_OK; } +static njs_ret_t +njs_prototype_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + vm->retval = njs_value_void; + + return NXT_OK; +} + + /* * Object(), * Object.__proto__ -> Function_Prototype, @@ -493,53 +521,15 @@ njs_builtin_objects_clone(njs_vm_t *vm) } -nxt_array_t * -njs_vm_completions(njs_vm_t *vm, nxt_str_t *expression) +static size_t +njs_builtin_completions_size(njs_vm_t *vm) { - size_t size; - nxt_array_t *completions; - - if (expression == NULL) { - if (njs_builtin_completions(vm, &size, NULL) != NXT_OK) { - return NULL; - } - - completions = nxt_array_create(size, sizeof(nxt_str_t), - &njs_array_mem_proto, - vm->mem_cache_pool); - - if (nxt_slow_path(completions == NULL)) { - return NULL; - } - - if (njs_builtin_completions(vm, &size, completions->start) != NXT_OK) { - return NULL; - } - - completions->items = size; - - return completions; - } - - return njs_vm_expression_completions(vm, expression); -} - - -static nxt_int_t -njs_builtin_completions(njs_vm_t *vm, size_t *size, nxt_str_t *completions) -{ - char *compl; - size_t n, len; - nxt_str_t string; - nxt_uint_t i, k; - njs_object_t *objects; - njs_keyword_t *keyword; - njs_function_t *constructors; - njs_object_prop_t *prop; - nxt_lvlhsh_each_t lhe, lhe_prop; - njs_extern_value_t *ev; - const njs_extern_t *ext_proto, *ext_prop; - njs_object_prototype_t *prototypes; + nxt_uint_t n; + njs_keyword_t *keyword; + nxt_lvlhsh_each_t lhe, lhe_prop; + njs_extern_value_t *ev; + const njs_extern_t *ext_proto, *ext_prop; + const njs_object_init_t **p; n = 0; @@ -552,123 +542,147 @@ njs_builtin_completions(njs_vm_t *vm, si break; } - if (completions != NULL) { - completions[n++] = keyword->name; + n++; + } + + for (p = njs_object_init; *p != NULL; p++) { + n += (*p)->items; + } + + for (p = njs_prototype_init; *p != NULL; p++) { + n += (*p)->items; + } + + for (p = njs_constructor_init; *p != NULL; p++) { + n += (*p)->items; + } + + nxt_lvlhsh_each_init(&lhe, &njs_extern_value_hash_proto); - } else { + for ( ;; ) { + ev = nxt_lvlhsh_each(&vm->externals_hash, &lhe); + + if (ev == NULL) { + break; + } + + ext_proto = ev->value.external.proto; + + nxt_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto); + + n++; + + for ( ;; ) { + ext_prop = nxt_lvlhsh_each(&ext_proto->hash, &lhe_prop); + + if (ext_prop == NULL) { + break; + } + n++; } } - objects = vm->shared->objects; + return n; +} + - for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) { - if (njs_object_init[i] == NULL) { - continue; +static nxt_array_t * +njs_builtin_completions(njs_vm_t *vm, nxt_array_t *array) +{ + char *compl; + size_t n, len; + nxt_str_t string, *completions; + nxt_uint_t i, k; + njs_keyword_t *keyword; + nxt_lvlhsh_each_t lhe, lhe_prop; + njs_extern_value_t *ev; + const njs_extern_t *ext_proto, *ext_prop; + const njs_object_prop_t *prop; + const njs_object_init_t *obj, **p; + + n = 0; + completions = array->start; + + nxt_lvlhsh_each_init(&lhe, &njs_keyword_hash_proto); + + for ( ;; ) { + keyword = nxt_lvlhsh_each(&vm->shared->keywords_hash, &lhe); + + if (keyword == NULL) { + break; } - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + completions[n++] = keyword->name; + } + + for (p = njs_object_init; *p != NULL; p++) { + obj = *p; - for ( ;; ) { - prop = nxt_lvlhsh_each(&objects[i].shared_hash, &lhe); + for (i = 0; i < obj->items; i++) { + prop = &obj->properties[i]; + njs_string_get(&prop->name, &string); + len = obj->name.length + string.length + 2; - if (prop == NULL) { - break; + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); + if (compl == NULL) { + return NULL; } - if (completions != NULL) { - njs_string_get(&prop->name, &string); - len = njs_object_init[i]->name.length + string.length + 2; + snprintf(compl, len, "%s.%s", obj->name.start, string.start); + + completions[n].length = len; + completions[n++].start = (u_char *) compl; + } + } + + for (p = njs_prototype_init; *p != NULL; p++) { + obj = *p; + + for (i = 0; i < obj->items; i++) { + prop = &obj->properties[i]; + njs_string_get(&prop->name, &string); + len = string.length + 2; - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (compl == NULL) { - return NXT_ERROR; + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); + if (compl == NULL) { + return NULL; + } + + snprintf(compl, len, ".%s", string.start); + + for (k = 0; k < n; k++) { + if (strncmp((char *) completions[k].start, compl, len) + == 0) + { + break; } + } - snprintf(compl, len, "%s.%s", njs_object_init[i]->name.start, - string.start); - + if (k == n) { completions[n].length = len; completions[n++].start = (u_char *) compl; - - } else { - n++; } } } - prototypes = vm->shared->prototypes; - - for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + for (p = njs_constructor_init; *p != NULL; p++) { + obj = *p; - for ( ;; ) { - prop = nxt_lvlhsh_each(&prototypes[i].object.shared_hash, &lhe); + for (i = 0; i < obj->items; i++) { + prop = &obj->properties[i]; + njs_string_get(&prop->name, &string); + len = obj->name.length + string.length + 2; - if (prop == NULL) { - break; + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); + if (compl == NULL) { + return NULL; } - if (completions != NULL) { - njs_string_get(&prop->name, &string); - len = string.length + 2; - - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (compl == NULL) { - return NXT_ERROR; - } - - snprintf(compl, len, ".%s", string.start); - - for (k = 0; k < n; k++) { - if (strncmp((char *) completions[k].start, compl, len) - == 0) - { - break; - } - } - - if (k == n) { - completions[n].length = len; - completions[n++].start = (u_char *) compl; - } - - } else { - n++; - } - } - } + snprintf(compl, len, "%s.%s", obj->name.start, string.start); - constructors = vm->shared->constructors; - - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - - for ( ;; ) { - prop = nxt_lvlhsh_each(&constructors[i].object.shared_hash, &lhe); - - if (prop == NULL) { - break; - } - - if (completions != NULL) { - njs_string_get(&prop->name, &string); - len = njs_constructor_init[i]->name.length + string.length + 2; - - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (compl == NULL) { - return NXT_ERROR; - } - - snprintf(compl, len, "%s.%s", - njs_constructor_init[i]->name.start, string.start); - - completions[n].length = len; - completions[n++].start = (u_char *) compl; - - } else { - n++; - } + completions[n].length = len; + completions[n++].start = (u_char *) compl; } } @@ -685,21 +699,16 @@ njs_builtin_completions(njs_vm_t *vm, si nxt_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto); - if (completions != NULL) { - len = ev->name.length + 1; - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (compl == NULL) { - return NXT_ERROR; - } + len = ev->name.length + 1; + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); + if (compl == NULL) { + return NULL; + } - snprintf(compl, len, "%.*s", (int) ev->name.length, ev->name.start); + snprintf(compl, len, "%.*s", (int) ev->name.length, ev->name.start); - completions[n].length = len; - completions[n++].start = (u_char *) compl; - - } else { - n++; - } + completions[n].length = len; + completions[n++].start = (u_char *) compl; for ( ;; ) { ext_prop = nxt_lvlhsh_each(&ext_proto->hash, &lhe_prop); @@ -708,31 +717,48 @@ njs_builtin_completions(njs_vm_t *vm, si break; } - if (completions != NULL) { - len = ev->name.length + ev->name.length + 2; - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (compl == NULL) { - return NXT_ERROR; - } + len = ev->name.length + ev->name.length + 2; + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); + if (compl == NULL) { + return NULL; + } - snprintf(compl, len, "%.*s.%.*s", (int) ev->name.length, - ev->name.start, (int) ext_prop->name.length, - ext_prop->name.start); + snprintf(compl, len, "%.*s.%.*s", (int) ev->name.length, + ev->name.start, (int) ext_prop->name.length, + ext_prop->name.start); - completions[n].length = len; - completions[n++].start = (u_char *) compl; - - } else { - n++; - } + completions[n].length = len; + completions[n++].start = (u_char *) compl; } } - if (size) { - *size = n; + array->items = n; + + return array; +} + + +nxt_array_t * +njs_vm_completions(njs_vm_t *vm, nxt_str_t *expression) +{ + size_t size; + nxt_array_t *completions; + + if (expression == NULL) { + size = njs_builtin_completions_size(vm); + + completions = nxt_array_create(size, sizeof(nxt_str_t), + &njs_array_mem_proto, + vm->mem_cache_pool); + + if (nxt_slow_path(completions == NULL)) { + return NULL; + } + + return njs_builtin_completions(vm, completions); } - return NXT_OK; + return njs_vm_expression_completions(vm, expression); } @@ -911,185 +937,135 @@ njs_object_completions(njs_vm_t *vm, njs } -nxt_int_t -njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, - nxt_str_t *name) +static nxt_int_t +njs_builtin_match(const njs_object_init_t **objects, njs_function_t *function, + const njs_object_prop_t **prop, const njs_object_init_t **object) { - char *buf; - size_t len; - nxt_str_t string; - nxt_uint_t i; - njs_module_t *module; - njs_object_t *objects; - njs_function_t *constructors; - njs_object_prop_t *prop; - nxt_lvlhsh_each_t lhe, lhe_prop; - njs_object_prototype_t *prototypes; + nxt_uint_t i; + const njs_object_init_t *o, **p; + const njs_object_prop_t *pr; - objects = vm->shared->objects; - - for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) { - if (njs_object_init[i] == NULL) { - continue; - } - - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + for (p = objects; *p != NULL; p++) { + o = *p; - for ( ;; ) { - prop = nxt_lvlhsh_each(&objects[i].shared_hash, &lhe); + for (i = 0; i < o->items; i++) { + pr = &o->properties[i]; - if (prop == NULL) { - break; - } - - if (!njs_is_function(&prop->value)) { + if (pr->type != NJS_METHOD) { continue; } - if (function == prop->value.data.u.function) { - njs_string_get(&prop->name, &string); - len = njs_object_init[i]->name.length + string.length - + sizeof("."); - - buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (buf == NULL) { - return NXT_ERROR; - } - - snprintf(buf, len, "%s.%s", njs_object_init[i]->name.start, - string.start); - - name->length = len; - name->start = (u_char *) buf; - - return NXT_OK; - } - } - } - - prototypes = vm->shared->prototypes; - - for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - - for ( ;; ) { - prop = nxt_lvlhsh_each(&prototypes[i].object.shared_hash, &lhe); - - if (prop == NULL) { - break; - } - - if (!njs_is_function(&prop->value)) { + if (function != pr->value.data.u.function) { continue; } - if (function == prop->value.data.u.function) { - njs_string_get(&prop->name, &string); - len = njs_prototype_init[i]->name.length + string.length - + sizeof(".prototype."); - - buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (buf == NULL) { - return NXT_ERROR; - } - - snprintf(buf, len, "%s.prototype.%s", - njs_prototype_init[i]->name.start, string.start); - - name->length = len; - name->start = (u_char *) buf; - - return NXT_OK; - } - } - } - - constructors = vm->shared->constructors; - - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - - for ( ;; ) { - prop = nxt_lvlhsh_each(&constructors[i].object.shared_hash, &lhe); - - if (prop == NULL) { - break; - } - - if (!njs_is_function(&prop->value)) { - continue; - } - - if (function == prop->value.data.u.function) { - njs_string_get(&prop->name, &string); _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel