From dbd39162e21fbf6b8c263794209c5331398a2ba1 Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Wed, 7 Dec 2022 18:11:54 -0800 Subject: [PATCH] Allowing to declare exotic slot for the external objects. --- src/njs.h | 8 ++++ src/njs_extern.c | 69 +++++++++++++++++++++++++---------- src/test/njs_externals_test.c | 33 +++++++++++++++++ src/test/njs_unit_test.c | 3 ++ 4 files changed, 94 insertions(+), 19 deletions(-) diff --git a/src/njs.h b/src/njs.h index 06f24153..4badacbf 100644 --- a/src/njs.h +++ b/src/njs.h @@ -132,9 +132,17 @@ typedef enum { typedef enum { + /* + * Extern property type. + */ NJS_EXTERN_PROPERTY = 0, NJS_EXTERN_METHOD = 1, NJS_EXTERN_OBJECT = 2, + NJS_EXTERN_SELF = 3, +#define NJS_EXTERN_TYPE_MASK 3 + /* + * Extern property flags. + */ NJS_EXTERN_SYMBOL = 4, } njs_extern_flag_t; diff --git a/src/njs_extern.c b/src/njs_extern.c index 39cb17f2..6cc9b00a 100644 --- a/src/njs_extern.c +++ b/src/njs_extern.c @@ -17,15 +17,16 @@ static njs_int_t njs_external_add(njs_vm_t *vm, njs_arr_t *protos, const njs_external_t *external, njs_uint_t n) { - size_t size; - ssize_t length; - njs_int_t ret; - njs_lvlhsh_t *hash; - const u_char *start; - njs_function_t *function; - njs_object_prop_t *prop; - njs_lvlhsh_query_t lhq; - njs_exotic_slots_t *slot, *next; + size_t size; + ssize_t length; + njs_int_t ret; + njs_lvlhsh_t *hash; + const u_char *start; + njs_function_t *function; + njs_object_prop_t *prop; + njs_lvlhsh_query_t lhq; + njs_exotic_slots_t *slot, *next; + const njs_external_t *end; slot = njs_arr_add(protos); njs_memzero(slot, sizeof(njs_exotic_slots_t)); @@ -37,7 +38,22 @@ njs_external_add(njs_vm_t *vm, njs_arr_t *protos, lhq.proto = &njs_object_hash_proto; lhq.pool = vm->mem_pool; - while (n != 0) { + end = external + n; + + while (external < end) { + + if ((external->flags & NJS_EXTERN_TYPE_MASK) == NJS_EXTERN_SELF) { + slot->writable = external->u.object.writable; + slot->configurable = external->u.object.configurable; + slot->enumerable = external->u.object.enumerable; + slot->prop_handler = external->u.object.prop_handler; + slot->magic32 = external->u.object.magic32; + slot->keys = external->u.object.keys; + + external++; + continue; + } + prop = njs_object_prop_alloc(vm, &njs_string_empty, &njs_value_invalid, 1); if (njs_slow_path(prop == NULL)) { @@ -48,7 +64,7 @@ njs_external_add(njs_vm_t *vm, njs_arr_t *protos, prop->configurable = external->configurable; prop->enumerable = external->enumerable; - if (external->flags & 4) { + if (external->flags & NJS_EXTERN_SYMBOL) { njs_set_symbol(&prop->name, external->name.symbol, NULL); lhq.key_hash = external->name.symbol; @@ -66,7 +82,7 @@ njs_external_add(njs_vm_t *vm, njs_arr_t *protos, lhq.value = prop; - switch (external->flags & 3) { + switch (external->flags & NJS_EXTERN_TYPE_MASK) { case NJS_EXTERN_METHOD: function = njs_mp_zalloc(vm->mem_pool, sizeof(njs_function_t)); if (njs_slow_path(function == NULL)) { @@ -128,12 +144,28 @@ njs_external_add(njs_vm_t *vm, njs_arr_t *protos, njs_prop_magic32(prop) = lhq.key_hash; njs_prop_handler(prop) = njs_external_prop_handler; - next->writable = external->u.object.writable; - next->configurable = external->u.object.configurable; - next->enumerable = external->u.object.enumerable; - next->prop_handler = external->u.object.prop_handler; - next->magic32 = external->u.object.magic32; - next->keys = external->u.object.keys; + if (external->u.object.prop_handler) { + if (next->prop_handler) { + njs_internal_error(vm, "overwritten self prop_handler"); + return NJS_ERROR; + } + + next->writable = external->u.object.writable; + next->configurable = external->u.object.configurable; + next->enumerable = external->u.object.enumerable; + + next->prop_handler = external->u.object.prop_handler; + next->magic32 = external->u.object.magic32; + } + + if (external->u.object.keys) { + if (next->keys) { + njs_internal_error(vm, "overwritten self keys"); + return NJS_ERROR; + } + + next->keys = external->u.object.keys; + } break; } @@ -144,7 +176,6 @@ njs_external_add(njs_vm_t *vm, njs_arr_t *protos, return NJS_ERROR; } - n--; external++; } diff --git a/src/test/njs_externals_test.c b/src/test/njs_externals_test.c index 68ec80f0..5856c234 100644 --- a/src/test/njs_externals_test.c +++ b/src/test/njs_externals_test.c @@ -585,6 +585,28 @@ static njs_external_t njs_unit_test_r_header_props[] = { }; +static njs_external_t njs_unit_test_r_header_props2[] = { + + { + .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL, + .name.symbol = NJS_SYMBOL_TO_STRING_TAG, + .u.property = { + .value = "Header2", + } + }, + + { + .flags = NJS_EXTERN_SELF, + .u.object = { + .enumerable = 1, + .prop_handler = njs_unit_test_r_header, + .keys = njs_unit_test_r_header_keys, + } + }, + +}; + + static njs_external_t njs_unit_test_r_external[] = { { @@ -644,6 +666,17 @@ static njs_external_t njs_unit_test_r_external[] = { } }, + { + .flags = NJS_EXTERN_OBJECT, + .name.string = njs_str("header2"), + .writable = 1, + .configurable = 1, + .u.object = { + .properties = njs_unit_test_r_header_props2, + .nproperties = njs_nitems(njs_unit_test_r_header_props2), + } + }, + { .flags = NJS_EXTERN_PROPERTY, .name.string = njs_str("host"), diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 8fa86a5c..7b59c07a 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -21712,6 +21712,9 @@ static njs_unit_test_t njs_externals_test[] = { njs_str("njs.dump($r.header)"), njs_str("Header {01:'01|АБВ',02:'02|АБВ',03:'03|АБВ'}") }, + { njs_str("njs.dump($r.header2)"), + njs_str("Header2 {01:'01|АБВ',02:'02|АБВ',03:'03|АБВ'}") }, + { njs_str("var o = {b:$r.props.b}; o.b"), njs_str("42") }, -- 2.47.3