details: https://hg.nginx.org/njs/rev/cf7e8f006bd8 branches: changeset: 2207:cf7e8f006bd8 user: Dmitry Volyntsev <xei...@nginx.com> date: Fri Sep 22 13:00:05 2023 -0700 description: Introduced API to work with external value pointers.
This allows to allocate the necessary context for external code on demand. diffstat: src/njs.h | 5 + src/njs_value.c | 25 ++++++++ src/test/njs_externals_test.c | 117 ++++++++++++++++++++++++++++++++++++++++++ src/test/njs_unit_test.c | 16 +++++- 4 files changed, 162 insertions(+), 1 deletions(-) diffs (265 lines): diff -r dbb011e433b2 -r cf7e8f006bd8 src/njs.h --- a/src/njs.h Fri Sep 22 13:00:04 2023 -0700 +++ b/src/njs.h Fri Sep 22 13:00:05 2023 -0700 @@ -532,12 +532,15 @@ NJS_EXPORT void njs_value_boolean_set(nj NJS_EXPORT void njs_value_number_set(njs_value_t *value, double num); NJS_EXPORT void njs_value_function_set(njs_value_t *value, njs_function_t *function); +NJS_EXPORT void njs_value_external_set(njs_value_t *value, + njs_external_ptr_t external); NJS_EXPORT uint8_t njs_value_bool(const njs_value_t *value); NJS_EXPORT double njs_value_number(const njs_value_t *value); NJS_EXPORT njs_function_t *njs_value_function(const njs_value_t *value); NJS_EXPORT njs_function_native_t njs_value_native_function( const njs_value_t *value); +njs_external_ptr_t njs_value_external(const njs_value_t *value); NJS_EXPORT njs_int_t njs_value_external_tag(const njs_value_t *value); NJS_EXPORT uint16_t njs_vm_prop_magic16(njs_object_prop_t *prop); @@ -555,6 +558,8 @@ NJS_EXPORT njs_int_t njs_value_is_valid_ NJS_EXPORT njs_int_t njs_value_is_string(const njs_value_t *value); NJS_EXPORT njs_int_t njs_value_is_object(const njs_value_t *value); NJS_EXPORT njs_int_t njs_value_is_error(const njs_value_t *value); +NJS_EXPORT njs_int_t njs_value_is_external(const njs_value_t *value, + njs_int_t proto_id); NJS_EXPORT njs_int_t njs_value_is_array(const njs_value_t *value); NJS_EXPORT njs_int_t njs_value_is_function(const njs_value_t *value); NJS_EXPORT njs_int_t njs_value_is_buffer(const njs_value_t *value); diff -r dbb011e433b2 -r cf7e8f006bd8 src/njs_value.c --- a/src/njs_value.c Fri Sep 22 13:00:04 2023 -0700 +++ b/src/njs_value.c Fri Sep 22 13:00:05 2023 -0700 @@ -466,6 +466,15 @@ njs_value_function_set(njs_value_t *valu } +void +njs_value_external_set(njs_value_t *value, njs_external_ptr_t external) +{ + njs_assert(njs_value_is_external(value, NJS_PROTO_ID_ANY)); + + njs_object_data(value) = external; +} + + uint8_t njs_value_bool(const njs_value_t *value) { @@ -504,6 +513,15 @@ njs_value_native_function(const njs_valu } +njs_external_ptr_t +njs_value_external(const njs_value_t *value) +{ + njs_assert(njs_value_is_external(value, NJS_PROTO_ID_ANY)); + + return njs_object_data(value); +} + + njs_int_t njs_value_is_null(const njs_value_t *value) { @@ -577,6 +595,13 @@ njs_value_is_error(const njs_value_t *va njs_int_t +njs_value_is_external(const njs_value_t *value, njs_int_t proto_id) +{ + return njs_is_object_data(value, njs_make_tag(proto_id)); +} + + +njs_int_t njs_value_is_array(const njs_value_t *value) { return njs_is_array(value); diff -r dbb011e433b2 -r cf7e8f006bd8 src/test/njs_externals_test.c --- a/src/test/njs_externals_test.c Fri Sep 22 13:00:04 2023 -0700 +++ b/src/test/njs_externals_test.c Fri Sep 22 13:00:05 2023 -0700 @@ -33,6 +33,7 @@ njs_int_t njs_array_buffer_detach(njs_vm static njs_int_t njs_external_r_proto_id; +static njs_int_t njs_external_null_proto_id; static njs_int_t njs_external_error_ctor_id; @@ -556,6 +557,67 @@ njs_unit_test_r_bind(njs_vm_t *vm, njs_v static njs_int_t +njs_unit_test_null_get(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) +{ + double *d; + njs_value_t *this; + + this = njs_argument(args, 0); + + if (!njs_value_is_external(this, njs_external_null_proto_id)) { + njs_type_error(vm, "\"this\" is not a null external"); + return NJS_ERROR; + } + + d = njs_value_external(this); + + if (d == NULL) { + njs_value_undefined_set(retval); + + } else { + njs_value_number_set(retval, *d); + } + + return NJS_OK; +} + + +static njs_int_t +njs_unit_test_null_set(njs_vm_t *vm, njs_value_t *args, + njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) +{ + double *d; + njs_value_t *this; + + this = njs_argument(args, 0); + + if (!njs_value_is_external(this, njs_external_null_proto_id)) { + njs_type_error(vm, "\"this\" is not a null external"); + return NJS_ERROR; + } + + d = njs_value_external(this); + + if (d == NULL) { + d = njs_mp_alloc(vm->mem_pool, sizeof(double)); + if (d == NULL) { + njs_memory_error(vm); + return NJS_ERROR; + } + } + + *d = njs_value_number(njs_arg(args, nargs, 1)); + + njs_value_external_set(this, d); + + njs_value_undefined_set(retval); + + return NJS_OK; +} + + +static njs_int_t njs_unit_test_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { @@ -1043,6 +1105,40 @@ static njs_external_t njs_unit_test_r_e }; +static njs_external_t njs_unit_test_null_external[] = { + + { + .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL, + .name.symbol = NJS_SYMBOL_TO_STRING_TAG, + .u.property = { + .value = "Null", + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("get"), + .writable = 1, + .configurable = 1, + .enumerable = 1, + .u.method = { + .native = njs_unit_test_null_get, + } + }, + + { + .flags = NJS_EXTERN_METHOD, + .name.string = njs_str("set"), + .writable = 1, + .configurable = 1, + .enumerable = 1, + .u.method = { + .native = njs_unit_test_null_set, + } + }, + +}; + static njs_external_t njs_unit_test_ctor_props[] = { @@ -1170,6 +1266,7 @@ njs_externals_init_internal(njs_vm_t *vm njs_unit_test_prop_t *prop; static const njs_str_t external_ctor = njs_str("ExternalConstructor"); + static const njs_str_t external_null = njs_str("ExternalNull"); static const njs_str_t external_error = njs_str("ExternalError"); if (shared) { @@ -1195,6 +1292,26 @@ njs_externals_init_internal(njs_vm_t *vm return NJS_ERROR; } + njs_external_null_proto_id = njs_vm_external_prototype(vm, + njs_unit_test_null_external, + njs_nitems(njs_unit_test_null_external)); + if (njs_slow_path(njs_external_null_proto_id < 0)) { + njs_printf("njs_vm_external_prototype() failed\n"); + return NJS_ERROR; + } + + ret = njs_vm_external_create(vm, njs_value_arg(&value), + njs_external_null_proto_id, NULL, 1); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + ret = njs_vm_bind(vm, &external_null, njs_value_arg(&value), 1); + if (njs_slow_path(ret != NJS_OK)) { + njs_printf("njs_vm_bind() failed\n"); + return NJS_ERROR; + } + njs_external_error_ctor_id = njs_vm_external_constructor(vm, &external_error, njs_error_constructor, njs_unit_test_ctor_props, diff -r dbb011e433b2 -r cf7e8f006bd8 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Fri Sep 22 13:00:04 2023 -0700 +++ b/src/test/njs_unit_test.c Fri Sep 22 13:00:05 2023 -0700 @@ -22637,7 +22637,8 @@ static njs_unit_test_t njs_externals_te #endif { njs_str("Object.keys(this).sort()"), - njs_str("$262,$r,$r2,$r3,$shared,ExternalConstructor,ExternalError," NCRYPTO "global,njs,process") }, + njs_str("$262,$r,$r2,$r3,$shared,ExternalConstructor,ExternalError," + "ExternalNull," NCRYPTO "global,njs,process") }, { njs_str("Object.getOwnPropertySymbols($r2)[0] == Symbol.toStringTag"), njs_str("true") }, @@ -22924,6 +22925,19 @@ static njs_unit_test_t njs_shared_test[ { njs_str("var sum = new Function('a, b', 'return a + b');" "sum(2, 4);"), njs_str("6") }, + + { njs_str("ExternalNull.get()"), + njs_str("undefined") }, + + { njs_str("ExternalNull.set(37); ExternalNull.get()"), + njs_str("37") }, + + { njs_str("ExternalNull.set(23); ExternalNull.set(37); ExternalNull.get()"), + njs_str("37") }, + + { njs_str("var v = Math.round(Math.random() * 1000); ExternalNull.set(v);" + "ExternalNull.get() == v"), + njs_str("true") }, }; _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel