| |
| /* |
| * Copyright (C) Igor Sysoev |
| * Copyright (C) Dmitry Volyntsev |
| * Copyright (C) NGINX, Inc. |
| */ |
| |
| |
| #include <njs_main.h> |
| |
| |
| typedef struct { |
| enum { |
| NJS_BUILTIN_TRAVERSE_KEYS, |
| NJS_BUILTIN_TRAVERSE_MATCH, |
| } type; |
| |
| njs_function_t *func; |
| |
| njs_lvlhsh_t keys; |
| njs_str_t match; |
| } njs_builtin_traverse_t; |
| |
| |
| static njs_int_t njs_global_this_prop_handler(njs_vm_t *vm, |
| njs_object_prop_t *self, njs_value_t *global, njs_value_t *setval, |
| njs_value_t *retval); |
| static njs_arr_t *njs_vm_expression_completions(njs_vm_t *vm, |
| njs_str_t *expression); |
| static njs_arr_t *njs_object_completions(njs_vm_t *vm, njs_value_t *object); |
| static njs_int_t njs_env_hash_init(njs_vm_t *vm, njs_lvlhsh_t *hash, |
| char **environment); |
| |
| |
| static const njs_object_init_t njs_global_this_init; |
| static const njs_object_init_t njs_njs_object_init; |
| static const njs_object_init_t njs_process_object_init; |
| #ifdef NJS_TEST262 |
| static const njs_object_init_t njs_262_object_init; |
| #endif |
| |
| |
| static const njs_object_init_t *njs_object_init[] = { |
| &njs_global_this_init, |
| &njs_njs_object_init, |
| &njs_process_object_init, |
| &njs_math_object_init, |
| &njs_json_object_init, |
| #ifdef NJS_TEST262 |
| &njs_262_object_init, |
| #endif |
| NULL |
| }; |
| |
| |
| static const njs_object_init_t *njs_module_init[] = { |
| &njs_fs_object_init, |
| &njs_crypto_object_init, |
| &njs_query_string_object_init, |
| &njs_buffer_object_init, |
| NULL |
| }; |
| |
| |
| static const njs_object_type_init_t *const |
| njs_object_type_init[NJS_OBJ_TYPE_MAX] = |
| { |
| /* Global types. */ |
| |
| &njs_obj_type_init, |
| &njs_array_type_init, |
| &njs_boolean_type_init, |
| &njs_number_type_init, |
| &njs_symbol_type_init, |
| &njs_string_type_init, |
| &njs_function_type_init, |
| &njs_regexp_type_init, |
| &njs_date_type_init, |
| &njs_promise_type_init, |
| &njs_array_buffer_type_init, |
| &njs_data_view_type_init, |
| &njs_text_decoder_type_init, |
| &njs_text_encoder_type_init, |
| &njs_buffer_type_init, |
| |
| /* Hidden types. */ |
| |
| &njs_iterator_type_init, |
| &njs_array_iterator_type_init, |
| &njs_dirent_type_init, |
| &njs_hash_type_init, |
| &njs_hmac_type_init, |
| &njs_typed_array_type_init, |
| |
| /* TypedArray types. */ |
| |
| &njs_typed_array_u8_type_init, |
| &njs_typed_array_u8clamped_type_init, |
| &njs_typed_array_i8_type_init, |
| &njs_typed_array_u16_type_init, |
| &njs_typed_array_i16_type_init, |
| &njs_typed_array_u32_type_init, |
| &njs_typed_array_i32_type_init, |
| &njs_typed_array_f32_type_init, |
| &njs_typed_array_f64_type_init, |
| |
| /* Error types. */ |
| &njs_error_type_init, |
| &njs_eval_error_type_init, |
| &njs_internal_error_type_init, |
| &njs_range_error_type_init, |
| &njs_reference_error_type_init, |
| &njs_syntax_error_type_init, |
| &njs_type_error_type_init, |
| &njs_uri_error_type_init, |
| &njs_memory_error_type_init, |
| }; |
| |
| |
| extern char **environ; |
| |
| |
| njs_inline njs_int_t |
| njs_object_hash_init(njs_vm_t *vm, njs_lvlhsh_t *hash, |
| const njs_object_init_t *init) |
| { |
| return njs_object_hash_create(vm, hash, init->properties, init->items); |
| } |
| |
| |
| njs_int_t |
| njs_builtin_objects_create(njs_vm_t *vm) |
| { |
| njs_int_t ret; |
| njs_uint_t i; |
| njs_module_t *module; |
| njs_object_t *object, *string_object; |
| njs_function_t *constructor; |
| njs_vm_shared_t *shared; |
| njs_lvlhsh_query_t lhq; |
| njs_regexp_pattern_t *pattern; |
| njs_object_prototype_t *prototype; |
| const njs_object_prop_t *prop; |
| const njs_object_init_t *obj, **p; |
| |
| static const njs_str_t sandbox_key = njs_str("sandbox"); |
| static const njs_str_t name_key = njs_str("name"); |
| |
| shared = njs_mp_zalloc(vm->mem_pool, sizeof(njs_vm_shared_t)); |
| if (njs_slow_path(shared == NULL)) { |
| return NJS_ERROR; |
| } |
| |
| njs_lvlhsh_init(&shared->keywords_hash); |
| njs_lvlhsh_init(&shared->values_hash); |
| |
| pattern = njs_regexp_pattern_create(vm, (u_char *) "(?:)", |
| njs_length("(?:)"), 0); |
| if (njs_slow_path(pattern == NULL)) { |
| return NJS_ERROR; |
| } |
| |
| shared->empty_regexp_pattern = pattern; |
| |
| ret = njs_object_hash_init(vm, &shared->array_instance_hash, |
| &njs_array_instance_init); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| ret = njs_object_hash_init(vm, &shared->string_instance_hash, |
| &njs_string_instance_init); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| ret = njs_object_hash_init(vm, &shared->function_instance_hash, |
| &njs_function_instance_init); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| ret = njs_object_hash_init(vm, &shared->arrow_instance_hash, |
| &njs_arrow_instance_init); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| ret = njs_object_hash_init(vm, &shared->arguments_object_instance_hash, |
| &njs_arguments_object_instance_init); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| ret = njs_object_hash_init(vm, &shared->regexp_instance_hash, |
| &njs_regexp_instance_init); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| object = shared->objects; |
| |
| for (p = njs_object_init; *p != NULL; p++) { |
| obj = *p; |
| |
| ret = njs_object_hash_init(vm, &object->shared_hash, obj); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| object->type = NJS_OBJECT; |
| object->shared = 1; |
| object->extensible = 1; |
| |
| object++; |
| } |
| |
| ret = njs_env_hash_init(vm, &shared->env_hash, environ); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| njs_lvlhsh_init(&shared->modules_hash); |
| |
| lhq.replace = 0; |
| lhq.pool = vm->mem_pool; |
| |
| for (p = njs_module_init; *p != NULL; p++) { |
| obj = *p; |
| |
| module = njs_mp_zalloc(vm->mem_pool, sizeof(njs_module_t)); |
| if (njs_slow_path(module == NULL)) { |
| return NJS_ERROR; |
| } |
| |
| module->function.native = 1; |
| |
| ret = njs_object_hash_init(vm, &module->object.shared_hash, obj); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| if (vm->options.sandbox) { |
| lhq.key = sandbox_key; |
| lhq.key_hash = njs_djb_hash(sandbox_key.start, sandbox_key.length); |
| lhq.proto = &njs_object_hash_proto; |
| |
| ret = njs_lvlhsh_find(&module->object.shared_hash, &lhq); |
| if (njs_fast_path(ret != NJS_OK)) { |
| continue; |
| } |
| } |
| |
| lhq.key = name_key; |
| lhq.key_hash = njs_djb_hash(name_key.start, name_key.length); |
| lhq.proto = &njs_object_hash_proto; |
| |
| ret = njs_lvlhsh_find(&module->object.shared_hash, &lhq); |
| if (njs_fast_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| prop = lhq.value; |
| |
| njs_string_get(&prop->value, &module->name); |
| module->object.shared = 1; |
| |
| lhq.key = module->name; |
| lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); |
| lhq.proto = &njs_modules_hash_proto; |
| lhq.value = module; |
| |
| ret = njs_lvlhsh_insert(&shared->modules_hash, &lhq); |
| if (njs_fast_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| } |
| |
| prototype = shared->prototypes; |
| |
| for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_MAX; i++) { |
| prototype[i] = njs_object_type_init[i]->prototype_value; |
| |
| ret = njs_object_hash_init(vm, &prototype[i].object.shared_hash, |
| njs_object_type_init[i]->prototype_props); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| prototype[i].object.extensible = 1; |
| } |
| |
| shared->prototypes[NJS_OBJ_TYPE_REGEXP].regexp.pattern = |
| shared->empty_regexp_pattern; |
| |
| constructor = shared->constructors; |
| |
| for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_MAX; i++) { |
| if (njs_object_type_init[i]->constructor_props == NULL) { |
| continue; |
| } |
| |
| constructor[i] = njs_object_type_init[i]->constructor; |
| constructor[i].object.shared = 0; |
| |
| ret = njs_object_hash_init(vm, &constructor[i].object.shared_hash, |
| njs_object_type_init[i]->constructor_props); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| } |
| |
| shared->global_slots.prop_handler = njs_global_this_prop_handler; |
| shared->global_slots.writable = 1; |
| shared->global_slots.configurable = 1; |
| shared->global_slots.enumerable = 1; |
| |
| shared->objects[0].slots = &shared->global_slots; |
| |
| 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; |
| } |
| |
| |
| njs_int_t |
| njs_builtin_objects_clone(njs_vm_t *vm, njs_value_t *global) |
| { |
| size_t size; |
| njs_uint_t i; |
| njs_object_t *object_prototype, *function_prototype, |
| *typed_array_prototype, *error_prototype, |
| *typed_array_ctor, *error_ctor; |
| |
| /* |
| * Copy both prototypes and constructors arrays by one memcpy() |
| * because they are stored together. |
| */ |
| size = (sizeof(njs_object_prototype_t) + sizeof(njs_function_t)) |
| * NJS_OBJ_TYPE_MAX; |
| |
| memcpy(vm->prototypes, vm->shared->prototypes, size); |
| |
| object_prototype = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object; |
| |
| for (i = NJS_OBJ_TYPE_ARRAY; i < NJS_OBJ_TYPE_NORMAL_MAX; i++) { |
| vm->prototypes[i].object.__proto__ = object_prototype; |
| } |
| |
| typed_array_prototype = &vm->prototypes[NJS_OBJ_TYPE_TYPED_ARRAY].object; |
| |
| for (i = NJS_OBJ_TYPE_TYPED_ARRAY_MIN; |
| i < NJS_OBJ_TYPE_TYPED_ARRAY_MAX; |
| i++) |
| { |
| vm->prototypes[i].object.__proto__ = typed_array_prototype; |
| } |
| |
| vm->prototypes[NJS_OBJ_TYPE_ARRAY_ITERATOR].object.__proto__ = |
| &vm->prototypes[NJS_OBJ_TYPE_ITERATOR].object; |
| |
| vm->prototypes[NJS_OBJ_TYPE_BUFFER].object.__proto__ = |
| &vm->prototypes[NJS_OBJ_TYPE_UINT8_ARRAY].object; |
| |
| error_prototype = &vm->prototypes[NJS_OBJ_TYPE_ERROR].object; |
| error_prototype->__proto__ = object_prototype; |
| |
| for (i = NJS_OBJ_TYPE_EVAL_ERROR; i < NJS_OBJ_TYPE_MAX; i++) { |
| vm->prototypes[i].object.__proto__ = error_prototype; |
| } |
| |
| function_prototype = &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object; |
| |
| for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_NORMAL_MAX; i++) { |
| vm->constructors[i].object.__proto__ = function_prototype; |
| } |
| |
| typed_array_ctor = &vm->constructors[NJS_OBJ_TYPE_TYPED_ARRAY].object; |
| |
| for (i = NJS_OBJ_TYPE_TYPED_ARRAY_MIN; |
| i < NJS_OBJ_TYPE_TYPED_ARRAY_MAX; |
| i++) |
| { |
| vm->constructors[i].object.__proto__ = typed_array_ctor; |
| } |
| |
| error_ctor = &vm->constructors[NJS_OBJ_TYPE_ERROR].object; |
| error_ctor->__proto__ = function_prototype; |
| |
| for (i = NJS_OBJ_TYPE_EVAL_ERROR; i < NJS_OBJ_TYPE_MAX; i++) { |
| vm->constructors[i].object.__proto__ = error_ctor; |
| } |
| |
| vm->global_object.__proto__ = object_prototype; |
| |
| njs_set_undefined(global); |
| njs_set_object(global, &vm->global_object); |
| |
| vm->string_object = vm->shared->string_object; |
| vm->string_object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_STRING].object; |
| |
| return NJS_OK; |
| } |
| |
| |
| static njs_int_t |
| njs_builtin_traverse(njs_vm_t *vm, njs_traverse_t *traverse, void *data) |
| { |
| size_t len; |
| u_char *p, *start, *end; |
| njs_int_t ret, n; |
| njs_str_t name; |
| njs_bool_t symbol; |
| njs_value_t key; |
| njs_function_t *func; |
| njs_object_prop_t *prop; |
| njs_lvlhsh_query_t lhq; |
| njs_builtin_traverse_t *ctx; |
| njs_traverse_t *path[NJS_TRAVERSE_MAX_DEPTH]; |
| u_char buf[256]; |
| |
| ctx = data; |
| |
| if (ctx->type == NJS_BUILTIN_TRAVERSE_MATCH) { |
| prop = traverse->prop; |
| func = ctx->func; |
| |
| if (!(njs_is_function(&prop->value) |
| && njs_function(&prop->value)->native |
| && njs_native_function_same(njs_function(&prop->value), func))) |
| { |
| return NJS_OK; |
| } |
| } |
| |
| n = 0; |
| |
| while (traverse != NULL) { |
| path[n++] = traverse; |
| traverse = traverse->parent; |
| } |
| |
| n--; |
| |
| p = buf; |
| end = buf + sizeof(buf); |
| |
| do { |
| symbol = 0; |
| key = path[n]->prop->name; |
| |
| if (njs_slow_path(njs_is_symbol(&key))) { |
| symbol = 1; |
| key = *njs_symbol_description(&key); |
| if (njs_is_undefined(&key)) { |
| key = njs_string_empty; |
| } |
| } |
| |
| njs_string_get(&key, &name); |
| |
| if (njs_slow_path((p + name.length + 3) > end)) { |
| njs_type_error(vm, "njs_builtin_traverse() key is too long"); |
| return NJS_ERROR; |
| } |
| |
| if (symbol) { |
| *p++ = '['; |
| |
| } else if (p != buf) { |
| *p++ = '.'; |
| } |
| |
| p = njs_cpymem(p, name.start, name.length); |
| |
| if (symbol) { |
| *p++ = ']'; |
| } |
| |
| } while (n-- > 0); |
| |
| if (ctx->type == NJS_BUILTIN_TRAVERSE_MATCH) { |
| len = ctx->match.length; |
| start = njs_mp_alloc(vm->mem_pool, len + (p - buf) + (len != 0)); |
| if (njs_slow_path(start == NULL)) { |
| njs_memory_error(vm); |
| return NJS_ERROR; |
| } |
| |
| if (len != 0) { |
| memcpy(start, ctx->match.start, len); |
| start[len++] = '.'; |
| } |
| |
| memcpy(start + len, buf, p - buf); |
| ctx->match.length = len + p - buf; |
| ctx->match.start = start; |
| |
| return NJS_DONE; |
| } |
| |
| /* NJS_BUILTIN_TRAVERSE_KEYS. */ |
| |
| prop = njs_object_prop_alloc(vm, &njs_value_undefined, &njs_value_null, 0); |
| if (njs_slow_path(prop == NULL)) { |
| return NJS_ERROR; |
| } |
| |
| ret = njs_string_new(vm, &prop->name, buf, p - buf, 0); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return ret; |
| } |
| |
| lhq.value = prop; |
| njs_string_get(&prop->name, &lhq.key); |
| 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; |
| |
| ret = njs_lvlhsh_insert(&ctx->keys, &lhq); |
| if (njs_slow_path(ret != NJS_OK)) { |
| njs_internal_error(vm, "lvlhsh insert/replace failed"); |
| return NJS_ERROR; |
| } |
| |
| return NJS_OK; |
| } |
| |
| |
| static njs_arr_t * |
| njs_builtin_completions(njs_vm_t *vm) |
| { |
| njs_arr_t *array; |
| njs_str_t *completion; |
| njs_int_t ret; |
| njs_lvlhsh_each_t lhe; |
| njs_builtin_traverse_t ctx; |
| const njs_object_prop_t *prop; |
| |
| array = njs_arr_create(vm->mem_pool, 64, sizeof(njs_str_t)); |
| if (njs_slow_path(array == NULL)) { |
| return NULL; |
| } |
| |
| ret = njs_lexer_keywords(array); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NULL; |
| } |
| |
| /* Global object completions. */ |
| |
| ctx.type = NJS_BUILTIN_TRAVERSE_KEYS; |
| njs_lvlhsh_init(&ctx.keys); |
| |
| ret = njs_object_traverse(vm, &vm->global_object, &ctx, |
| njs_builtin_traverse); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NULL; |
| } |
| |
| njs_lvlhsh_each_init(&lhe, &njs_object_hash_proto); |
| |
| for ( ;; ) { |
| prop = njs_lvlhsh_each(&ctx.keys, &lhe); |
| |
| if (prop == NULL) { |
| break; |
| } |
| |
| completion = njs_arr_add(array); |
| if (njs_slow_path(completion == NULL)) { |
| return NULL; |
| } |
| |
| njs_string_get(&prop->name, completion); |
| } |
| |
| return array; |
| } |
| |
| |
| njs_arr_t * |
| njs_vm_completions(njs_vm_t *vm, njs_str_t *expression) |
| { |
| if (expression == NULL) { |
| return njs_builtin_completions(vm); |
| } |
| |
| return njs_vm_expression_completions(vm, expression); |
| } |
| |
| |
| static njs_arr_t * |
| njs_vm_expression_completions(njs_vm_t *vm, njs_str_t *expression) |
| { |
| u_char *p, *end; |
| njs_int_t ret; |
| njs_value_t *value; |
| njs_variable_t *var; |
| njs_rbtree_node_t *node; |
| njs_object_prop_t *prop; |
| njs_lvlhsh_query_t lhq; |
| njs_variable_node_t var_node; |
| |
| if (njs_slow_path(vm->parser == NULL)) { |
| return NULL; |
| } |
| |
| p = expression->start; |
| end = p + expression->length; |
| |
| lhq.key.start = p; |
| |
| while (p < end && *p != '.') { p++; } |
| |
| lhq.proto = &njs_lexer_hash_proto; |
| lhq.key.length = p - lhq.key.start; |
| lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); |
| |
| ret = njs_lvlhsh_find(&vm->shared->keywords_hash, &lhq); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NULL; |
| } |
| |
| var_node.key = (uintptr_t) lhq.value; |
| |
| node = njs_rbtree_find(&vm->parser->scope->variables, &var_node.node); |
| if (njs_slow_path(node == NULL)) { |
| return NULL; |
| } |
| |
| var = ((njs_variable_node_t *) node)->variable; |
| value = njs_vmcode_operand(vm, var->index); |
| |
| if (!njs_is_object(value)) { |
| return NULL; |
| } |
| |
| lhq.proto = &njs_object_hash_proto; |
| |
| for ( ;; ) { |
| |
| if (p == end) { |
| break; |
| } |
| |
| lhq.key.start = ++p; |
| |
| while (p < end && *p != '.') { p++; } |
| |
| lhq.key.length = p - lhq.key.start; |
| lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); |
| |
| ret = njs_lvlhsh_find(njs_object_hash(value), &lhq); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NULL; |
| } |
| |
| prop = lhq.value; |
| |
| if (!njs_is_object(&prop->value)) { |
| return NULL; |
| } |
| |
| value = &prop->value; |
| } |
| |
| return njs_object_completions(vm, value); |
| } |
| |
| |
| static njs_arr_t * |
| njs_object_completions(njs_vm_t *vm, njs_value_t *object) |
| { |
| double num; |
| njs_arr_t *array; |
| njs_str_t *completion; |
| njs_uint_t n; |
| njs_array_t *keys; |
| njs_value_type_t type; |
| |
| array = NULL; |
| type = object->type; |
| |
| if (type == NJS_ARRAY || type == NJS_TYPED_ARRAY) { |
| object->type = NJS_OBJECT; |
| } |
| |
| keys = njs_value_enumerate(vm, object, NJS_ENUM_KEYS, NJS_ENUM_STRING, 1); |
| if (njs_slow_path(keys == NULL)) { |
| goto done; |
| } |
| |
| array = njs_arr_create(vm->mem_pool, 8, sizeof(njs_str_t)); |
| if (njs_slow_path(array == NULL)) { |
| goto done; |
| } |
| |
| for (n = 0; n < keys->length; n++) { |
| num = njs_key_to_index(&keys->start[n]); |
| |
| if (!njs_key_is_integer_index(num, &keys->start[n])) { |
| completion = njs_arr_add(array); |
| if (njs_slow_path(completion == NULL)) { |
| njs_arr_destroy(array); |
| array = NULL; |
| goto done; |
| } |
| |
| njs_string_get(&keys->start[n], completion); |
| } |
| } |
| |
| done: |
| |
| if (type == NJS_ARRAY || type == NJS_TYPED_ARRAY) { |
| object->type = type; |
| } |
| |
| return array; |
| } |
| |
| |
| typedef struct { |
| njs_str_t name; |
| njs_function_native_t native; |
| uint8_t magic8; |
| } njs_function_name_t; |
| |
| |
| njs_int_t |
| njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, |
| njs_str_t *name) |
| { |
| uint8_t magic8; |
| njs_int_t ret; |
| njs_uint_t i, n; |
| njs_value_t value; |
| njs_module_t *module; |
| njs_lvlhsh_each_t lhe; |
| njs_function_name_t *fn; |
| njs_function_native_t native; |
| njs_builtin_traverse_t ctx; |
| |
| if (vm->functions_name_cache != NULL) { |
| n = vm->functions_name_cache->items; |
| fn = vm->functions_name_cache->start; |
| |
| magic8 = function->magic8; |
| native = function->u.native; |
| |
| while (n != 0) { |
| if (fn->native == native && fn->magic8 == magic8) { |
| *name = fn->name; |
| return NJS_OK; |
| } |
| |
| fn++; |
| n--; |
| } |
| } |
| |
| ctx.type = NJS_BUILTIN_TRAVERSE_MATCH; |
| ctx.func = function; |
| |
| /* Global object. */ |
| |
| ctx.match = njs_str_value(""); |
| |
| ret = njs_object_traverse(vm, &vm->global_object, &ctx, |
| njs_builtin_traverse); |
| |
| if (ret == NJS_DONE) { |
| goto found; |
| } |
| |
| /* Constructor from built-in modules (not-mapped to global object). */ |
| |
| for (i = NJS_OBJ_TYPE_HIDDEN_MIN; i < NJS_OBJ_TYPE_HIDDEN_MAX; i++) { |
| njs_set_object(&value, &vm->constructors[i].object); |
| |
| ret = njs_value_property(vm, &value, njs_value_arg(&njs_string_name), |
| &value); |
| |
| if (ret == NJS_OK && njs_is_string(&value)) { |
| njs_string_get(&value, &ctx.match); |
| } |
| |
| ret = njs_object_traverse(vm, &vm->constructors[i].object, &ctx, |
| njs_builtin_traverse); |
| |
| if (ret == NJS_DONE) { |
| goto found; |
| } |
| } |
| |
| /* Modules. */ |
| |
| njs_lvlhsh_each_init(&lhe, &njs_modules_hash_proto); |
| |
| for ( ;; ) { |
| module = njs_lvlhsh_each(&vm->modules_hash, &lhe); |
| |
| if (module == NULL) { |
| break; |
| } |
| |
| ctx.match = module->name; |
| |
| ret = njs_object_traverse(vm, &module->object, &ctx, |
| njs_builtin_traverse); |
| |
| if (ret == NJS_DONE) { |
| goto found; |
| } |
| } |
| |
| return NJS_DECLINED; |
| |
| found: |
| |
| if (vm->functions_name_cache == NULL) { |
| vm->functions_name_cache = njs_arr_create(vm->mem_pool, 4, |
| sizeof(njs_function_name_t)); |
| if (njs_slow_path(vm->functions_name_cache == NULL)) { |
| return NJS_ERROR; |
| } |
| } |
| |
| fn = njs_arr_add(vm->functions_name_cache); |
| if (njs_slow_path(fn == NULL)) { |
| njs_memory_error(vm); |
| return NJS_ERROR; |
| } |
| |
| fn->name = ctx.match; |
| fn->native = function->u.native; |
| fn->magic8 = function->magic8; |
| |
| *name = fn->name; |
| |
| return NJS_OK; |
| } |
| |
| |
| static njs_int_t |
| njs_dump_value(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, |
| njs_index_t unused) |
| { |
| uint32_t n; |
| njs_int_t ret; |
| njs_str_t str; |
| njs_value_t *value, *indent; |
| |
| value = njs_arg(args, nargs, 1); |
| indent = njs_arg(args, nargs, 2); |
| |
| ret = njs_value_to_uint32(vm, indent, &n); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return ret; |
| } |
| |
| n = njs_min(n, 5); |
| |
| if (njs_vm_value_dump(vm, &str, value, 1, n) != NJS_OK) { |
| return NJS_ERROR; |
| } |
| |
| return njs_string_new(vm, &vm->retval, str.start, str.length, 0); |
| } |
| |
| |
| static njs_int_t |
| njs_global_this_prop_handler(njs_vm_t *vm, njs_object_prop_t *prop, |
| njs_value_t *global, njs_value_t *setval, njs_value_t *retval) |
| { |
| njs_int_t ret; |
| njs_value_t *value; |
| njs_rbtree_node_t *rb_node; |
| njs_lvlhsh_query_t lhq; |
| njs_variable_node_t *node, var_node; |
| |
| if (retval == NULL) { |
| return NJS_DECLINED; |
| } |
| |
| njs_string_get(&prop->name, &lhq.key); |
| lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); |
| lhq.proto = &njs_lexer_hash_proto; |
| |
| ret = njs_lvlhsh_find(&vm->shared->keywords_hash, &lhq); |
| |
| if (njs_slow_path(ret != NJS_OK || lhq.value == NULL)) { |
| return NJS_DECLINED; |
| } |
| |
| var_node.key = (uintptr_t) lhq.value; |
| |
| rb_node = njs_rbtree_find(vm->variables_hash, &var_node.node); |
| if (rb_node == NULL) { |
| return NJS_DECLINED; |
| } |
| |
| node = (njs_variable_node_t *) rb_node; |
| value = njs_vmcode_operand(vm, node->variable->index); |
| |
| if (setval != NULL) { |
| *value = *setval; |
| } |
| |
| *retval = *value; |
| |
| return NJS_OK; |
| } |
| |
| |
| static njs_int_t |
| njs_global_this_object(njs_vm_t *vm, njs_object_prop_t *self, |
| njs_value_t *global, njs_value_t *setval, njs_value_t *retval) |
| { |
| njs_int_t ret; |
| njs_object_prop_t *prop; |
| njs_lvlhsh_query_t lhq; |
| |
| *retval = *global; |
| |
| if (njs_slow_path(setval != NULL)) { |
| *retval = *setval; |
| |
| } else if (njs_slow_path(retval == NULL)) { |
| return NJS_DECLINED; |
| } |
| |
| prop = njs_object_prop_alloc(vm, &self->name, retval, 1); |
| if (njs_slow_path(prop == NULL)) { |
| return NJS_ERROR; |
| } |
| |
| /* GC */ |
| |
| prop->value = *retval; |
| prop->enumerable = self->enumerable; |
| |
| lhq.value = prop; |
| njs_string_get(&self->name, &lhq.key); |
| lhq.key_hash = self->value.data.magic32; |
| lhq.replace = 1; |
| lhq.pool = vm->mem_pool; |
| lhq.proto = &njs_object_hash_proto; |
| |
| ret = njs_lvlhsh_insert(njs_object_hash(global), &lhq); |
| if (njs_slow_path(ret != NJS_OK)) { |
| njs_internal_error(vm, "lvlhsh insert/replace failed"); |
| return NJS_ERROR; |
| } |
| |
| return NJS_OK; |
| } |
| |
| |
| static njs_int_t |
| njs_top_level_object(njs_vm_t *vm, njs_object_prop_t *self, |
| njs_value_t *global, njs_value_t *setval, njs_value_t *retval) |
| { |
| njs_int_t ret; |
| njs_object_t *object; |
| njs_object_prop_t *prop; |
| njs_lvlhsh_query_t lhq; |
| |
| if (njs_slow_path(setval != NULL)) { |
| *retval = *setval; |
| |
| } else { |
| if (njs_slow_path(retval == NULL)) { |
| return NJS_DECLINED; |
| } |
| |
| njs_set_object(retval, &vm->shared->objects[self->value.data.magic16]); |
| |
| object = njs_object_value_copy(vm, retval); |
| if (njs_slow_path(object == NULL)) { |
| return NJS_ERROR; |
| } |
| } |
| |
| prop = njs_object_prop_alloc(vm, &self->name, retval, 1); |
| if (njs_slow_path(prop == NULL)) { |
| return NJS_ERROR; |
| } |
| |
| /* GC */ |
| |
| prop->value = *retval; |
| prop->enumerable = self->enumerable; |
| |
| lhq.value = prop; |
| njs_string_get(&self->name, &lhq.key); |
| lhq.key_hash = self->value.data.magic32; |
| lhq.replace = 1; |
| lhq.pool = vm->mem_pool; |
| lhq.proto = &njs_object_hash_proto; |
| |
| ret = njs_lvlhsh_insert(njs_object_hash(global), &lhq); |
| if (njs_slow_path(ret != NJS_OK)) { |
| njs_internal_error(vm, "lvlhsh insert/replace failed"); |
| return NJS_ERROR; |
| } |
| |
| return NJS_OK; |
| } |
| |
| |
| static njs_int_t |
| njs_top_level_constructor(njs_vm_t *vm, njs_object_prop_t *self, |
| njs_value_t *global, njs_value_t *setval, njs_value_t *retval) |
| { |
| njs_int_t ret; |
| njs_function_t *ctor; |
| njs_object_prop_t *prop; |
| njs_lvlhsh_query_t lhq; |
| |
| if (njs_slow_path(setval != NULL)) { |
| *retval = *setval; |
| |
| } else { |
| if (njs_slow_path(retval == NULL)) { |
| return NJS_DECLINED; |
| } |
| |
| ctor = &vm->constructors[self->value.data.magic16]; |
| |
| njs_set_function(retval, ctor); |
| } |
| |
| prop = njs_object_prop_alloc(vm, &self->name, retval, 1); |
| if (njs_slow_path(prop == NULL)) { |
| return NJS_ERROR; |
| } |
| |
| /* GC */ |
| |
| prop->value = *retval; |
| prop->enumerable = 0; |
| |
| lhq.value = prop; |
| njs_string_get(&self->name, &lhq.key); |
| lhq.key_hash = self->value.data.magic32; |
| lhq.replace = 1; |
| lhq.pool = vm->mem_pool; |
| lhq.proto = &njs_object_hash_proto; |
| |
| ret = njs_lvlhsh_insert(njs_object_hash(global), &lhq); |
| if (njs_slow_path(ret != NJS_OK)) { |
| njs_internal_error(vm, "lvlhsh insert/replace failed"); |
| return NJS_ERROR; |
| } |
| |
| return NJS_OK; |
| } |
| |
| |
| static const njs_object_prop_t njs_global_this_object_properties[] = |
| { |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG), |
| .value = njs_string("global"), |
| .configurable = 1, |
| }, |
| |
| /* Global aliases. */ |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("global"), |
| .value = njs_prop_handler2(njs_global_this_object, 0, NJS_GLOBAL_HASH), |
| .writable = 1, |
| .enumerable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("globalThis"), |
| .value = njs_prop_handler2(njs_global_this_object, 0, |
| NJS_GLOBAL_THIS_HASH), |
| .writable = 1, |
| .enumerable = 0, |
| .configurable = 1, |
| }, |
| |
| /* Global constants. */ |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("NaN"), |
| .value = njs_value(NJS_NUMBER, 0, NAN), |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("Infinity"), |
| .value = njs_value(NJS_NUMBER, 1, INFINITY), |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("undefined"), |
| .value = njs_value(NJS_UNDEFINED, 0, NAN), |
| }, |
| |
| /* Global functions. */ |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("isFinite"), |
| .value = njs_native_function(njs_number_global_is_finite, 1), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("isNaN"), |
| .value = njs_native_function(njs_number_global_is_nan, 1), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("parseFloat"), |
| .value = njs_native_function(njs_number_parse_float, 1), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("parseInt"), |
| .value = njs_native_function(njs_number_parse_int, 2), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("toString"), |
| .value = njs_native_function(njs_object_prototype_to_string, 0), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("encodeURI"), |
| .value = njs_native_function2(njs_string_encode_uri, 1, 0), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_long_string("encodeURIComponent"), |
| .value = njs_native_function2(njs_string_encode_uri, 1, 1), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("decodeURI"), |
| .value = njs_native_function2(njs_string_decode_uri, 1, 0), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_long_string("decodeURIComponent"), |
| .value = njs_native_function2(njs_string_decode_uri, 1, 1), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("eval"), |
| .value = njs_native_function(njs_eval_function, 1), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("setTimeout"), |
| .value = njs_native_function(njs_set_timeout, 2), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("setImmediate"), |
| .value = njs_native_function(njs_set_immediate, 4), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("clearTimeout"), |
| .value = njs_native_function(njs_clear_timeout, 1), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("require"), |
| .value = njs_native_function(njs_module_require, 1), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| /* Global objects. */ |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("njs"), |
| .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_NJS, |
| NJS_NJS_HASH), |
| .writable = 1, |
| .enumerable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("process"), |
| .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_PROCESS, |
| NJS_PROCESS_HASH), |
| .writable = 1, |
| .enumerable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Math"), |
| .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_MATH, |
| NJS_MATH_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("JSON"), |
| .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_JSON, |
| NJS_JSON_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| #ifdef NJS_TEST262 |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("$262"), |
| .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_262, |
| NJS_262_HASH), |
| .writable = 1, |
| .enumerable = 1, |
| .configurable = 1, |
| }, |
| #endif |
| |
| /* Global constructors. */ |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Object"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_OBJECT, NJS_OBJECT_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Array"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_ARRAY, NJS_ARRAY_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("ArrayBuffer"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_ARRAY_BUFFER, |
| NJS_ARRAY_BUFFER_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("DataView"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_DATA_VIEW, |
| NJS_DATA_VIEW_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("TextDecoder"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_TEXT_DECODER, |
| NJS_TEXT_DECODER_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("TextEncoder"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_TEXT_ENCODER, |
| NJS_TEXT_ENCODER_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Buffer"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_BUFFER, NJS_BUFFER_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Uint8Array"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_UINT8_ARRAY, |
| NJS_UINT8ARRAY_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Uint16Array"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_UINT16_ARRAY, |
| NJS_UINT16ARRAY_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Uint32Array"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_UINT32_ARRAY, |
| NJS_UINT32ARRAY_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Int8Array"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_INT8_ARRAY, |
| NJS_INT8ARRAY_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Int16Array"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_INT16_ARRAY, |
| NJS_INT16ARRAY_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Int32Array"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_INT32_ARRAY, |
| NJS_INT32ARRAY_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Float32Array"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_FLOAT32_ARRAY, |
| NJS_FLOAT32ARRAY_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Float64Array"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_FLOAT64_ARRAY, |
| NJS_FLOAT64ARRAY_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_long_string("Uint8ClampedArray"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_UINT8_CLAMPED_ARRAY, |
| NJS_UINT8CLAMPEDARRAY_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Boolean"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_BOOLEAN, NJS_BOOLEAN_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Number"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_NUMBER, NJS_NUMBER_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Symbol"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_SYMBOL, NJS_SYMBOL_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("String"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_STRING, NJS_STRING_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Function"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_FUNCTION, NJS_FUNCTION_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("RegExp"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_REGEXP, NJS_REGEXP_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Date"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_DATE, NJS_DATE_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Promise"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_PROMISE, NJS_PROMISE_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("Error"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_ERROR, NJS_ERROR_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("EvalError"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_EVAL_ERROR, |
| NJS_EVAL_ERROR_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("InternalError"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_INTERNAL_ERROR, |
| NJS_INTERNAL_ERROR_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("RangeError"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_RANGE_ERROR, |
| NJS_RANGE_ERROR_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("ReferenceError"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_REF_ERROR, NJS_REF_ERROR_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("SyntaxError"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_SYNTAX_ERROR, |
| NJS_SYNTAX_ERROR_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("TypeError"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_TYPE_ERROR, |
| NJS_TYPE_ERROR_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("URIError"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_URI_ERROR, |
| NJS_URI_ERROR_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("MemoryError"), |
| .value = njs_prop_handler2(njs_top_level_constructor, |
| NJS_OBJ_TYPE_MEMORY_ERROR, |
| NJS_MEMORY_ERROR_HASH), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| }; |
| |
| |
| static const njs_object_init_t njs_global_this_init = { |
| njs_global_this_object_properties, |
| njs_nitems(njs_global_this_object_properties) |
| }; |
| |
| |
| static const njs_object_prop_t njs_njs_object_properties[] = |
| { |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG), |
| .value = njs_string("njs"), |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("version"), |
| .value = njs_string(NJS_VERSION), |
| .configurable = 1, |
| .enumerable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_string("dump"), |
| .value = njs_native_function(njs_dump_value, 0), |
| .configurable = 1, |
| }, |
| }; |
| |
| |
| static const njs_object_init_t njs_njs_object_init = { |
| njs_njs_object_properties, |
| njs_nitems(njs_njs_object_properties), |
| }; |
| |
| |
| static njs_int_t |
| njs_process_object_argv(njs_vm_t *vm, njs_object_prop_t *pr, |
| njs_value_t *process, njs_value_t *unused, njs_value_t *retval) |
| { |
| char **arg; |
| njs_int_t ret; |
| njs_uint_t i; |
| njs_array_t *argv; |
| njs_object_prop_t *prop; |
| njs_lvlhsh_query_t lhq; |
| |
| static const njs_value_t argv_string = njs_string("argv"); |
| |
| argv = njs_array_alloc(vm, 1, vm->options.argc, 0); |
| if (njs_slow_path(argv == NULL)) { |
| return NJS_ERROR; |
| } |
| |
| i = 0; |
| |
| for (arg = vm->options.argv; i < vm->options.argc; arg++) { |
| njs_string_set(vm, &argv->start[i++], (u_char *) *arg, |
| njs_strlen(*arg)); |
| } |
| |
| prop = njs_object_prop_alloc(vm, &argv_string, &njs_value_undefined, 1); |
| if (njs_slow_path(prop == NULL)) { |
| return NJS_ERROR; |
| } |
| |
| njs_set_array(&prop->value, argv); |
| |
| lhq.value = prop; |
| lhq.key_hash = NJS_ARGV_HASH; |
| lhq.key = njs_str_value("argv"); |
| lhq.replace = 1; |
| lhq.pool = vm->mem_pool; |
| lhq.proto = &njs_object_hash_proto; |
| |
| ret = njs_lvlhsh_insert(njs_object_hash(process), &lhq); |
| |
| if (njs_fast_path(ret == NJS_OK)) { |
| *retval = prop->value; |
| return NJS_OK; |
| } |
| |
| njs_internal_error(vm, "lvlhsh insert failed"); |
| |
| return NJS_ERROR; |
| } |
| |
| |
| static njs_int_t |
| njs_env_hash_init(njs_vm_t *vm, njs_lvlhsh_t *hash, char **environment) |
| { |
| char **ep; |
| u_char *val, *entry; |
| njs_int_t ret; |
| njs_object_prop_t *prop; |
| njs_lvlhsh_query_t lhq; |
| |
| lhq.replace = 0; |
| lhq.pool = vm->mem_pool; |
| lhq.proto = &njs_object_hash_proto; |
| |
| ep = environment; |
| |
| while (*ep != NULL) { |
| prop = njs_object_prop_alloc(vm, &njs_value_undefined, |
| &njs_value_undefined, 1); |
| if (njs_slow_path(prop == NULL)) { |
| return NJS_ERROR; |
| } |
| |
| entry = (u_char *) *ep++; |
| |
| val = njs_strchr(entry, '='); |
| if (njs_slow_path(val == NULL)) { |
| continue; |
| } |
| |
| ret = njs_string_set(vm, &prop->name, entry, val - entry); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| val++; |
| |
| ret = njs_string_set(vm, &prop->value, val, njs_strlen(val)); |
| if (njs_slow_path(ret != NJS_OK)) { |
| return NJS_ERROR; |
| } |
| |
| lhq.value = prop; |
| njs_string_get(&prop->name, &lhq.key); |
| lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); |
| |
| ret = njs_lvlhsh_insert(hash, &lhq); |
| if (njs_slow_path(ret != NJS_OK)) { |
| njs_internal_error(vm, "lvlhsh insert failed"); |
| return NJS_ERROR; |
| } |
| } |
| |
| return NJS_OK; |
| } |
| |
| |
| static njs_int_t |
| njs_process_object_env(njs_vm_t *vm, njs_object_prop_t *pr, |
| njs_value_t *process, njs_value_t *unused, njs_value_t *retval) |
| { |
| njs_int_t ret; |
| njs_object_t *env; |
| njs_object_prop_t *prop; |
| njs_lvlhsh_query_t lhq; |
| |
| static const njs_value_t env_string = njs_string("env"); |
| |
| env = njs_object_alloc(vm); |
| if (njs_slow_path(env == NULL)) { |
| return NJS_ERROR; |
| } |
| |
| env->shared_hash = vm->shared->env_hash; |
| |
| prop = njs_object_prop_alloc(vm, &env_string, &njs_value_undefined, 1); |
| if (njs_slow_path(prop == NULL)) { |
| return NJS_ERROR; |
| } |
| |
| njs_set_object(&prop->value, env); |
| |
| lhq.replace = 1; |
| lhq.pool = vm->mem_pool; |
| lhq.proto = &njs_object_hash_proto; |
| lhq.value = prop; |
| lhq.key = njs_str_value("env"); |
| lhq.key_hash = NJS_ENV_HASH; |
| |
| ret = njs_lvlhsh_insert(njs_object_hash(process), &lhq); |
| |
| if (njs_fast_path(ret == NJS_OK)) { |
| *retval = prop->value; |
| return NJS_OK; |
| } |
| |
| njs_internal_error(vm, "lvlhsh insert failed"); |
| |
| return NJS_ERROR; |
| } |
| |
| |
| static njs_int_t |
| njs_process_object_pid(njs_vm_t *vm, njs_object_prop_t *prop, |
| njs_value_t *unused, njs_value_t *unused2, njs_value_t *retval) |
| { |
| njs_set_number(retval, getpid()); |
| |
| return NJS_OK; |
| } |
| |
| |
| static njs_int_t |
| njs_process_object_ppid(njs_vm_t *vm, njs_object_prop_t *prop, |
| njs_value_t *unused, njs_value_t *unused2, njs_value_t *retval) |
| { |
| njs_set_number(retval, getppid()); |
| |
| return NJS_OK; |
| } |
| |
| |
| static const njs_object_prop_t njs_process_object_properties[] = |
| { |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG), |
| .value = njs_string("process"), |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("argv"), |
| .value = njs_prop_handler(njs_process_object_argv), |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("env"), |
| .value = njs_prop_handler(njs_process_object_env), |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("pid"), |
| .value = njs_prop_handler(njs_process_object_pid), |
| }, |
| |
| { |
| .type = NJS_PROPERTY_HANDLER, |
| .name = njs_string("ppid"), |
| .value = njs_prop_handler(njs_process_object_ppid), |
| }, |
| |
| }; |
| |
| |
| static const njs_object_init_t njs_process_object_init = { |
| njs_process_object_properties, |
| njs_nitems(njs_process_object_properties), |
| }; |
| |
| |
| #if (NJS_TEST262) |
| |
| static njs_int_t |
| njs_262_detach_array_buffer(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, |
| njs_index_t unused) |
| { |
| njs_value_t *value; |
| njs_array_buffer_t *buffer; |
| |
| value = njs_arg(args, nargs, 1); |
| if (njs_slow_path(!njs_is_array_buffer(value))) { |
| njs_type_error(vm, "\"this\" is not an ArrayBuffer"); |
| return NJS_ERROR; |
| } |
| |
| buffer = njs_array_buffer(value); |
| buffer->u.data = NULL; |
| buffer->size = 0; |
| |
| njs_set_null(&vm->retval); |
| |
| return NJS_OK; |
| } |
| |
| static const njs_object_prop_t njs_262_object_properties[] = |
| { |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG), |
| .value = njs_string("$262"), |
| .configurable = 1, |
| }, |
| |
| { |
| .type = NJS_PROPERTY, |
| .name = njs_long_string("detachArrayBuffer"), |
| .value = njs_native_function(njs_262_detach_array_buffer, 2), |
| .writable = 1, |
| .configurable = 1, |
| }, |
| }; |
| |
| |
| static const njs_object_init_t njs_262_object_init = { |
| njs_262_object_properties, |
| njs_nitems(njs_262_object_properties), |
| }; |
| |
| #endif |