From: Alexander Borisov Date: Wed, 17 Apr 2019 14:27:14 +0000 (+0300) Subject: Added two new function for working with enumerate value. X-Git-Tag: 0.3.2~67 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=3ca688b765d246baae929e3e50358cb3727c9ea5;p=njs.git Added two new function for working with enumerate value. New functions njs_value_enumerate() and njs_value_own_enumerate(). Changed function njs_object_enumerate() for working only with object. --- diff --git a/njs/njs_json.c b/njs/njs_json.c index 6f432b07..e94d506a 100644 --- a/njs/njs_json.c +++ b/njs/njs_json.c @@ -1127,7 +1127,7 @@ njs_json_push_parse_state(njs_vm_t *vm, njs_json_parse_t *parse, } else { state->type = NJS_JSON_OBJECT_START; state->prop_value = NULL; - state->keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS, 0); + state->keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, 0); if (state->keys == NULL) { return NULL; } @@ -1705,7 +1705,8 @@ njs_json_push_stringify_state(njs_vm_t *vm, njs_json_stringify_t *stringify, state->keys = njs_extern_keys_array(vm, value->external.proto); } else { - state->keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS, 0); + state->keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, + 0); } if (state->keys == NULL) { diff --git a/njs/njs_object.c b/njs/njs_object.c index 0b48996c..6c8331eb 100644 --- a/njs/njs_object.c +++ b/njs/njs_object.c @@ -27,6 +27,25 @@ static njs_ret_t njs_object_query_prop_handler(njs_property_query_t *pq, static njs_ret_t njs_define_property(njs_vm_t *vm, njs_value_t *object, const njs_value_t *name, const njs_object_t *descriptor); +static njs_object_prop_t * njs_object_exist_in_proto(const njs_object_t *begin, + const njs_object_t *end, nxt_lvlhsh_query_t *lhq); +static uint32_t njs_object_enumerate_array_length(const njs_object_t *object); +static uint32_t njs_object_enumerate_string_length(const njs_object_t *object); +static uint32_t njs_object_enumerate_object_length(const njs_object_t *object, + nxt_bool_t all); +static uint32_t njs_object_own_enumerate_object_length( + const njs_object_t *object, const njs_object_t *parent, nxt_bool_t all); +static njs_ret_t njs_object_enumerate_array(njs_vm_t *vm, + const njs_array_t *array, njs_array_t *items, njs_object_enum_t kind); +static njs_ret_t njs_object_enumerate_string(njs_vm_t *vm, + const njs_value_t *value, njs_array_t *items, njs_object_enum_t kind); +static njs_ret_t njs_object_enumerate_object(njs_vm_t *vm, + const njs_object_t *object, njs_array_t *items, njs_object_enum_t kind, + nxt_bool_t all); +static njs_ret_t njs_object_own_enumerate_object(njs_vm_t *vm, + const njs_object_t *object, const njs_object_t *parent, njs_array_t *items, + njs_object_enum_t kind, nxt_bool_t all); + nxt_noinline njs_object_t * njs_object_alloc(njs_vm_t *vm) @@ -886,7 +905,7 @@ njs_object_keys(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, return NXT_ERROR; } - keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS, 0); + keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, 0); if (keys == NULL) { return NXT_ERROR; } @@ -915,7 +934,7 @@ njs_object_values(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, return NXT_ERROR; } - array = njs_object_enumerate(vm, value, NJS_ENUM_VALUES, 0); + array = njs_value_own_enumerate(vm, value, NJS_ENUM_VALUES, 0); if (array == NULL) { return NXT_ERROR; } @@ -944,7 +963,7 @@ njs_object_entries(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, return NXT_ERROR; } - array = njs_object_enumerate(vm, value, NJS_ENUM_BOTH, 0); + array = njs_value_own_enumerate(vm, value, NJS_ENUM_BOTH, 0); if (array == NULL) { return NXT_ERROR; } @@ -957,69 +976,306 @@ njs_object_entries(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, } -njs_array_t * -njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value, - njs_object_enum_t kind, nxt_bool_t all) +static njs_object_prop_t * +njs_object_exist_in_proto(const njs_object_t *begin, const njs_object_t *end, + nxt_lvlhsh_query_t *lhq) { - u_char *dst; - uint32_t i, length, size, items_length, properties; - njs_value_t *string, *item; - njs_array_t *items, *array, *entry; - nxt_lvlhsh_t *hash; - const u_char *src, *end; - njs_object_t *object; + nxt_int_t ret; njs_object_prop_t *prop; - njs_string_prop_t string_prop; - nxt_lvlhsh_each_t lhe; - array = NULL; - length = 0; - object = NULL; - items_length = 0; + lhq->proto = &njs_object_hash_proto; - switch (value->type) { - case NJS_ARRAY: - array = value->data.u.array; - length = array->length; + while (begin != end) { + ret = nxt_lvlhsh_find(&begin->hash, lhq); - for (i = 0; i < length; i++) { - if (njs_is_valid(&array->start[i])) { - items_length++; + if (nxt_fast_path(ret == NXT_OK)) { + prop = lhq->value; + + if (prop->type == NJS_WHITEOUT) { + goto next; } + + return lhq->value; } + ret = nxt_lvlhsh_find(&begin->shared_hash, lhq); + + if (nxt_fast_path(ret == NXT_OK)) { + return lhq->value; + } + +next: + + begin = begin->__proto__; + } + + return NULL; +} + + +nxt_inline uint32_t +njs_object_enumerate_length(const njs_object_t *object, nxt_bool_t all) +{ + uint32_t length; + + length = njs_object_enumerate_object_length(object, all); + + switch (object->type) { + case NJS_ARRAY: + length += njs_object_enumerate_array_length(object); break; - case NJS_STRING: case NJS_OBJECT_STRING: - if (value->type == NJS_OBJECT_STRING) { - string = &value->data.u.object_value->value; + length += njs_object_enumerate_string_length(object); + break; - } else { - string = (njs_value_t *) value; - object = &vm->string_object; - } + default: + break; + } - length = njs_string_prop(&string_prop, string); - items_length += length; + return length; +} + +nxt_inline uint32_t +njs_object_own_enumerate_length(const njs_object_t *object, + const njs_object_t *parent, nxt_bool_t all) +{ + uint32_t length; + + length = njs_object_own_enumerate_object_length(object, parent, all); + + switch (object->type) { + case NJS_ARRAY: + length += njs_object_enumerate_array_length(object); + break; + + case NJS_OBJECT_STRING: + length += njs_object_enumerate_string_length(object); break; default: break; } - /* GCC 4 and Clang 3 complain about uninitialized hash. */ - hash = NULL; - properties = 0; + return length; +} - if (nxt_fast_path(njs_is_object(value))) { - object = value->data.u.object; + +nxt_inline njs_ret_t +njs_object_enumerate_value(njs_vm_t *vm, const njs_object_t *object, + njs_array_t *items, njs_object_enum_t kind, nxt_bool_t all) +{ + njs_ret_t ret; + njs_object_value_t *obj_val; + + switch (object->type) { + case NJS_ARRAY: + ret = njs_object_enumerate_array(vm, (njs_array_t *) object, items, + kind); + break; + + case NJS_OBJECT_STRING: + obj_val = (njs_object_value_t *) object; + + ret = njs_object_enumerate_string(vm, &obj_val->value, items, kind); + break; + + default: + goto object; + } + + if (nxt_slow_path(ret != NJS_OK)) { + return NJS_ERROR; } - if (object != NULL) { +object: + + ret = njs_object_enumerate_object(vm, object, items, kind, all); + if (nxt_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + return NJS_OK; +} + + +nxt_inline njs_ret_t +njs_object_own_enumerate_value(njs_vm_t *vm, const njs_object_t *object, + const njs_object_t *parent, njs_array_t *items, njs_object_enum_t kind, + nxt_bool_t all) +{ + njs_ret_t ret; + njs_object_value_t *obj_val; + + switch (object->type) { + case NJS_ARRAY: + ret = njs_object_enumerate_array(vm, (njs_array_t *) object, items, + kind); + break; + + case NJS_OBJECT_STRING: + obj_val = (njs_object_value_t *) object; + + ret = njs_object_enumerate_string(vm, &obj_val->value, items, kind); + break; + + default: + goto object; + } + + if (nxt_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + +object: + + ret = njs_object_own_enumerate_object(vm, object, parent, items, kind, all); + if (nxt_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + return NJS_OK; +} + + +njs_array_t * +njs_object_enumerate(njs_vm_t *vm, const njs_object_t *object, + njs_object_enum_t kind, nxt_bool_t all) +{ + uint32_t length; + njs_ret_t ret; + njs_array_t *items; + + length = njs_object_enumerate_length(object, all); + + items = njs_array_alloc(vm, length, NJS_ARRAY_SPARE); + if (nxt_slow_path(items == NULL)) { + return NULL; + } + + ret = njs_object_enumerate_value(vm, object, items, kind, all); + if (nxt_slow_path(ret != NJS_OK)) { + return NULL; + } + + items->start -= items->length; + + return items; +} + + +njs_array_t * +njs_object_own_enumerate(njs_vm_t *vm, const njs_object_t *object, + njs_object_enum_t kind, nxt_bool_t all) +{ + uint32_t length; + njs_ret_t ret; + njs_array_t *items; + + length = njs_object_own_enumerate_length(object, object, all); + + items = njs_array_alloc(vm, length, NJS_ARRAY_SPARE); + if (nxt_slow_path(items == NULL)) { + return NULL; + } + + ret = njs_object_own_enumerate_value(vm, object, object, items, kind, all); + if (nxt_slow_path(ret != NJS_OK)) { + return NULL; + } + + items->start -= items->length; + + return items; +} + + +static uint32_t +njs_object_enumerate_array_length(const njs_object_t *object) +{ + uint32_t i, length; + njs_array_t *array; + + length = 0; + array = (njs_array_t *) object; + + for (i = 0; i < array->length; i++) { + if (njs_is_valid(&array->start[i])) { + length++; + } + } + + return length; +} + + +static uint32_t +njs_object_enumerate_string_length(const njs_object_t *object) +{ + njs_object_value_t *obj_val; + + obj_val = (njs_object_value_t *) object; + + return njs_string_length(&obj_val->value); +} + + +static uint32_t +njs_object_enumerate_object_length(const njs_object_t *object, nxt_bool_t all) +{ + uint32_t length; + const njs_object_t *ptr; + + length = njs_object_own_enumerate_object_length(object, object, all); + + for (ptr = object->__proto__; ptr != NULL; ptr = ptr->__proto__) { + + length += njs_object_own_enumerate_length(ptr, object, all); + } + + return length; +} + + +static uint32_t +njs_object_own_enumerate_object_length(const njs_object_t *object, + const njs_object_t *parent, nxt_bool_t all) +{ + uint32_t length; + nxt_int_t ret; + nxt_lvlhsh_each_t lhe; + njs_object_prop_t *prop, *ext_prop; + nxt_lvlhsh_query_t lhq; + const nxt_lvlhsh_t *hash; + + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + hash = &object->hash; + + length = 0; + + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); + + if (prop == NULL) { + break; + } + + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); + + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); + + if (ext_prop == NULL && prop->type != NJS_WHITEOUT + && (prop->enumerable || all)) + { + length++; + } + } + + if (nxt_slow_path(all)) { nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - hash = &object->hash; + hash = &object->shared_hash; for ( ;; ) { prop = nxt_lvlhsh_each(hash, &lhe); @@ -1028,195 +1284,278 @@ njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value, break; } - if (prop->type != NJS_WHITEOUT && (prop->enumerable || all)) { - properties++; - } - } + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); - if (nxt_slow_path(all)) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - hash = &object->shared_hash; + lhq.proto = &njs_object_hash_proto; + ret = nxt_lvlhsh_find(&object->hash, &lhq); - for ( ;; ) { - prop = nxt_lvlhsh_each(hash, &lhe); + if (ret != NXT_OK) { + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); - if (prop == NULL) { - break; + if (ext_prop == NULL) { + length++; } - - properties++; } } - - items_length += properties; } - items = njs_array_alloc(vm, items_length, NJS_ARRAY_SPARE); - if (nxt_slow_path(items == NULL)) { - return NULL; - } + return length; +} + + +static njs_ret_t +njs_object_enumerate_array(njs_vm_t *vm, const njs_array_t *array, + njs_array_t *items, njs_object_enum_t kind) +{ + uint32_t i; + njs_value_t *item; + njs_array_t *entry; item = items->start; - if (array != NULL) { + switch (kind) { + case NJS_ENUM_KEYS: + for (i = 0; i < array->length; i++) { + if (njs_is_valid(&array->start[i])) { + njs_uint32_to_string(item++, i); + } + } - switch (kind) { - case NJS_ENUM_KEYS: - for (i = 0; i < length; i++) { - if (njs_is_valid(&array->start[i])) { - njs_uint32_to_string(item++, i); - } + break; + + case NJS_ENUM_VALUES: + for (i = 0; i < array->length; i++) { + if (njs_is_valid(&array->start[i])) { + /* GC: retain. */ + *item++ = array->start[i]; } + } - break; + break; + + case NJS_ENUM_BOTH: + for (i = 0; i < array->length; i++) { + if (njs_is_valid(&array->start[i])) { - case NJS_ENUM_VALUES: - for (i = 0; i < length; i++) { - if (njs_is_valid(&array->start[i])) { - /* GC: retain. */ - *item++ = array->start[i]; + entry = njs_array_alloc(vm, 2, 0); + if (nxt_slow_path(entry == NULL)) { + return NJS_ERROR; } + + njs_uint32_to_string(&entry->start[0], i); + + /* GC: retain. */ + entry->start[1] = array->start[i]; + + item->data.u.array = entry; + item->type = NJS_ARRAY; + item->data.truth = 1; + + item++; } + } - break; + break; + } - case NJS_ENUM_BOTH: - for (i = 0; i < length; i++) { - if (njs_is_valid(&array->start[i])) { - entry = njs_array_alloc(vm, 2, 0); - if (nxt_slow_path(entry == NULL)) { - return NULL; - } + items->start = item; - njs_uint32_to_string(&entry->start[0], i); + return NJS_OK; +} - /* GC: retain. */ - entry->start[1] = array->start[i]; - item->data.u.array = entry; - item->type = NJS_ARRAY; - item->data.truth = 1; +static njs_ret_t +njs_object_enumerate_string(njs_vm_t *vm, const njs_value_t *value, + njs_array_t *items, njs_object_enum_t kind) +{ + u_char *begin; + uint32_t i, len, size; + njs_value_t *item, *string; + njs_array_t *entry; + const u_char *src, *end; + njs_string_prop_t str_prop; - item++; - } - } + item = items->start; + len = (uint32_t) njs_string_prop(&str_prop, value); - break; + switch (kind) { + case NJS_ENUM_KEYS: + for (i = 0; i < len; i++) { + njs_uint32_to_string(item++, i); } - } else if (length != 0) { + break; - switch (kind) { - case NJS_ENUM_KEYS: - for (i = 0; i < length; i++) { - njs_uint32_to_string(item++, i); + case NJS_ENUM_VALUES: + if (str_prop.size == (size_t) len) { + /* Byte or ASCII string. */ + + for (i = 0; i < len; i++) { + begin = njs_string_short_start(item); + *begin = str_prop.start[i]; + + njs_string_short_set(item, 1, 1); + + item++; } - break; + } else { + /* UTF-8 string. */ + + src = str_prop.start; + end = src + str_prop.size; + + do { + begin = (u_char *) src; + nxt_utf8_copy(njs_string_short_start(item), &src, end); + size = (uint32_t) (src - begin); + + njs_string_short_set(item, size, 1); + + item++; + + } while (src != end); + } - case NJS_ENUM_VALUES: - if (string_prop.size == (size_t) length) { - /* Byte or ASCII string. */ + break; - for (i = 0; i < length; i++) { - dst = njs_string_short_start(item); - dst[0] = string_prop.start[i]; + case NJS_ENUM_BOTH: + if (str_prop.size == (size_t) len) { + /* Byte or ASCII string. */ - njs_string_short_set(item, 1, 1); + for (i = 0; i < len; i++) { - item++; + entry = njs_array_alloc(vm, 2, 0); + if (nxt_slow_path(entry == NULL)) { + return NJS_ERROR; } - } else { - /* UTF-8 string. */ + njs_uint32_to_string(&entry->start[0], i); - src = string_prop.start; - end = src + string_prop.size; + string = &entry->start[1]; - do { - dst = njs_string_short_start(item); - dst = nxt_utf8_copy(dst, &src, end); - size = dst - njs_string_short_start(value); + begin = njs_string_short_start(string); + *begin = str_prop.start[i]; - njs_string_short_set(item, size, 1); + njs_string_short_set(string, 1, 1); - item++; + item->data.u.array = entry; + item->type = NJS_ARRAY; + item->data.truth = 1; - } while (src != end); + item++; } - break; + } else { + /* UTF-8 string. */ - case NJS_ENUM_BOTH: - if (string_prop.size == (size_t) length) { - /* Byte or ASCII string. */ + src = str_prop.start; + end = src + str_prop.size; + i = 0; - for (i = 0; i < length; i++) { - entry = njs_array_alloc(vm, 2, 0); - if (nxt_slow_path(entry == NULL)) { - return NULL; - } + do { + entry = njs_array_alloc(vm, 2, 0); + if (nxt_slow_path(entry == NULL)) { + return NJS_ERROR; + } - njs_uint32_to_string(&entry->start[0], i); + njs_uint32_to_string(&entry->start[0], i++); - string = &entry->start[1]; + string = &entry->start[1]; - dst = njs_string_short_start(string); - dst[0] = string_prop.start[i]; + begin = (u_char *) src; + nxt_utf8_copy(njs_string_short_start(string), &src, end); + size = (uint32_t) (src - begin); - njs_string_short_set(string, 1, 1); + njs_string_short_set(string, size, 1); - item->data.u.array = entry; - item->type = NJS_ARRAY; - item->data.truth = 1; + item->data.u.array = entry; + item->type = NJS_ARRAY; + item->data.truth = 1; - item++; - } + item++; - } else { - /* UTF-8 string. */ + } while (src != end); + } - src = string_prop.start; - end = src + string_prop.size; - i = 0; + break; + } - do { - entry = njs_array_alloc(vm, 2, 0); - if (nxt_slow_path(entry == NULL)) { - return NULL; - } + items->start = item; + + return NJS_OK; +} + + +static njs_ret_t +njs_object_enumerate_object(njs_vm_t *vm, const njs_object_t *object, + njs_array_t *items, njs_object_enum_t kind, nxt_bool_t all) +{ + njs_ret_t ret; + const njs_object_t *ptr; + + ret = njs_object_own_enumerate_object(vm, object, object, items, kind, all); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + for (ptr = object->__proto__; ptr != NULL; ptr = ptr->__proto__) { - njs_uint32_to_string(&entry->start[0], i++); + ret = njs_object_own_enumerate_value(vm, ptr, object, items, kind, + all); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + } - string = &entry->start[1]; + return NJS_OK; +} - dst = njs_string_short_start(string); - dst = nxt_utf8_copy(dst, &src, end); - size = dst - njs_string_short_start(value); - njs_string_short_set(string, size, 1); +static njs_ret_t +njs_object_own_enumerate_object(njs_vm_t *vm, const njs_object_t *object, + const njs_object_t *parent, njs_array_t *items, njs_object_enum_t kind, + nxt_bool_t all) +{ + nxt_int_t ret; + njs_value_t *item; + njs_array_t *entry; + nxt_lvlhsh_each_t lhe; + njs_object_prop_t *prop, *ext_prop; + nxt_lvlhsh_query_t lhq; + const nxt_lvlhsh_t *hash; + + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - item->data.u.array = entry; - item->type = NJS_ARRAY; - item->data.truth = 1; + item = items->start; + hash = &object->hash; - item++; + switch (kind) { + case NJS_ENUM_KEYS: + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); - } while (src != end); + if (prop == NULL) { + break; } - break; - } - } + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); - if (nxt_fast_path(properties != 0)) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); - hash = &object->hash; + if (ext_prop == NULL && prop->type != NJS_WHITEOUT + && (prop->enumerable || all)) + { + njs_string_copy(item++, &prop->name); + } + } - switch (kind) { + if (nxt_slow_path(all)) { + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + hash = &object->shared_hash; - case NJS_ENUM_KEYS: for ( ;; ) { prop = nxt_lvlhsh_each(hash, &lhe); @@ -1224,29 +1563,49 @@ njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value, break; } - if (prop->type != NJS_WHITEOUT && (prop->enumerable || all)) { - njs_string_copy(item++, &prop->name); + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); + + lhq.proto = &njs_object_hash_proto; + ret = nxt_lvlhsh_find(&object->hash, &lhq); + + if (ret != NXT_OK) { + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); + + if (ext_prop == NULL) { + njs_string_copy(item++, &prop->name); + } } } + } + + break; - if (nxt_slow_path(all)) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - hash = &object->shared_hash; + case NJS_ENUM_VALUES: + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); - for ( ;; ) { - prop = nxt_lvlhsh_each(hash, &lhe); + if (prop == NULL) { + break; + } - if (prop == NULL) { - break; - } + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); - njs_string_copy(item++, &prop->name); - } + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); + + if (ext_prop == NULL && prop->type != NJS_WHITEOUT + && (prop->enumerable || all)) + { + /* GC: retain. */ + *item++ = prop->value; } + } - break; + if (nxt_slow_path(all)) { + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + hash = &object->shared_hash; - case NJS_ENUM_VALUES: for ( ;; ) { prop = nxt_lvlhsh_each(hash, &lhe); @@ -1254,15 +1613,62 @@ njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value, break; } - if (prop->type != NJS_WHITEOUT && prop->enumerable) { - /* GC: retain. */ - *item++ = prop->value; + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); + + lhq.proto = &njs_object_hash_proto; + ret = nxt_lvlhsh_find(&object->hash, &lhq); + + if (ret != NXT_OK) { + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); + + if (ext_prop == NULL) { + *item++ = prop->value; + } } } + } - break; + break; + + case NJS_ENUM_BOTH: + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); + + if (prop == NULL) { + break; + } + + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); + + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); + + if (ext_prop == NULL && prop->type != NJS_WHITEOUT + && (prop->enumerable || all)) + { + entry = njs_array_alloc(vm, 2, 0); + if (nxt_slow_path(entry == NULL)) { + return NJS_ERROR; + } + + njs_string_copy(&entry->start[0], &prop->name); + + /* GC: retain. */ + entry->start[1] = prop->value; + + item->data.u.array = entry; + item->type = NJS_ARRAY; + item->data.truth = 1; + + item++; + } + } + + if (nxt_slow_path(all)) { + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + hash = &object->shared_hash; - case NJS_ENUM_BOTH: for ( ;; ) { prop = nxt_lvlhsh_each(hash, &lhe); @@ -1270,30 +1676,42 @@ njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value, break; } - if (prop->type != NJS_WHITEOUT && prop->enumerable) { - entry = njs_array_alloc(vm, 2, 0); - if (nxt_slow_path(entry == NULL)) { - return NULL; - } + lhq.key_hash = lhe.key_hash; + njs_string_get(&prop->name, &lhq.key); + + lhq.proto = &njs_object_hash_proto; + ret = nxt_lvlhsh_find(&object->hash, &lhq); + + if (ret != NXT_OK) { + ext_prop = njs_object_exist_in_proto(parent, object, &lhq); - njs_string_copy(&entry->start[0], &prop->name); + if (ext_prop == NULL) { + entry = njs_array_alloc(vm, 2, 0); + if (nxt_slow_path(entry == NULL)) { + return NJS_ERROR; + } - /* GC: retain. */ - entry->start[1] = prop->value; + njs_string_copy(&entry->start[0], &prop->name); - item->data.u.array = entry; - item->type = NJS_ARRAY; - item->data.truth = 1; + /* GC: retain. */ + entry->start[1] = prop->value; - item++; + item->data.u.array = entry; + item->type = NJS_ARRAY; + item->data.truth = 1; + + item++; + } } } - - break; } + + break; } - return items; + items->start = item; + + return NJS_OK; } @@ -1799,7 +2217,7 @@ njs_object_get_own_property_descriptors(njs_vm_t *vm, njs_value_t *args, return NXT_ERROR; } - names = njs_object_enumerate(vm, value, NJS_ENUM_KEYS, 1); + names = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, 1); if (nxt_slow_path(names == NULL)) { return NXT_ERROR; } @@ -1862,7 +2280,7 @@ njs_object_get_own_property_names(njs_vm_t *vm, njs_value_t *args, return NXT_ERROR; } - names = njs_object_enumerate(vm, value, NJS_ENUM_KEYS, 1); + names = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, 1); if (names == NULL) { return NXT_ERROR; } diff --git a/njs/njs_object.h b/njs/njs_object.h index 9f7b138f..d1ab7802 100644 --- a/njs/njs_object.h +++ b/njs/njs_object.h @@ -17,13 +17,6 @@ typedef enum { } njs_object_property_type_t; -typedef enum { - NJS_ENUM_KEYS, - NJS_ENUM_VALUES, - NJS_ENUM_BOTH, -} njs_object_enum_t; - - /* * Attributes are generally used as Boolean values. * The UNSET value is used internally only by njs_define_property(). @@ -86,7 +79,9 @@ njs_object_t *njs_object_alloc(njs_vm_t *vm); njs_object_t *njs_object_value_copy(njs_vm_t *vm, njs_value_t *value); njs_object_t *njs_object_value_alloc(njs_vm_t *vm, const njs_value_t *value, nxt_uint_t type); -njs_array_t *njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value, +njs_array_t *njs_object_enumerate(njs_vm_t *vm, const njs_object_t *object, + njs_object_enum_t kind, nxt_bool_t all); +njs_array_t *njs_object_own_enumerate(njs_vm_t *vm, const njs_object_t *object, njs_object_enum_t kind, nxt_bool_t all); njs_ret_t njs_value_property(njs_vm_t *vm, const njs_value_t *value, const njs_value_t *property, njs_value_t *retval); diff --git a/njs/njs_vm.c b/njs/njs_vm.c index f4565d01..a10ca42e 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -3636,3 +3636,45 @@ njs_lvlhsh_free(void *data, void *p, size_t size) { nxt_mp_free(data, p); } + + +njs_array_t * +njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value, + njs_object_enum_t kind, nxt_bool_t all) +{ + njs_object_value_t obj_val; + + if (njs_is_object(value)) { + return njs_object_enumerate(vm, value->data.u.object, kind, all); + } + + if (value->type != NJS_STRING) { + return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); + } + + obj_val.object = vm->string_object; + obj_val.value = *value; + + return njs_object_enumerate(vm, (njs_object_t *) &obj_val, kind, all); +} + + +njs_array_t * +njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value, + njs_object_enum_t kind, nxt_bool_t all) +{ + njs_object_value_t obj_val; + + if (njs_is_object(value)) { + return njs_object_own_enumerate(vm, value->data.u.object, kind, all); + } + + if (value->type != NJS_STRING) { + return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); + } + + obj_val.object = vm->string_object; + obj_val.value = *value; + + return njs_object_own_enumerate(vm, (njs_object_t *) &obj_val, kind, all); +} diff --git a/njs/njs_vm.h b/njs/njs_vm.h index 52916ace..3c8996c9 100644 --- a/njs/njs_vm.h +++ b/njs/njs_vm.h @@ -1137,6 +1137,13 @@ struct njs_vm_shared_s { }; +typedef enum { + NJS_ENUM_KEYS, + NJS_ENUM_VALUES, + NJS_ENUM_BOTH, +} njs_object_enum_t; + + nxt_int_t njs_vmcode_interpreter(njs_vm_t *vm); void njs_value_retain(njs_value_t *value); @@ -1295,6 +1302,10 @@ nxt_array_t *njs_vm_backtrace(njs_vm_t *vm); void *njs_lvlhsh_alloc(void *data, size_t size, nxt_uint_t nalloc); void njs_lvlhsh_free(void *data, void *p, size_t size); +njs_array_t * njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value, + njs_object_enum_t kind, nxt_bool_t all); +njs_array_t * njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value, + njs_object_enum_t kind, nxt_bool_t all); extern const njs_value_t njs_value_undefined; extern const njs_value_t njs_value_null;