[njs] Marking different external pointer with unique tag.

Dmitry Volyntsev xeioex at nginx.com
Fri Jul 9 19:37:10 UTC 2021


details:   https://hg.nginx.org/njs/rev/42fdcacfd131
branches:  
changeset: 1675:42fdcacfd131
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Fri Jul 09 19:14:23 2021 +0000
description:
Marking different external pointer with unique tag.

An external value has an arbitrary raw pointer associated with it.
External values with different prototypes have different C-level
structures.  To ensure that only appropriate structures are fetched
by njs_vm_external() the unique tag has to be provided during
creation of external values.

diffstat:

 nginx/ngx_http_js_module.c    |  55 +++++++++++++++++++-------------
 nginx/ngx_js.c                |   6 +-
 nginx/ngx_js_fetch.c          |  19 ++++++-----
 nginx/ngx_stream_js_module.c  |  16 ++++++---
 src/njs.h                     |   5 ++-
 src/njs_extern.c              |  21 +++++++++---
 src/njs_shell.c               |  71 +++++++++++++++++-------------------------
 src/njs_value.h               |   8 ++++-
 src/test/njs_externals_test.c |  64 ++++++++++++++++++--------------------
 src/test/njs_externals_test.h |   2 +-
 src/test/njs_unit_test.c      |  23 +++++++++----
 11 files changed, 157 insertions(+), 133 deletions(-)

diffs (908 lines):

