[njs] Added Symbol support for builtin operations.
Dmitry Volyntsev
xeioex at nginx.com
Thu Nov 21 17:57:34 UTC 2019
details: https://hg.nginx.org/njs/rev/10a19a2e1d4f
branches:
changeset: 1248:10a19a2e1d4f
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Thu Nov 21 20:56:06 2019 +0300
description:
Added Symbol support for builtin operations.
1) object property get/set, object literals.
2) Added Object.getOwnPropertySymbols().
3) Extended to support Symbol: Object.getOwnPropertyNames(),
Object.keys(), Object.defineProperty(), Object.defineProperties(),
Object.getOwnPropertyDescriptor(),
Object.getOwnPropertyDescriptors().
diffstat:
src/njs_array.c | 7 +-
src/njs_date.c | 4 +-
src/njs_error.c | 2 +-
src/njs_function.c | 2 +-
src/njs_json.c | 16 +-
src/njs_object.c | 339 ++++++++++++++++++++++++++++------------------
src/njs_object.h | 170 ++++++++++++++++++++---
src/njs_object_prop.c | 19 ++-
src/njs_value.c | 38 +++-
src/njs_value.h | 14 +-
src/njs_vmcode.c | 14 +-
src/test/njs_unit_test.c | 49 ++++++
12 files changed, 482 insertions(+), 192 deletions(-)
diffs (truncated from 1329 to 1000 lines):
diff -r 263c75a40999 -r 10a19a2e1d4f src/njs_array.c
--- a/src/njs_array.c Tue Nov 19 20:45:22 2019 +0300
+++ b/src/njs_array.c Thu Nov 21 20:56:06 2019 +0300
@@ -1106,8 +1106,10 @@ njs_array_prototype_to_string(njs_vm_t *
njs_value_t value;
njs_lvlhsh_query_t lhq;
+ static const njs_value_t join_string = njs_string("join");
+
if (njs_is_object(&args[0])) {
- njs_object_property_init(&lhq, "join", NJS_JOIN_HASH);
+ njs_object_property_init(&lhq, &join_string, NJS_JOIN_HASH);
ret = njs_object_property(vm, &args[0], &lhq, &value);
@@ -1322,7 +1324,8 @@ njs_object_indexes(njs_vm_t *vm, njs_val
uint32_t i;
njs_array_t *keys;
- keys = njs_value_own_enumerate(vm, object, NJS_ENUM_KEYS, 0);
+ keys = njs_value_own_enumerate(vm, object, NJS_ENUM_KEYS, NJS_ENUM_STRING,
+ 0);
if (njs_slow_path(keys == NULL)) {
return NULL;
}
diff -r 263c75a40999 -r 10a19a2e1d4f src/njs_date.c
--- a/src/njs_date.c Tue Nov 19 20:45:22 2019 +0300
+++ b/src/njs_date.c Thu Nov 21 20:56:06 2019 +0300
@@ -1403,8 +1403,10 @@ njs_date_prototype_to_json(njs_vm_t *vm,
njs_value_t value;
njs_lvlhsh_query_t lhq;
+ static const njs_value_t to_iso_string = njs_string("toISOString");
+
if (njs_is_object(&args[0])) {
- njs_object_property_init(&lhq, "toISOString", NJS_TO_ISO_STRING_HASH);
+ njs_object_property_init(&lhq, &to_iso_string, NJS_TO_ISO_STRING_HASH);
ret = njs_object_property(vm, &args[0], &lhq, &value);
diff -r 263c75a40999 -r 10a19a2e1d4f src/njs_error.c
--- a/src/njs_error.c Tue Nov 19 20:45:22 2019 +0300
+++ b/src/njs_error.c Thu Nov 21 20:56:06 2019 +0300
@@ -630,7 +630,7 @@ njs_error_to_string(njs_vm_t *vm, njs_va
static const njs_value_t default_name = njs_string("Error");
- njs_object_property_init(&lhq, "name", NJS_NAME_HASH);
+ njs_object_property_init(&lhq, &njs_string_name, NJS_NAME_HASH);
ret = njs_object_property(vm, error, &lhq, &value1);
diff -r 263c75a40999 -r 10a19a2e1d4f src/njs_function.c
--- a/src/njs_function.c Tue Nov 19 20:45:22 2019 +0300
+++ b/src/njs_function.c Thu Nov 21 20:56:06 2019 +0300
@@ -1160,7 +1160,7 @@ njs_function_prototype_bind(njs_vm_t *vm
function->u.bound_target = njs_function(&args[0]);
- njs_object_property_init(&lhq, "name", NJS_NAME_HASH);
+ njs_object_property_init(&lhq, &njs_string_name, NJS_NAME_HASH);
ret = njs_object_property(vm, &args[0], &lhq, &name);
if (njs_slow_path(ret == NJS_ERROR)) {
diff -r 263c75a40999 -r 10a19a2e1d4f src/njs_json.c
--- a/src/njs_json.c Tue Nov 19 20:45:22 2019 +0300
+++ b/src/njs_json.c Thu Nov 21 20:56:06 2019 +0300
@@ -68,6 +68,7 @@ typedef struct {
njs_value_t replacer;
njs_str_t space;
u_char space_buf[16];
+ njs_object_enum_type_t keys_type;
} njs_json_stringify_t;
@@ -227,6 +228,7 @@ njs_json_stringify(njs_vm_t *vm, njs_val
stringify->depth = 0;
stringify->nodes = NULL;
stringify->last = NULL;
+ stringify->keys_type = NJS_ENUM_STRING;
replacer = njs_arg(args, nargs, 2);
@@ -867,7 +869,8 @@ njs_json_push_parse_state(njs_vm_t *vm,
} else {
state->type = NJS_JSON_OBJECT;
state->prop = NULL;
- state->keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, 0);
+ state->keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS,
+ NJS_ENUM_STRING, 0);
if (state->keys == NULL) {
return NULL;
}
@@ -1094,7 +1097,7 @@ njs_json_push_stringify_state(njs_vm_t *
} else {
state->keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS,
- 0);
+ stringify->keys_type, 0);
}
if (njs_slow_path(state->keys == NULL)) {
@@ -1362,7 +1365,9 @@ njs_object_to_json_function(njs_vm_t *vm
njs_value_t retval;
njs_lvlhsh_query_t lhq;
- njs_object_property_init(&lhq, "toJSON", NJS_TO_JSON_HASH);
+ static const njs_value_t to_json_string = njs_string("toJSON");
+
+ njs_object_property_init(&lhq, &to_json_string, NJS_TO_JSON_HASH);
ret = njs_object_property(vm, value, &lhq, &retval);
@@ -2179,6 +2184,7 @@ njs_vm_value_dump(njs_vm_t *vm, njs_str_
stringify->nodes = NULL;
stringify->last = NULL;
njs_set_undefined(&stringify->replacer);
+ stringify->keys_type = NJS_ENUM_STRING | NJS_ENUM_SYMBOL;
if (!njs_dump_is_object(value)) {
ret = njs_dump_value(stringify, value, console);
@@ -2221,8 +2227,7 @@ njs_vm_value_dump(njs_vm_t *vm, njs_str_
}
key = &state->keys->start[state->index++];
- njs_string_get(key, &lhq.key);
- lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length);
+ njs_object_property_key_set(&lhq, key, 0);
if (njs_is_external(&state->value)) {
lhq.proto = &njs_extern_hash_proto;
@@ -2277,6 +2282,7 @@ njs_vm_value_dump(njs_vm_t *vm, njs_str_
}
state->written = 1;
+ njs_key_string_get(vm, key, &lhq.key);
njs_json_stringify_append((char *) lhq.key.start, lhq.key.length);
njs_json_stringify_append(":", 1);
if (stringify->space.length != 0) {
diff -r 263c75a40999 -r 10a19a2e1d4f src/njs_object.c
--- a/src/njs_object.c Tue Nov 19 20:45:22 2019 +0300
+++ b/src/njs_object.c Thu Nov 21 20:56:06 2019 +0300
@@ -14,19 +14,20 @@ static njs_object_prop_t *njs_object_exi
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,
- njs_bool_t all);
+ njs_object_enum_type_t type, njs_bool_t all);
static uint32_t njs_object_own_enumerate_object_length(
- const njs_object_t *object, const njs_object_t *parent, njs_bool_t all);
+ const njs_object_t *object, const njs_object_t *parent,
+ njs_object_enum_type_t type, njs_bool_t all);
static njs_int_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_int_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_int_t njs_object_enumerate_object(njs_vm_t *vm,
const njs_object_t *object, njs_array_t *items, njs_object_enum_t kind,
- njs_bool_t all);
+ njs_object_enum_type_t type, njs_bool_t all);
static njs_int_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, njs_bool_t all);
+ njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
njs_object_t *
@@ -128,8 +129,9 @@ njs_object_hash_create(njs_vm_t *vm, njs
lhq.pool = vm->mem_pool;
while (n != 0) {
- njs_string_get(&prop->name, &lhq.key);
- lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length);
+
+ njs_object_property_key_set(&lhq, &prop->name, 0);
+
lhq.value = (void *) prop;
ret = njs_lvlhsh_insert(hash, &lhq);
@@ -161,25 +163,34 @@ njs_object_hash_test(njs_lvlhsh_query_t
{
size_t size;
u_char *start;
+ njs_value_t *name;
njs_object_prop_t *prop;
prop = data;
-
- size = prop->name.short_string.size;
+ name = &prop->name;
+
+ if (njs_slow_path(njs_is_symbol(name))) {
+ return ((njs_symbol_key(name) == lhq->key_hash)
+ && lhq->key.length == 0) ? NJS_OK : NJS_DECLINED;
+ }
+
+ /* string. */
+
+ size = name->short_string.size;
if (size != NJS_STRING_LONG) {
if (lhq->key.length != size) {
return NJS_DECLINED;
}
- start = prop->name.short_string.start;
+ start = name->short_string.start;
} else {
- if (lhq->key.length != prop->name.long_string.size) {
+ if (lhq->key.length != name->long_string.size) {
return NJS_DECLINED;
}
- start = prop->name.long_string.data->start;
+ start = name->long_string.data->start;
}
if (memcmp(start, lhq->key.start, lhq->key.length) == 0) {
@@ -293,7 +304,8 @@ njs_object_keys(njs_vm_t *vm, njs_value_
return NJS_ERROR;
}
- keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, 0);
+ keys = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS,
+ NJS_ENUM_STRING, 0);
if (keys == NULL) {
return NJS_ERROR;
}
@@ -320,7 +332,8 @@ njs_object_values(njs_vm_t *vm, njs_valu
return NJS_ERROR;
}
- array = njs_value_own_enumerate(vm, value, NJS_ENUM_VALUES, 0);
+ array = njs_value_own_enumerate(vm, value, NJS_ENUM_VALUES,
+ NJS_ENUM_STRING, 0);
if (array == NULL) {
return NJS_ERROR;
}
@@ -347,7 +360,8 @@ njs_object_entries(njs_vm_t *vm, njs_val
return NJS_ERROR;
}
- array = njs_value_own_enumerate(vm, value, NJS_ENUM_BOTH, 0);
+ array = njs_value_own_enumerate(vm, value, NJS_ENUM_BOTH,
+ NJS_ENUM_STRING, 0);
if (array == NULL) {
return NJS_ERROR;
}
@@ -396,23 +410,26 @@ next:
njs_inline uint32_t
-njs_object_enumerate_length(const njs_object_t *object, njs_bool_t all)
+njs_object_enumerate_length(const njs_object_t *object,
+ njs_object_enum_type_t type, njs_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_OBJECT_STRING:
- length += njs_object_enumerate_string_length(object);
- break;
-
- default:
- break;
+ length = njs_object_enumerate_object_length(object, type, all);
+
+ if (type & NJS_STRING) {
+ 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;
+ }
}
return length;
@@ -421,23 +438,25 @@ njs_object_enumerate_length(const njs_ob
njs_inline uint32_t
njs_object_own_enumerate_length(const njs_object_t *object,
- const njs_object_t *parent, njs_bool_t all)
+ const njs_object_t *parent, njs_object_enum_type_t type, njs_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;
+ length = njs_object_own_enumerate_object_length(object, parent, type, all);
+
+ if (type & NJS_ENUM_STRING) {
+ 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;
+ }
}
return length;
@@ -446,34 +465,37 @@ njs_object_own_enumerate_length(const nj
njs_inline njs_int_t
njs_object_enumerate_value(njs_vm_t *vm, const njs_object_t *object,
- njs_array_t *items, njs_object_enum_t kind, njs_bool_t all)
+ njs_array_t *items, njs_object_enum_t kind, njs_object_enum_type_t type,
+ njs_bool_t all)
{
njs_int_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 (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
+ if (type & NJS_ENUM_STRING) {
+ 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 (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
}
object:
- ret = njs_object_enumerate_object(vm, object, items, kind, all);
+ ret = njs_object_enumerate_object(vm, object, items, kind, type, all);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
}
@@ -485,34 +507,37 @@ object:
njs_inline njs_int_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,
- njs_bool_t all)
+ njs_object_enum_type_t type, njs_bool_t all)
{
njs_int_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 (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
+ if (type & NJS_ENUM_STRING) {
+ 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 (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
}
object:
- ret = njs_object_own_enumerate_object(vm, object, parent, items, kind, all);
+ ret = njs_object_own_enumerate_object(vm, object, parent, items, kind,
+ type, all);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
}
@@ -523,20 +548,20 @@ object:
njs_array_t *
njs_object_enumerate(njs_vm_t *vm, const njs_object_t *object,
- njs_object_enum_t kind, njs_bool_t all)
+ njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all)
{
uint32_t length;
njs_int_t ret;
njs_array_t *items;
- length = njs_object_enumerate_length(object, all);
+ length = njs_object_enumerate_length(object, type, all);
items = njs_array_alloc(vm, length, NJS_ARRAY_SPARE);
if (njs_slow_path(items == NULL)) {
return NULL;
}
- ret = njs_object_enumerate_value(vm, object, items, kind, all);
+ ret = njs_object_enumerate_value(vm, object, items, kind, type, all);
if (njs_slow_path(ret != NJS_OK)) {
return NULL;
}
@@ -549,20 +574,21 @@ njs_object_enumerate(njs_vm_t *vm, const
njs_array_t *
njs_object_own_enumerate(njs_vm_t *vm, const njs_object_t *object,
- njs_object_enum_t kind, njs_bool_t all)
+ njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all)
{
uint32_t length;
njs_int_t ret;
njs_array_t *items;
- length = njs_object_own_enumerate_length(object, object, all);
+ length = njs_object_own_enumerate_length(object, object, type, all);
items = njs_array_alloc(vm, length, NJS_ARRAY_SPARE);
if (njs_slow_path(items == NULL)) {
return NULL;
}
- ret = njs_object_own_enumerate_value(vm, object, object, items, kind, all);
+ ret = njs_object_own_enumerate_value(vm, object, object, items, kind, type,
+ all);
if (njs_slow_path(ret != NJS_OK)) {
return NULL;
}
@@ -604,17 +630,18 @@ njs_object_enumerate_string_length(const
static uint32_t
-njs_object_enumerate_object_length(const njs_object_t *object, njs_bool_t all)
+njs_object_enumerate_object_length(const njs_object_t *object,
+ njs_object_enum_type_t type, njs_bool_t all)
{
uint32_t length;
const njs_object_t *proto;
- length = njs_object_own_enumerate_object_length(object, object, all);
+ length = njs_object_own_enumerate_object_length(object, object, type, all);
proto = object->__proto__;
while (proto != NULL) {
- length += njs_object_own_enumerate_length(proto, object, all);
+ length += njs_object_own_enumerate_length(proto, object, type, all);
proto = proto->__proto__;
}
@@ -622,9 +649,17 @@ njs_object_enumerate_object_length(const
}
+njs_inline njs_bool_t
+njs_is_enumerable(const njs_value_t *value, njs_object_enum_type_t type)
+{
+ return (njs_is_string(value) && (type & NJS_ENUM_STRING))
+ || (njs_is_symbol(value) && (type & NJS_ENUM_SYMBOL));
+}
+
+
static uint32_t
njs_object_own_enumerate_object_length(const njs_object_t *object,
- const njs_object_t *parent, njs_bool_t all)
+ const njs_object_t *parent, njs_object_enum_type_t type, njs_bool_t all)
{
uint32_t length;
njs_int_t ret;
@@ -645,8 +680,11 @@ njs_object_own_enumerate_object_length(c
break;
}
- lhq.key_hash = lhe.key_hash;
- njs_string_get(&prop->name, &lhq.key);
+ if (!njs_is_enumerable(&prop->name, type)) {
+ continue;
+ }
+
+ njs_object_property_key_set(&lhq, &prop->name, lhe.key_hash);
ext_prop = njs_object_exist_in_proto(parent, object, &lhq);
@@ -667,10 +705,12 @@ njs_object_own_enumerate_object_length(c
break;
}
- lhq.key_hash = lhe.key_hash;
- njs_string_get(&prop->name, &lhq.key);
-
- lhq.proto = &njs_object_hash_proto;
+ if (!njs_is_enumerable(&prop->name, type)) {
+ continue;
+ }
+
+ njs_object_property_key_set(&lhq, &prop->name, lhe.key_hash);
+
ret = njs_lvlhsh_find(&object->hash, &lhq);
if (ret != NJS_OK) {
@@ -866,12 +906,14 @@ njs_object_enumerate_string(njs_vm_t *vm
static njs_int_t
njs_object_enumerate_object(njs_vm_t *vm, const njs_object_t *object,
- njs_array_t *items, njs_object_enum_t kind, njs_bool_t all)
+ njs_array_t *items, njs_object_enum_t kind, njs_object_enum_type_t type,
+ njs_bool_t all)
{
njs_int_t ret;
const njs_object_t *proto;
- ret = njs_object_own_enumerate_object(vm, object, object, items, kind, all);
+ ret = njs_object_own_enumerate_object(vm, object, object, items, kind,
+ type, all);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
}
@@ -880,7 +922,7 @@ njs_object_enumerate_object(njs_vm_t *vm
while (proto != NULL) {
ret = njs_object_own_enumerate_value(vm, proto, object, items, kind,
- all);
+ type, all);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
}
@@ -895,7 +937,7 @@ njs_object_enumerate_object(njs_vm_t *vm
static njs_int_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,
- njs_bool_t all)
+ njs_object_enum_type_t type, njs_bool_t all)
{
njs_int_t ret;
njs_value_t *item;
@@ -910,6 +952,8 @@ njs_object_own_enumerate_object(njs_vm_t
item = items->start;
hash = &object->hash;
+ lhq.proto = &njs_object_hash_proto;
+
switch (kind) {
case NJS_ENUM_KEYS:
for ( ;; ) {
@@ -919,8 +963,11 @@ njs_object_own_enumerate_object(njs_vm_t
break;
}
- lhq.key_hash = lhe.key_hash;
- njs_string_get(&prop->name, &lhq.key);
+ if (!njs_is_enumerable(&prop->name, type)) {
+ continue;
+ }
+
+ njs_object_property_key_set(&lhq, &prop->name, lhe.key_hash);
ext_prop = njs_object_exist_in_proto(parent, object, &lhq);
@@ -941,10 +988,12 @@ njs_object_own_enumerate_object(njs_vm_t
break;
}
- lhq.key_hash = lhe.key_hash;
- njs_string_get(&prop->name, &lhq.key);
-
- lhq.proto = &njs_object_hash_proto;
+ if (!njs_is_enumerable(&prop->name, type)) {
+ continue;
+ }
+
+ njs_object_property_key_set(&lhq, &prop->name, lhe.key_hash);
+
ret = njs_lvlhsh_find(&object->hash, &lhq);
if (ret != NJS_OK) {
@@ -966,8 +1015,11 @@ njs_object_own_enumerate_object(njs_vm_t
break;
}
- lhq.key_hash = lhe.key_hash;
- njs_string_get(&prop->name, &lhq.key);
+ if (!njs_is_enumerable(&prop->name, type)) {
+ continue;
+ }
+
+ njs_object_property_key_set(&lhq, &prop->name, lhe.key_hash);
ext_prop = njs_object_exist_in_proto(parent, object, &lhq);
@@ -989,10 +1041,12 @@ njs_object_own_enumerate_object(njs_vm_t
break;
}
- lhq.key_hash = lhe.key_hash;
- njs_string_get(&prop->name, &lhq.key);
-
- lhq.proto = &njs_object_hash_proto;
+ if (!njs_is_enumerable(&prop->name, type)) {
+ continue;
+ }
+
+ njs_object_property_key_set(&lhq, &prop->name, lhe.key_hash);
+
ret = njs_lvlhsh_find(&object->hash, &lhq);
if (ret != NJS_OK) {
@@ -1014,8 +1068,11 @@ njs_object_own_enumerate_object(njs_vm_t
break;
}
- lhq.key_hash = lhe.key_hash;
- njs_string_get(&prop->name, &lhq.key);
+ if (!njs_is_enumerable(&prop->name, type)) {
+ continue;
+ }
+
+ njs_object_property_key_set(&lhq, &prop->name, lhe.key_hash);
ext_prop = njs_object_exist_in_proto(parent, object, &lhq);
@@ -1048,10 +1105,12 @@ njs_object_own_enumerate_object(njs_vm_t
break;
}
- lhq.key_hash = lhe.key_hash;
- njs_string_get(&prop->name, &lhq.key);
-
- lhq.proto = &njs_object_hash_proto;
+ if (!njs_is_enumerable(&prop->name, type)) {
+ continue;
+ }
+
+ njs_object_property_key_set(&lhq, &prop->name, lhe.key_hash);
+
ret = njs_lvlhsh_find(&object->hash, &lhq);
if (ret != NJS_OK && (prop->enumerable || all)) {
@@ -1194,13 +1253,6 @@ njs_object_define_property(njs_vm_t *vm,
name = njs_lvalue_arg(&lvalue, args, nargs, 2);
- if (njs_slow_path(!njs_is_string(name))) {
- ret = njs_value_to_string(vm, name, name);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
- }
-
ret = njs_object_prop_define(vm, value, name, desc,
NJS_OBJECT_PROP_DESCRIPTOR);
if (njs_slow_path(ret != NJS_OK)) {
@@ -1274,7 +1326,7 @@ static njs_int_t
njs_object_get_own_property_descriptor(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused)
{
- njs_value_t *value, *property;
+ njs_value_t lvalue, *value, *property;
value = njs_arg(args, nargs, 1);
@@ -1284,7 +1336,7 @@ njs_object_get_own_property_descriptor(n
return NJS_ERROR;
}
- property = njs_arg(args, nargs, 2);
+ property = njs_lvalue_arg(&lvalue, args, nargs, 2);
return njs_object_prop_descriptor(vm, &vm->retval, value, property);
}
@@ -1311,7 +1363,8 @@ njs_object_get_own_property_descriptors(
return NJS_ERROR;
}
- names = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, 1);
+ names = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS,
+ NJS_ENUM_STRING | NJS_ENUM_SYMBOL, 1);
if (njs_slow_path(names == NULL)) {
return NJS_ERROR;
}
@@ -1339,8 +1392,7 @@ njs_object_get_own_property_descriptors(
return NJS_ERROR;
}
- njs_string_get(key, &lhq.key);
- lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length);
+ njs_object_property_key_set(&lhq, key, 0);
lhq.value = pr;
ret = njs_lvlhsh_insert(&descriptors->hash, &lhq);
@@ -1357,8 +1409,8 @@ njs_object_get_own_property_descriptors(
static njs_int_t
-njs_object_get_own_property_names(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused)
+njs_object_get_own_property(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t type)
{
njs_array_t *names;
njs_value_t *value;
@@ -1372,7 +1424,8 @@ njs_object_get_own_property_names(njs_vm
return NJS_ERROR;
}
- names = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS, 1);
+ names = njs_value_own_enumerate(vm, value, NJS_ENUM_KEYS,
+ type, 1);
if (names == NULL) {
return NJS_ERROR;
}
@@ -1669,7 +1722,8 @@ njs_object_assign(njs_vm_t *vm, njs_valu
for (i = 2; i < nargs; i++) {
source = &args[i];
- names = njs_value_own_enumerate(vm, source, NJS_ENUM_KEYS, 1);
+ names = njs_value_own_enumerate(vm, source, NJS_ENUM_KEYS,
+ NJS_ENUM_STRING | NJS_ENUM_SYMBOL, 1);
if (njs_slow_path(names == NULL)) {
return NJS_ERROR;
}
@@ -1913,7 +1967,18 @@ static const njs_object_prop_t njs_obje
{
.type = NJS_PROPERTY,
.name = njs_long_string("getOwnPropertyNames"),
- .value = njs_native_function(njs_object_get_own_property_names, 1),
+ .value = njs_native_function2(njs_object_get_own_property, 1,
+ NJS_ENUM_STRING),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ /* Object.getOwnPropertySymbols(). */
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("getOwnPropertySymbols"),
+ .value = njs_native_function2(njs_object_get_own_property, 1,
+ NJS_ENUM_SYMBOL),
.writable = 1,
.configurable = 1,
},
diff -r 263c75a40999 -r 10a19a2e1d4f src/njs_object.h
--- a/src/njs_object.h Tue Nov 19 20:45:22 2019 +0300
+++ b/src/njs_object.h Thu Nov 21 20:56:06 2019 +0300
@@ -8,27 +8,6 @@
#define _NJS_OBJECT_H_INCLUDED_
-#define njs_is_data_descriptor(prop) \
- ((prop)->writable != NJS_ATTRIBUTE_UNSET || njs_is_valid(&(prop)->value))
-
-
-#define njs_is_accessor_descriptor(prop) \
- (njs_is_function_or_undefined(&(prop)->getter) \
- || njs_is_function_or_undefined(&(prop)->setter))
-
-
-#define njs_is_generic_descriptor(prop) \
- (!njs_is_data_descriptor(prop) && !njs_is_accessor_descriptor(prop))
-
-
-#define njs_object_property_init(lhq, _key, hash) \
- do { \
- (lhq)->proto = &njs_object_hash_proto; \
- (lhq)->key_hash = hash; \
- (lhq)->key = njs_str_value(_key); \
- } while (0)
-
-
typedef enum {
NJS_OBJECT_PROP_DESCRIPTOR,
NJS_OBJECT_PROP_GETTER,
@@ -65,9 +44,9 @@ njs_object_t *njs_object_value_copy(njs_
njs_object_t *njs_object_value_alloc(njs_vm_t *vm, const njs_value_t *value,
njs_uint_t type);
njs_array_t *njs_object_enumerate(njs_vm_t *vm, const njs_object_t *object,
- njs_object_enum_t kind, njs_bool_t all);
+ njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
njs_array_t *njs_object_own_enumerate(njs_vm_t *vm, const njs_object_t *object,
- njs_object_enum_t kind, njs_bool_t all);
+ njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
njs_int_t njs_object_traverse(njs_vm_t *vm, njs_object_t *object, void *ctx,
njs_object_traverse_cb_t cb);
njs_int_t njs_object_hash_create(njs_vm_t *vm, njs_lvlhsh_t *hash,
@@ -101,7 +80,147 @@ njs_int_t njs_object_prop_descriptor(njs
njs_value_t *value, njs_value_t *setval);
const char *njs_prop_type_string(njs_object_prop_type_t type);
-extern const njs_object_type_init_t njs_obj_type_init;
+
+njs_inline njs_bool_t
+njs_is_data_descriptor(njs_object_prop_t *prop)
+{
+ return prop->writable != NJS_ATTRIBUTE_UNSET || njs_is_valid(&prop->value);
+}
+
+
+njs_inline njs_bool_t
+njs_is_accessor_descriptor(njs_object_prop_t *prop)
+{
+ return njs_is_function_or_undefined(&prop->getter)
+ || njs_is_function_or_undefined(&prop->setter);
+}
+
+
+njs_inline njs_bool_t
+njs_is_generic_descriptor(njs_object_prop_t *prop)
+{
+ return !njs_is_data_descriptor(prop) && !njs_is_accessor_descriptor(prop);
+}
+
+
+njs_inline void
+njs_object_property_key_set(njs_lvlhsh_query_t *lhq, const njs_value_t *key,
+ uint32_t hash)
+{
+ if (njs_is_symbol(key)) {
+
+ lhq->key.length = 0;
+ lhq->key_hash = njs_symbol_key(key);
+
+ } else {
+
+ /* string. */
+
+ njs_string_get(key, &lhq->key);
+
+ if (hash == 0) {
+ lhq->key_hash = njs_djb_hash(lhq->key.start, lhq->key.length);
+
+ } else {
+ lhq->key_hash = hash;
+ }
+ }
+}
+
+
+njs_inline void
+njs_object_property_init(njs_lvlhsh_query_t *lhq, const njs_value_t *key,
+ uint32_t hash)
+{
+ lhq->proto = &njs_object_hash_proto;
+
+ njs_object_property_key_set(lhq, key, hash);
+}
+
+
+njs_inline njs_int_t
+njs_primitive_value_to_key(njs_vm_t *vm, njs_value_t *dst,
+ const njs_value_t *src)
+{
+ const njs_value_t *value;
+
+ switch (src->type) {
+
+ case NJS_NULL:
+ value = &njs_string_null;
+ break;
+
+ case NJS_UNDEFINED:
+ value = &njs_string_undefined;
+ break;
+
+ case NJS_BOOLEAN:
+ value = njs_is_true(src) ? &njs_string_true : &njs_string_false;
+ break;
+
+ case NJS_NUMBER:
+ return njs_number_to_string(vm, dst, src);
+
+ case NJS_SYMBOL:
+ case NJS_STRING:
+ /* GC: njs_retain(src); */
+ value = src;
+ break;
+
+ default:
+ return NJS_ERROR;
+ }
+
+ *dst = *value;
+
+ return NJS_OK;
+}
+
+
+njs_inline njs_int_t
+njs_value_to_key(njs_vm_t *vm, njs_value_t *dst, njs_value_t *value)
+{
+ njs_int_t ret;
+ njs_value_t primitive;
+
+ if (njs_slow_path(!njs_is_primitive(value))) {
+ if (njs_slow_path(value->type == NJS_OBJECT_SYMBOL)) {
+ /* should fail */
+ value = njs_object_value(value);
+
+ } else {
+ ret = njs_value_to_primitive(vm, &primitive, value, 1);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ value = &primitive;
+ }
+ }
+
+ return njs_primitive_value_to_key(vm, dst, value);
+}
+
+
+njs_inline njs_int_t
+njs_key_string_get(njs_vm_t *vm, const njs_value_t *key, njs_str_t *str)
+{
+ njs_int_t ret;
+ njs_value_t dst;
+
+ if (njs_slow_path(njs_is_symbol(key))) {
+ ret = njs_symbol_to_string(vm, &dst, key);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ key = &dst;
+ }
+
+ njs_string_get(key, str);
+
+ return NJS_OK;
+}
njs_inline njs_int_t
@@ -118,4 +237,7 @@ njs_object_length_set(njs_vm_t *vm, njs_
More information about the nginx-devel
mailing list