[njs] Added Symbol.for() and Symbol.keyfor().
Dmitry Volyntsev
xeioex at nginx.com
Wed Jun 22 05:14:59 UTC 2022
details: https://hg.nginx.org/njs/rev/f7fec5be38a0
branches:
changeset: 1895:f7fec5be38a0
user: Dmitry Volyntsev <xeioex at 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") },
More information about the nginx-devel
mailing list