diff -r 92cb9b80cf8b -r 42fdcacfd131 nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c	Fri Jul 09 14:01:26 2021 +0000
+++ b/nginx/ngx_http_js_module.c	Fri Jul 09 19:14:23 2021 +0000
@@ -1256,7 +1256,7 @@ ngx_http_js_ext_raw_header(njs_vm_t *vm,
     ngx_table_elt_t     *header, *h;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -1349,7 +1349,7 @@ ngx_http_js_ext_header_out(njs_vm_t *vm,
         { njs_str(""), ngx_http_js_header_generic },
     };
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         if (retval != NULL) {
             njs_value_undefined_set(retval);
@@ -1840,7 +1840,7 @@ ngx_http_js_ext_keys_header_out(njs_vm_t
         return NJS_ERROR;
     }
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         return NJS_OK;
     }
@@ -1885,7 +1885,7 @@ ngx_http_js_ext_status(njs_vm_t *vm, njs
     ngx_int_t            n;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -1912,7 +1912,8 @@ ngx_http_js_ext_send_header(njs_vm_t *vm
 {
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id,
+                        njs_argument(args, 0));
     if (r == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -1945,7 +1946,8 @@ ngx_http_js_ext_send(njs_vm_t *vm, njs_v
     ngx_http_js_ctx_t   *ctx;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, njs_argument(args, 0));
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id,
+                        njs_argument(args, 0));
     if (r == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -2033,7 +2035,8 @@ ngx_http_js_ext_send_buffer(njs_vm_t *vm
     static const njs_str_t last_key = njs_str("last");
     static const njs_str_t flush_key = njs_str("flush");
 
-    r = njs_vm_external(vm, njs_argument(args, 0));
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id,
+                        njs_argument(args, 0));
     if (r == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -2104,7 +2107,8 @@ ngx_http_js_ext_done(njs_vm_t *vm, njs_v
     ngx_http_js_ctx_t   *ctx;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, njs_argument(args, 0));
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id,
+                        njs_argument(args, 0));
     if (r == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -2132,7 +2136,8 @@ ngx_http_js_ext_finish(njs_vm_t *vm, njs
     ngx_http_js_ctx_t   *ctx;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id,
+                        njs_argument(args, 0));
     if (r == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -2162,7 +2167,8 @@ ngx_http_js_ext_return(njs_vm_t *vm, njs
     ngx_http_request_t        *r;
     ngx_http_complex_value_t   cv;
 
-    r = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id,
+                        njs_argument(args, 0));
     if (r == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -2215,7 +2221,8 @@ ngx_http_js_ext_internal_redirect(njs_vm
     ngx_http_js_ctx_t   *ctx;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id,
+                        njs_argument(args, 0));
     if (r == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -2256,7 +2263,7 @@ ngx_http_js_ext_get_http_version(njs_vm_
     ngx_str_t            v;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -2302,7 +2309,7 @@ ngx_http_js_ext_get_remote_address(njs_v
     ngx_connection_t    *c;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -2328,7 +2335,7 @@ ngx_http_js_ext_get_request_body(njs_vm_
     ngx_http_js_ctx_t   *ctx;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -2425,7 +2432,7 @@ ngx_http_js_ext_header_in(njs_vm_t *vm, 
         { njs_str(""), ngx_http_js_header_generic },
     };
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         if (retval != NULL) {
             njs_value_undefined_set(retval);
@@ -2542,7 +2549,7 @@ ngx_http_js_ext_keys_header_in(njs_vm_t 
         return NJS_ERROR;
     }
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         return NJS_OK;
     }
@@ -2559,7 +2566,7 @@ ngx_http_js_ext_get_arg(njs_vm_t *vm, nj
     ngx_str_t            arg;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -2595,7 +2602,7 @@ ngx_http_js_ext_keys_arg(njs_vm_t *vm, n
         return NJS_ERROR;
     }
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         return NJS_OK;
     }
@@ -2646,7 +2653,7 @@ ngx_http_js_ext_variables(njs_vm_t *vm, 
     ngx_http_core_main_conf_t  *cmcf;
     ngx_http_variable_value_t  *vv;
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -2739,7 +2746,8 @@ ngx_http_js_promise_trampoline(njs_vm_t 
     ngx_http_js_ctx_t   *ctx;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, njs_argument(args, 1));
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id,
+                        njs_arg(args, nargs, 1));
     ctx = ngx_http_get_module_ctx(r->parent, ngx_http_js_module);
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -2823,7 +2831,8 @@ ngx_http_js_ext_subrequest(njs_vm_t *vm,
     static const njs_str_t body_key = njs_str("body");
     static const njs_str_t detached_key = njs_str("detached");
 
-    r = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id,
+                        njs_argument(args, 0));
     if (r == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -3165,7 +3174,7 @@ ngx_http_js_ext_get_parent(njs_vm_t *vm,
     ngx_http_js_ctx_t   *ctx;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -3197,7 +3206,7 @@ ngx_http_js_ext_get_response_body(njs_vm
     ngx_http_js_ctx_t   *ctx;
     ngx_http_request_t  *r;
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, ngx_http_js_request_proto_id, value);
     if (r == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
diff -r 92cb9b80cf8b -r 42fdcacfd131 nginx/ngx_js.c
--- a/nginx/ngx_js.c	Fri Jul 09 14:01:26 2021 +0000
+++ b/nginx/ngx_js.c	Fri Jul 09 19:14:23 2021 +0000
@@ -173,7 +173,7 @@ ngx_js_ext_string(njs_vm_t *vm, njs_obje
     char       *p;
     ngx_str_t  *field;
 
-    p = njs_vm_external(vm, value);
+    p = njs_vm_external(vm, NJS_PROTO_ID_ANY, value);
     if (p == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -192,7 +192,7 @@ ngx_js_ext_uint(njs_vm_t *vm, njs_object
     char        *p;
     ngx_uint_t   field;
 
-    p = njs_vm_external(vm, value);
+    p = njs_vm_external(vm, NJS_PROTO_ID_ANY, value);
     if (p == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -237,7 +237,7 @@ ngx_js_ext_log(njs_vm_t *vm, njs_value_t
     ngx_connection_t    *c;
     ngx_log_handler_pt   handler;
 
-    p = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    p = njs_vm_external(vm, NJS_PROTO_ID_ANY, njs_argument(args, 0));
     if (p == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
diff -r 92cb9b80cf8b -r 42fdcacfd131 nginx/ngx_js_fetch.c
--- a/nginx/ngx_js_fetch.c	Fri Jul 09 14:01:26 2021 +0000
+++ b/nginx/ngx_js_fetch.c	Fri Jul 09 19:14:23 2021 +0000
@@ -345,7 +345,7 @@ ngx_js_ext_fetch(njs_vm_t *vm, njs_value
     static const njs_str_t body_size_key = njs_str("max_response_body_size");
     static const njs_str_t method_key = njs_str("method");
 
-    external = njs_vm_external(vm, njs_argument(args, 0));
+    external = njs_vm_external(vm, NJS_PROTO_ID_ANY, njs_argument(args, 0));
     if (external == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -1859,7 +1859,7 @@ ngx_response_js_ext_header_get(njs_vm_t 
     ngx_js_http_t    *http;
     ngx_table_elt_t  *header, *h;
 
-    http = njs_vm_external(vm, value);
+    http = njs_vm_external(vm, ngx_http_js_fetch_proto_id, value);
     if (http == NULL) {
         njs_value_null_set(retval);
         return NJS_DECLINED;
@@ -2011,7 +2011,7 @@ ngx_response_js_ext_keys(njs_vm_t *vm, n
     ngx_js_http_t    *http;
     ngx_table_elt_t  *h, *headers;
 
-    http = njs_vm_external(vm, value);
+    http = njs_vm_external(vm, ngx_http_js_fetch_proto_id, value);
     if (http == NULL) {
         njs_value_undefined_set(keys);
         return NJS_DECLINED;
@@ -2067,7 +2067,8 @@ ngx_response_js_ext_body(njs_vm_t *vm, n
     ngx_js_http_t       *http;
     njs_opaque_value_t   retval;
 
-    http = njs_vm_external(vm, njs_argument(args, 0));
+    http = njs_vm_external(vm, ngx_http_js_fetch_proto_id,
+                           njs_argument(args, 0));
     if (http == NULL) {
         njs_value_undefined_set(njs_vm_retval(vm));
         return NJS_DECLINED;
@@ -2124,7 +2125,7 @@ ngx_response_js_ext_body_used(njs_vm_t *
 {
     ngx_js_http_t  *http;
 
-    http = njs_vm_external(vm, value);
+    http = njs_vm_external(vm, ngx_http_js_fetch_proto_id, value);
     if (http == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -2143,7 +2144,7 @@ ngx_response_js_ext_ok(njs_vm_t *vm, njs
     ngx_uint_t      code;
     ngx_js_http_t  *http;
 
-    http = njs_vm_external(vm, value);
+    http = njs_vm_external(vm, ngx_http_js_fetch_proto_id, value);
     if (http == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -2163,7 +2164,7 @@ ngx_response_js_ext_status(njs_vm_t *vm,
 {
     ngx_js_http_t  *http;
 
-    http = njs_vm_external(vm, value);
+    http = njs_vm_external(vm, ngx_http_js_fetch_proto_id, value);
     if (http == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -2181,7 +2182,7 @@ ngx_response_js_ext_status_text(njs_vm_t
 {
     ngx_js_http_t  *http;
 
-    http = njs_vm_external(vm, value);
+    http = njs_vm_external(vm, ngx_http_js_fetch_proto_id, value);
     if (http == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -2201,7 +2202,7 @@ ngx_response_js_ext_type(njs_vm_t *vm, n
 {
     ngx_js_http_t  *http;
 
-    http = njs_vm_external(vm, value);
+    http = njs_vm_external(vm, ngx_http_js_fetch_proto_id, value);
     if (http == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
diff -r 92cb9b80cf8b -r 42fdcacfd131 nginx/ngx_stream_js_module.c
--- a/nginx/ngx_stream_js_module.c	Fri Jul 09 14:01:26 2021 +0000
+++ b/nginx/ngx_stream_js_module.c	Fri Jul 09 19:14:23 2021 +0000
@@ -952,7 +952,7 @@ ngx_stream_js_ext_get_remote_address(njs
     ngx_connection_t      *c;
     ngx_stream_session_t  *s;
 
-    s = njs_vm_external(vm, value);
+    s = njs_vm_external(vm, ngx_stream_js_session_proto_id, value);
     if (s == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -974,7 +974,8 @@ ngx_stream_js_ext_done(njs_vm_t *vm, njs
     ngx_stream_js_ctx_t   *ctx;
     ngx_stream_session_t  *s;
 
-    s = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    s = njs_vm_external(vm, ngx_stream_js_session_proto_id,
+                        njs_argument(args, 0));
     if (s == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -1025,7 +1026,8 @@ ngx_stream_js_ext_on(njs_vm_t *vm, njs_v
     njs_vm_event_t        *event;
     ngx_stream_session_t  *s;
 
-    s = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    s = njs_vm_external(vm, ngx_stream_js_session_proto_id,
+                        njs_argument(args, 0));
     if (s == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -1072,7 +1074,8 @@ ngx_stream_js_ext_off(njs_vm_t *vm, njs_
     njs_vm_event_t        *event;
     ngx_stream_session_t  *s;
 
-    s = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    s = njs_vm_external(vm, ngx_stream_js_session_proto_id,
+                        njs_argument(args, 0));
     if (s == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -1115,7 +1118,8 @@ ngx_stream_js_ext_send(njs_vm_t *vm, njs
     static const njs_str_t last_key = njs_str("last");
     static const njs_str_t flush_key = njs_str("flush");
 
-    s = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    s = njs_vm_external(vm, ngx_stream_js_session_proto_id,
+                        njs_argument(args, 0));
     if (s == NULL) {
         njs_vm_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -1194,7 +1198,7 @@ ngx_stream_js_ext_variables(njs_vm_t *vm
     ngx_stream_core_main_conf_t  *cmcf;
     ngx_stream_variable_value_t  *vv;
 
-    s = njs_vm_external(vm, value);
+    s = njs_vm_external(vm, ngx_stream_js_session_proto_id, value);
     if (s == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
diff -r 92cb9b80cf8b -r 42fdcacfd131 src/njs.h
--- a/src/njs.h	Fri Jul 09 14:01:26 2021 +0000
+++ b/src/njs.h	Fri Jul 09 19:14:23 2021 +0000
@@ -299,12 +299,14 @@ NJS_EXPORT njs_int_t njs_vm_start(njs_vm
 
 NJS_EXPORT njs_int_t njs_vm_add_path(njs_vm_t *vm, const njs_str_t *path);
 
+#define NJS_PROTO_ID_ANY    (-1)
+
 NJS_EXPORT njs_int_t njs_vm_external_prototype(njs_vm_t *vm,
     const njs_external_t *definition, njs_uint_t n);
 NJS_EXPORT njs_int_t njs_vm_external_create(njs_vm_t *vm, njs_value_t *value,
     njs_int_t proto_id, njs_external_ptr_t external, njs_bool_t shared);
 NJS_EXPORT njs_external_ptr_t njs_vm_external(njs_vm_t *vm,
-    const njs_value_t *value);
+    njs_int_t proto_id, const njs_value_t *value);
 NJS_EXPORT uintptr_t njs_vm_meta(njs_vm_t *vm, njs_uint_t index);
 
 NJS_EXPORT njs_function_t *njs_vm_function_alloc(njs_vm_t *vm,
@@ -381,6 +383,7 @@ NJS_EXPORT void njs_value_number_set(njs
 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_int_t njs_value_external_tag(const njs_value_t *value);
 
 NJS_EXPORT uint16_t njs_vm_prop_magic16(njs_object_prop_t *prop);
 NJS_EXPORT uint32_t njs_vm_prop_magic32(njs_object_prop_t *prop);
diff -r 92cb9b80cf8b -r 42fdcacfd131 src/njs_extern.c
--- a/src/njs_extern.c	Fri Jul 09 14:01:26 2021 +0000
+++ b/src/njs_extern.c	Fri Jul 09 19:14:23 2021 +0000
@@ -179,7 +179,7 @@ njs_external_prop_handler(njs_vm_t *vm, 
         *retval = *setval;
 
     } else {
-        external = njs_vm_external(vm, value);
+        external = njs_vm_external(vm, NJS_PROTO_ID_ANY, value);
         if (njs_slow_path(external == NULL)) {
             njs_value_undefined_set(retval);
             return NJS_OK;
@@ -203,7 +203,7 @@ njs_external_prop_handler(njs_vm_t *vm, 
         ov->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object;
         ov->object.slots = slots;
 
-        njs_set_data(&ov->value, external, NJS_DATA_TAG_EXTERNAL);
+        njs_set_data(&ov->value, external, njs_value_external_tag(value));
         njs_set_object_value(retval, ov);
     }
 
@@ -332,18 +332,18 @@ njs_vm_external_create(njs_vm_t *vm, njs
     ov->object.slots = slots;
 
     njs_set_object_value(value, ov);
-    njs_set_data(&ov->value, external, NJS_DATA_TAG_EXTERNAL);
+    njs_set_data(&ov->value, external, njs_make_tag(proto_id));
 
     return NJS_OK;
 }
 
 
 njs_external_ptr_t
-njs_vm_external(njs_vm_t *vm, const njs_value_t *value)
+njs_vm_external(njs_vm_t *vm, njs_int_t proto_id, const njs_value_t *value)
 {
     njs_external_ptr_t  external;
 
-    if (njs_fast_path(njs_is_object_data(value, NJS_DATA_TAG_EXTERNAL))) {
+    if (njs_fast_path(njs_is_object_data(value, njs_make_tag(proto_id)))) {
         external = njs_object_data(value);
         if (external == NULL) {
             external = vm->external;
@@ -354,3 +354,14 @@ njs_vm_external(njs_vm_t *vm, const njs_
 
     return NULL;
 }
+
+
+njs_int_t
+njs_value_external_tag(const njs_value_t *value)
+{
+    if (njs_is_object_data(value, njs_make_tag(NJS_PROTO_ID_ANY))) {
+        return njs_object_value(value)->data.magic32;
+    }
+
+    return -1;
+}
diff -r 92cb9b80cf8b -r 42fdcacfd131 src/njs_shell.c
--- a/src/njs_shell.c	Fri Jul 09 14:01:26 2021 +0000
+++ b/src/njs_shell.c	Fri Jul 09 19:14:23 2021 +0000
@@ -202,6 +202,9 @@ static njs_vm_ops_t njs_console_ops = {
 };
 
 
+static njs_int_t      njs_console_proto_id;
+
+
 static njs_console_t  njs_console;
 
 
@@ -656,38 +659,6 @@ njs_console_init(njs_vm_t *vm, njs_conso
 }
 
 
-static njs_value_t *
-njs_external_add(njs_vm_t *vm, njs_external_t *definition,
-    njs_uint_t n, const njs_str_t *name, njs_external_ptr_t external)
-{
-    njs_int_t    ret, proto_id;
-    njs_value_t  *value;
-
-    proto_id = njs_vm_external_prototype(vm, definition, n);
-    if (njs_slow_path(proto_id < 0)) {
-        njs_stderror("failed to add \"%V\" proto\n", name);
-        return NULL;
-    }
-
-    value = njs_mp_zalloc(vm->mem_pool, sizeof(njs_opaque_value_t));
-    if (njs_slow_path(value == NULL)) {
-        return NULL;
-    }
-
-    ret = njs_vm_external_create(vm, value, proto_id, external, 0);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return NULL;
-    }
-
-    ret = njs_vm_bind(vm, name, value, 0);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return NULL;
-    }
-
-    return value;
-}
-
-
 static njs_int_t
 njs_externals_init(njs_vm_t *vm, njs_console_t *console)
 {
@@ -696,15 +667,31 @@ njs_externals_init(njs_vm_t *vm, njs_con
 
     static const njs_str_t  console_name = njs_str("console");
     static const njs_str_t  print_name = njs_str("print");
-    static const njs_value_t  string_log = njs_string("log");
+    static const njs_str_t  console_log = njs_str("console.log");
 
-    value = njs_external_add(vm, njs_ext_console, njs_nitems(njs_ext_console),
-                            &console_name, console);
+    njs_console_proto_id = njs_vm_external_prototype(vm, njs_ext_console,
+                                         njs_nitems(njs_ext_console));
+    if (njs_slow_path(njs_console_proto_id < 0)) {
+        njs_stderror("failed to add \"console\" proto\n");
+        return NJS_ERROR;
+    }
+
+    value = njs_mp_zalloc(vm->mem_pool, sizeof(njs_opaque_value_t));
     if (njs_slow_path(value == NULL)) {
         return NJS_ERROR;
     }
 
-    ret = njs_value_property(vm, value, njs_value_arg(&string_log), &method);
+    ret = njs_vm_external_create(vm, value, njs_console_proto_id, console, 0);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_vm_bind(vm, &console_name, value, 0);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_vm_value(vm, &console_log, &method);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
@@ -1169,13 +1156,13 @@ njs_ext_console_time(njs_vm_t *vm, njs_v
     njs_index_t unused)
 {
     njs_int_t           ret;
-    njs_console_t       *console;
+    njs_str_t           name;
     njs_value_t         *value;
+    njs_console_t       *console;
     njs_timelabel_t     *label;
-    njs_str_t           name;
     njs_lvlhsh_query_t  lhq;
 
-    console = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    console = njs_vm_external(vm, njs_console_proto_id, njs_argument(args, 0));
     if (njs_slow_path(console == NULL)) {
         njs_type_error(vm, "external value is expected");
         return NJS_ERROR;
@@ -1244,15 +1231,15 @@ njs_ext_console_time_end(njs_vm_t *vm, n
 {
     uint64_t            ns, ms;
     njs_int_t           ret;
-    njs_console_t       *console;
+    njs_str_t           name;
     njs_value_t         *value;
+    njs_console_t       *console;
     njs_timelabel_t     *label;
-    njs_str_t           name;
     njs_lvlhsh_query_t  lhq;
 
     ns = njs_time();
 
-    console = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    console = njs_vm_external(vm, njs_console_proto_id, njs_argument(args, 0));
     if (njs_slow_path(console == NULL)) {
         njs_type_error(vm, "external value is expected");
         return NJS_ERROR;
diff -r 92cb9b80cf8b -r 42fdcacfd131 src/njs_value.h
--- a/src/njs_value.h	Fri Jul 09 14:01:26 2021 +0000
+++ b/src/njs_value.h	Fri Jul 09 19:14:23 2021 +0000
@@ -594,8 +594,14 @@ typedef struct {
     ((value)->type <= NJS_STRING)
 
 
+#define njs_make_tag(proto_id)                                                \
+    (((njs_uint_t) proto_id << 8) | NJS_DATA_TAG_EXTERNAL)
+
+
 #define njs_is_data(value, tag)                                               \
-    ((value)->type == NJS_DATA && value->data.magic32 == (tag))
+    ((value)->type == NJS_DATA                                                \
+     && ((tag) == njs_make_tag(NJS_PROTO_ID_ANY)                              \
+         || value->data.magic32 == (tag)))
 
 
 #define njs_is_object(value)                                                  \
diff -r 92cb9b80cf8b -r 42fdcacfd131 src/test/njs_externals_test.c
--- a/src/test/njs_externals_test.c	Fri Jul 09 14:01:26 2021 +0000
+++ b/src/test/njs_externals_test.c	Fri Jul 09 19:14:23 2021 +0000
@@ -11,7 +11,6 @@
 
 typedef struct {
     njs_lvlhsh_t          hash;
-    njs_int_t             proto_id;
 
     uint32_t              a;
     uint32_t              d;
@@ -27,6 +26,9 @@ typedef struct {
 } njs_unit_test_prop_t;
 
 
+static njs_int_t    njs_external_r_proto_id;
+
+
 static njs_int_t
 lvlhsh_unit_test_key_test(njs_lvlhsh_query_t *lhq, void *data)
 {
@@ -121,7 +123,7 @@ njs_unit_test_r_uri(njs_vm_t *vm, njs_ob
     char       *p;
     njs_str_t  *field;
 
-    p = njs_vm_external(vm, value);
+    p = njs_vm_external(vm, njs_external_r_proto_id, value);
     if (p == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -145,7 +147,7 @@ njs_unit_test_r_a(njs_vm_t *vm, njs_obje
     njs_unit_test_req_t  *r;
     u_char               buf[16];
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, njs_external_r_proto_id, value);
     if (r == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -173,7 +175,7 @@ njs_unit_test_r_d(njs_vm_t *vm, njs_obje
 {
     njs_unit_test_req_t  *r;
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, njs_external_r_proto_id, value);
     if (r == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -211,7 +213,7 @@ njs_unit_test_r_vars(njs_vm_t *vm, njs_o
     njs_unit_test_req_t   *r;
     njs_unit_test_prop_t  *prop;
 
-    r = njs_vm_external(vm, value);
+    r = njs_vm_external(vm, njs_external_r_proto_id, value);
     if (r == NULL) {
         njs_value_undefined_set(retval);
         return NJS_DECLINED;
@@ -352,7 +354,7 @@ njs_unit_test_r_method(njs_vm_t *vm, njs
     njs_str_t            s;
     njs_unit_test_req_t  *r;
 
-    r = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    r = njs_vm_external(vm, njs_external_r_proto_id, njs_argument(args, 0));
     if (r == NULL) {
         njs_type_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -377,7 +379,7 @@ njs_unit_test_r_create(njs_vm_t *vm, njs
     njs_int_t            ret;
     njs_unit_test_req_t  *r, *sr;
 
-    r = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    r = njs_vm_external(vm, njs_external_r_proto_id, njs_argument(args, 0));
     if (r == NULL) {
         njs_type_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -394,9 +396,8 @@ njs_unit_test_r_create(njs_vm_t *vm, njs
         return NJS_ERROR;
     }
 
-    sr->proto_id = r->proto_id;
-
-    ret = njs_vm_external_create(vm, &vm->retval, sr->proto_id, sr, 0);
+    ret = njs_vm_external_create(vm, &vm->retval, njs_external_r_proto_id,
+                                 sr, 0);
     if (ret != NJS_OK) {
         return NJS_ERROR;
     }
@@ -418,7 +419,7 @@ njs_unit_test_r_bind(njs_vm_t *vm, njs_v
     njs_str_t            name;
     njs_unit_test_req_t  *r;
 
-    r = njs_vm_external(vm, njs_arg(args, nargs, 0));
+    r = njs_vm_external(vm, njs_external_r_proto_id, njs_argument(args, 0));
     if (r == NULL) {
         njs_type_error(vm, "\"this\" is not an external");
         return NJS_ERROR;
@@ -679,45 +680,46 @@ static njs_unit_test_req_init_t njs_test
 
 
 static njs_int_t
-njs_externals_init_internal(njs_vm_t *vm, njs_int_t proto_id,
-    njs_unit_test_req_init_t *init, njs_uint_t n, njs_bool_t shared)
+njs_externals_init_internal(njs_vm_t *vm, njs_unit_test_req_init_t *init,
+    njs_uint_t n, njs_bool_t shared)
 {
     njs_int_t             ret;
     njs_uint_t            i, j;
     njs_unit_test_req_t   *requests;
     njs_unit_test_prop_t  *prop;
 
-    if (proto_id == -1) {
-        proto_id = njs_vm_external_prototype(vm, njs_unit_test_r_external,
+    if (shared) {
+        njs_external_r_proto_id = njs_vm_external_prototype(vm,
+                                         njs_unit_test_r_external,
                                          njs_nitems(njs_unit_test_r_external));
-        if (njs_slow_path(proto_id < 0)) {
+        if (njs_slow_path(njs_external_r_proto_id < 0)) {
             njs_printf("njs_vm_external_prototype() failed\n");
-            return -1;
+            return NJS_ERROR;
         }
     }
 
     requests = njs_mp_zalloc(vm->mem_pool, n * sizeof(njs_unit_test_req_t));
     if (njs_slow_path(requests == NULL)) {
-        return -1;
+        return NJS_ERROR;
     }
 
     for (i = 0; i < n; i++) {
 
         requests[i] = init[i].request;
-        requests[i].proto_id = proto_id;
 
         ret = njs_vm_external_create(vm, njs_value_arg(&requests[i].value),
-                                     proto_id, &requests[i], shared);
+                                     njs_external_r_proto_id, &requests[i],
+                                     shared);
         if (njs_slow_path(ret != NJS_OK)) {
             njs_printf("njs_vm_external_create() failed\n");
-            return -1;
+            return NJS_ERROR;
         }
 
         ret = njs_vm_bind(vm, &init[i].name, njs_value_arg(&requests[i].value),
                           shared);
         if (njs_slow_path(ret != NJS_OK)) {
             njs_printf("njs_vm_bind() failed\n");
-            return -1;
+            return NJS_ERROR;
         }
 
         for (j = 0; j < njs_nitems(init[i].props); j++) {
@@ -726,36 +728,30 @@ njs_externals_init_internal(njs_vm_t *vm
 
             if (njs_slow_path(prop == NULL)) {
                 njs_printf("lvlhsh_unit_test_alloc() failed\n");
-                return -1;
+                return NJS_ERROR;
             }
 
             ret = lvlhsh_unit_test_add(vm->mem_pool, &requests[i], prop);
             if (njs_slow_path(ret != NJS_OK)) {
                 njs_printf("lvlhsh_unit_test_add() failed\n");
-                return -1;
+                return NJS_ERROR;
             }
         }
     }
 
-    return proto_id;
+    return NJS_OK;
 }
 
 
 njs_int_t
 njs_externals_shared_init(njs_vm_t *vm)
 {
-    return njs_externals_init_internal(vm, -1, njs_test_requests, 1, 1);
+    return njs_externals_init_internal(vm, njs_test_requests, 1, 1);
 }
 
 
 njs_int_t
-njs_externals_init(njs_vm_t *vm, njs_int_t proto_id)
+njs_externals_init(njs_vm_t *vm)
 {
-    proto_id = njs_externals_init_internal(vm, proto_id, &njs_test_requests[1],
-                                        3, 0);
-    if (proto_id < 0) {
-        return NJS_ERROR;
-    }
-
-    return NJS_OK;
+    return njs_externals_init_internal(vm, &njs_test_requests[1], 3, 0);
 }
diff -r 92cb9b80cf8b -r 42fdcacfd131 src/test/njs_externals_test.h
--- a/src/test/njs_externals_test.h	Fri Jul 09 14:01:26 2021 +0000
+++ b/src/test/njs_externals_test.h	Fri Jul 09 19:14:23 2021 +0000
@@ -9,7 +9,7 @@
 
 
 njs_int_t njs_externals_shared_init(njs_vm_t *vm);
-njs_int_t njs_externals_init(njs_vm_t *vm, njs_int_t proto_id);
+njs_int_t njs_externals_init(njs_vm_t *vm);
 
 
 #endif /* _NJS_EXTERNALS_TEST_H_INCLUDED_ */
diff -r 92cb9b80cf8b -r 42fdcacfd131 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Fri Jul 09 14:01:26 2021 +0000
+++ b/src/test/njs_unit_test.c	Fri Jul 09 19:14:23 2021 +0000
@@ -20624,6 +20624,9 @@ static njs_unit_test_t  njs_externals_te
     { njs_str("$r.create('XXX').uri"),
       njs_str("XXX") },
 
+    { njs_str("$r.create.call([], 'XXX')"),
+      njs_str("TypeError: \"this\" is not an external") },
+
     { njs_str("var sr = $r.create('XXX'); sr.uri = 'YYY'; sr.uri"),
       njs_str("YYY") },
 
@@ -21198,9 +21201,9 @@ static njs_unit_test_t  njs_shell_test[]
               "    at eval (native)\n"
               "    at main (:1)\n") },
 
-    { njs_str("$r.method({}.a.a)" ENTER),
+    { njs_str("$shared.method({}.a.a)" ENTER),
       njs_str("TypeError: cannot get property \"a\" of undefined\n"
-              "    at $r3.method (native)\n"
+              "    at $shared.method (native)\n"
               "    at main (:1)\n") },
 
     { njs_str("new Function(\n\n@)" ENTER),
@@ -21372,7 +21375,7 @@ njs_unit_test(njs_unit_test_t tests[], s
 {
     u_char        *start, *end;
     njs_vm_t      *vm, *nvm;
-    njs_int_t     ret, proto_id;
+    njs_int_t     ret;
     njs_str_t     s;
     njs_uint_t    i, repeat;
     njs_stat_t    prev;
@@ -21381,7 +21384,6 @@ njs_unit_test(njs_unit_test_t tests[], s
 
     vm = NULL;
     nvm = NULL;
-    proto_id = -1;
 
     prev = *stat;
 
@@ -21405,8 +21407,8 @@ njs_unit_test(njs_unit_test_t tests[], s
         }
 
         if (opts->externals) {
-            proto_id = njs_externals_shared_init(vm);
-            if (proto_id < 0) {
+            ret = njs_externals_shared_init(vm);
+            if (ret != NJS_OK) {
                 goto done;
             }
         }
@@ -21435,7 +21437,7 @@ njs_unit_test(njs_unit_test_t tests[], s
                 }
 
                 if (opts->externals) {
-                    ret = njs_externals_init(nvm, proto_id);
+                    ret = njs_externals_init(nvm);
                     if (ret != NJS_OK) {
                         goto done;
                     }
@@ -21539,7 +21541,12 @@ njs_interactive_test(njs_unit_test_t tes
         }
 
         if (opts->externals) {
-            ret = njs_externals_init(vm, -1);
+            ret = njs_externals_shared_init(vm);
+            if (ret != NJS_OK) {
+                goto done;
+            }
+
+            ret = njs_externals_init(vm);
             if (ret != NJS_OK) {
                 goto done;
             }


More information about the nginx-devel mailing list