details: https://hg.nginx.org/njs/rev/f7fec5be38a0 branches: changeset: 1895:f7fec5be38a0 user: Dmitry Volyntsev <xei...@nginx.com> date: Tue Jun 21 21:54:14 2022 -0700 description: Added Symbol.for() and Symbol.keyfor().
diffstat: src/njs_extern.c | 2 +- src/njs_symbol.c | 146 +++++++++++++++++++++++++++++++++++----------- src/njs_symbol.h | 10 +++ src/njs_value.h | 3 +- src/njs_vm.c | 2 + src/njs_vm.h | 1 + src/test/njs_unit_test.c | 37 +++++++++++ 7 files changed, 162 insertions(+), 39 deletions(-) diffs (336 lines): diff -r 8ff4c3126a89 -r f7fec5be38a0 src/njs_extern.c --- a/src/njs_extern.c Tue Jun 21 15:29:00 2022 -0700 +++ b/src/njs_extern.c Tue Jun 21 21:54:14 2022 -0700 @@ -49,7 +49,7 @@ njs_external_add(njs_vm_t *vm, njs_arr_t prop->enumerable = external->enumerable; if (external->flags & 4) { - njs_set_symbol(&prop->name, external->name.symbol); + njs_set_symbol(&prop->name, external->name.symbol, NULL); lhq.key_hash = external->name.symbol; diff -r 8ff4c3126a89 -r f7fec5be38a0 src/njs_symbol.c --- a/src/njs_symbol.c Tue Jun 21 15:29:00 2022 -0700 +++ b/src/njs_symbol.c Tue Jun 21 21:54:14 2022 -0700 @@ -57,20 +57,16 @@ static const njs_value_t *njs_symbol_na const njs_value_t * njs_symbol_description(const njs_value_t *value) { - const njs_value_t *name; - - if (njs_symbol_key(value) < NJS_SYMBOL_KNOWN_MAX) { - name = njs_symbol_names[njs_symbol_key(value)]; + uint32_t key; - } else { - name = value->data.u.value; + key = njs_symbol_key(value); - if (name == NULL) { - return &njs_value_undefined; - } + if (key < NJS_SYMBOL_KNOWN_MAX) { + return njs_symbol_names[key]; } - return name; + return value->data.u.value != NULL ? value->data.u.value + : &njs_value_undefined; } @@ -109,9 +105,9 @@ static njs_int_t njs_symbol_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused) { + uint64_t key; njs_int_t ret; njs_value_t *value, *name; - uint64_t key; if (njs_slow_path(vm->top_frame->ctor)) { njs_type_error(vm, "Symbol is not a constructor"); @@ -120,25 +116,13 @@ njs_symbol_constructor(njs_vm_t *vm, njs value = njs_arg(args, nargs, 1); - if (njs_is_undefined(value)) { - name = NULL; - - } else { + if (njs_is_defined(value)) { if (njs_slow_path(!njs_is_string(value))) { ret = njs_value_to_string(vm, value, value); if (njs_slow_path(ret != NJS_OK)) { return ret; } } - - name = njs_mp_alloc(vm->mem_pool, sizeof(njs_value_t)); - if (njs_slow_path(name == NULL)) { - njs_memory_error(vm); - return NJS_ERROR; - } - - /* GC: retain */ - *name = *value; } key = ++vm->symbol_generator; @@ -148,32 +132,100 @@ njs_symbol_constructor(njs_vm_t *vm, njs return NJS_ERROR; } - vm->retval.type = NJS_SYMBOL; - vm->retval.data.truth = 1; - vm->retval.data.magic32 = key; - vm->retval.data.u.value = name; + name = njs_mp_alloc(vm->mem_pool, sizeof(njs_value_t)); + if (njs_slow_path(name == NULL)) { + njs_memory_error(vm); + return NJS_ERROR; + } + + njs_value_assign(name, value); + njs_set_symbol(&vm->retval, key, name); return NJS_OK; } static njs_int_t -njs_symbol_for(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused) +njs_symbol_for(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t unused) { - njs_internal_error(vm, "not implemented"); + uint64_t key; + njs_int_t ret; + njs_value_t *value; + njs_rbtree_node_t *rb_node; + njs_rb_symbol_node_t *node; + + value = njs_arg(args, nargs, 1); + + if (njs_slow_path(!njs_is_string(value))) { + ret = njs_value_to_string(vm, value, value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + } + + rb_node = njs_rbtree_min(&vm->global_symbols); + + while (njs_rbtree_is_there_successor(&vm->global_symbols, rb_node)) { + + node = (njs_rb_symbol_node_t *) rb_node; - return NJS_ERROR; + if (njs_is_string(&node->name) + && njs_string_cmp(value, &node->name) == 0) + { + njs_set_symbol(&vm->retval, node->key, &node->name); + return NJS_OK; + } + + rb_node = njs_rbtree_node_successor(&vm->global_symbols, rb_node); + } + + key = ++vm->symbol_generator; + + if (njs_slow_path(key >= UINT32_MAX)) { + njs_internal_error(vm, "Symbol generator overflow"); + return NJS_ERROR; + } + + node = njs_mp_alloc(vm->mem_pool, sizeof(njs_rb_symbol_node_t)); + if (njs_slow_path(node == NULL)) { + njs_memory_error(vm); + return NJS_ERROR; + } + + node->key = key; + njs_value_assign(&node->name, value); + + njs_rbtree_insert(&vm->global_symbols, &node->node); + + njs_set_symbol(&vm->retval, key, &node->name); + + return NJS_OK; } static njs_int_t -njs_symbol_key_for(njs_vm_t *vm, njs_value_t *args, - njs_uint_t nargs, njs_index_t unused) +njs_symbol_key_for(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t unused) { - njs_internal_error(vm, "not implemented"); + njs_value_t *value; + njs_rb_symbol_node_t query, *node; + + value = njs_arg(args, nargs, 1); - return NJS_ERROR; + if (njs_slow_path(!njs_is_symbol(value))) { + njs_type_error(vm, "is not a symbol"); + return NJS_ERROR; + } + + query.key = njs_symbol_key(value); + node = (njs_rb_symbol_node_t *) njs_rbtree_find(&vm->global_symbols, + &query.node); + + njs_value_assign(&vm->retval, + node != NULL ? &node->name : &njs_value_undefined); + + return NJS_OK; } @@ -355,7 +407,7 @@ njs_symbol_prototype_description(njs_vm_ return ret; } - vm->retval = *njs_symbol_description(&vm->retval); + njs_value_assign(&vm->retval, njs_symbol_description(&vm->retval)); return NJS_OK; } @@ -426,3 +478,23 @@ const njs_object_type_init_t njs_symbol .prototype_props = &njs_symbol_prototype_init, .prototype_value = { .object = { .type = NJS_OBJECT } }, }; + + +intptr_t +njs_symbol_rbtree_cmp(njs_rbtree_node_t *node1, njs_rbtree_node_t *node2) +{ + njs_rb_symbol_node_t *item1, *item2; + + item1 = (njs_rb_symbol_node_t *) node1; + item2 = (njs_rb_symbol_node_t *) node2; + + if (item1->key < item2->key) { + return -1; + } + + if (item1->key == item2->key) { + return 0; + } + + return 1; +} diff -r 8ff4c3126a89 -r f7fec5be38a0 src/njs_symbol.h --- a/src/njs_symbol.h Tue Jun 21 15:29:00 2022 -0700 +++ b/src/njs_symbol.h Tue Jun 21 21:54:14 2022 -0700 @@ -7,9 +7,19 @@ #ifndef _NJS_SYMBOL_H_INCLUDED_ #define _NJS_SYMBOL_H_INCLUDED_ + +typedef struct { + NJS_RBTREE_NODE (node); + uint32_t key; + njs_value_t name; +} njs_rb_symbol_node_t; + + const njs_value_t *njs_symbol_description(const njs_value_t *value); njs_int_t njs_symbol_descriptive_string(njs_vm_t *vm, njs_value_t *dst, const njs_value_t *value); +intptr_t njs_symbol_rbtree_cmp(njs_rbtree_node_t *node1, + njs_rbtree_node_t *node2); extern const njs_object_type_init_t njs_symbol_type_init; diff -r 8ff4c3126a89 -r f7fec5be38a0 src/njs_value.h --- a/src/njs_value.h Tue Jun 21 15:29:00 2022 -0700 +++ b/src/njs_value.h Tue Jun 21 21:54:14 2022 -0700 @@ -875,11 +875,12 @@ njs_set_uint32(njs_value_t *value, uint3 njs_inline void -njs_set_symbol(njs_value_t *value, uint32_t symbol) +njs_set_symbol(njs_value_t *value, uint32_t symbol, njs_value_t *name) { value->data.magic32 = symbol; value->type = NJS_SYMBOL; value->data.truth = 1; + value->data.u.value = name; } diff -r 8ff4c3126a89 -r f7fec5be38a0 src/njs_vm.c --- a/src/njs_vm.c Tue Jun 21 15:29:00 2022 -0700 +++ b/src/njs_vm.c Tue Jun 21 21:54:14 2022 -0700 @@ -396,6 +396,8 @@ njs_vm_init(njs_vm_t *vm) njs_lvlhsh_init(&vm->modules_hash); njs_lvlhsh_init(&vm->events_hash); + njs_rbtree_init(&vm->global_symbols, njs_symbol_rbtree_cmp); + njs_queue_init(&vm->posted_events); njs_queue_init(&vm->promise_events); diff -r 8ff4c3126a89 -r f7fec5be38a0 src/njs_vm.h --- a/src/njs_vm.h Tue Jun 21 15:29:00 2022 -0700 +++ b/src/njs_vm.h Tue Jun 21 21:54:14 2022 -0700 @@ -197,6 +197,7 @@ struct njs_vm_s { njs_trace_t trace; njs_random_t random; + njs_rbtree_t global_symbols; uint64_t symbol_generator; }; diff -r 8ff4c3126a89 -r f7fec5be38a0 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Tue Jun 21 15:29:00 2022 -0700 +++ b/src/test/njs_unit_test.c Tue Jun 21 21:54:14 2022 -0700 @@ -12866,6 +12866,43 @@ static njs_unit_test_t njs_test[] = ".every((x) => 'Symbol(Symbol.' + x.k + ')' == String(x.v))"), njs_str("true") }, + { njs_str("Symbol.for('desc').toString()"), + njs_str("Symbol(desc)") }, + + { njs_str("Symbol.for({toString: () => 'desc'}).description"), + njs_str("desc") }, + + { njs_str("Symbol.for('desc') === Symbol.for('desc')"), + njs_str("true") }, + + { njs_str("Symbol.keyFor(Symbol())"), + njs_str("undefined") }, + + { njs_str("Symbol.keyFor(Symbol('desc'))"), + njs_str("undefined") }, + + { njs_str("Symbol.keyFor(1)"), + njs_str("TypeError: is not a symbol") }, + + { njs_str("Symbol.keyFor(Symbol.for('desc'))"), + njs_str("desc") }, + + { njs_str("[ 'asyncIterator'," + " 'hasInstance'," + " 'isConcatSpreadable'," + " 'iterator'," + " 'match'," + " 'matchAll'," + " 'replace'," + " 'search'," + " 'species'," + " 'split'," + " 'toPrimitive'," + " 'toStringTag'," + " 'unscopables' ]" + ".every(v => Symbol.keyFor(Symbol[v]) === undefined)"), + njs_str("true") }, + { njs_str("typeof Symbol.prototype.description"), njs_str("TypeError: unexpected value type:object") }, _______________________________________________ nginx-devel mailing list -- nginx-devel@nginx.org To unsubscribe send an email to nginx-devel-le...@nginx.org