[njs] QueryString: module is rewritten using public API.

Dmitry Volyntsev xeioex at nginx.com
Wed May 3 04:13:31 UTC 2023


details:   https://hg.nginx.org/njs/rev/fd956d2a25a3
branches:  
changeset: 2101:fd956d2a25a3
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue May 02 20:50:55 2023 -0700
description:
QueryString: module is rewritten using public API.

diffstat:

 external/njs_query_string_module.c |  561 +++++++++++++++---------------------
 src/njs.h                          |    8 +
 src/njs_value.c                    |   17 +
 src/njs_value_conversion.h         |   25 -
 src/njs_vm.c                       |   25 +
 src/test/njs_unit_test.c           |   10 +-
 6 files changed, 289 insertions(+), 357 deletions(-)

diffs (truncated from 1114 to 1000 lines):

diff -r b2cbf06ba017 -r fd956d2a25a3 external/njs_query_string_module.c
--- a/external/njs_query_string_module.c	Tue May 02 20:50:52 2023 -0700
+++ b/external/njs_query_string_module.c	Tue May 02 20:50:55 2023 -0700
@@ -6,7 +6,8 @@
  */
 
 
-#include <njs_main.h>
+#include <njs.h>
+#include <njs_string.h>
 
 
 static njs_int_t njs_query_string_parser(njs_vm_t *vm, u_char *query,
@@ -108,48 +109,15 @@ njs_module_t  njs_query_string_module = 
 };
 
 
-static const njs_value_t  njs_escape_str = njs_string("escape");
-static const njs_value_t  njs_unescape_str = njs_string("unescape");
-static const njs_value_t  njs_encode_uri_str =
-                                         njs_long_string("encodeURIComponent");
-static const njs_value_t  njs_decode_uri_str =
-                                         njs_long_string("decodeURIComponent");
-static const njs_value_t  njs_max_keys_str = njs_string("maxKeys");
+static const njs_str_t  njs_escape_str = njs_str("escape");
+static const njs_str_t  njs_unescape_str = njs_str("unescape");
+static const njs_str_t  njs_encode_uri_str = njs_str("encodeURIComponent");
+static const njs_str_t  njs_decode_uri_str = njs_str("decodeURIComponent");
+static const njs_str_t  njs_max_keys_str = njs_str("maxKeys");
 
 static const njs_str_t njs_sep_default = njs_str("&");
 static const njs_str_t njs_eq_default = njs_str("=");
 
-static const njs_value_t  njs_unescape_default =
-    njs_native_function(njs_query_string_unescape, 1);
-
-
-static njs_object_t *
-njs_query_string_object_alloc(njs_vm_t *vm)
-{
-    njs_object_t  *obj;
-
-    obj = njs_mp_alloc(vm->mem_pool, sizeof(njs_object_t));
-
-    if (njs_fast_path(obj != NULL)) {
-        njs_lvlhsh_init(&obj->hash);
-        njs_lvlhsh_init(&obj->shared_hash);
-        obj->type = NJS_OBJECT;
-        obj->shared = 0;
-        obj->extensible = 1;
-        obj->error_data = 0;
-        obj->fast_array = 0;
-
-        obj->__proto__ = NULL;
-        obj->slots = NULL;
-
-        return obj;
-    }
-
-    njs_memory_error(vm);
-
-    return NULL;
-}
-
 
 static njs_int_t
 njs_query_string_decode(njs_vm_t *vm, njs_value_t *value, const u_char *start,
@@ -157,7 +125,6 @@ njs_query_string_decode(njs_vm_t *vm, nj
 {
     u_char                *dst;
     size_t                length;
-    ssize_t               str_size;
     uint32_t              cp;
     njs_int_t             ret;
     njs_chb_t             chain;
@@ -185,7 +152,7 @@ njs_query_string_decode(njs_vm_t *vm, nj
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     };
 
-    njs_chb_init(&chain, vm->mem_pool);
+    njs_chb_init(&chain, njs_vm_memory_pool(vm));
     njs_utf8_decode_init(&ctx);
 
     cp = 0;
@@ -240,21 +207,7 @@ njs_query_string_decode(njs_vm_t *vm, nj
         length++;
     }
 
-    str_size = njs_chb_size(&chain);
-    if (njs_slow_path(str_size < 0)) {
-        goto failed;
-    }
-
-    dst = njs_string_alloc(vm, value, str_size, length);
-    if (njs_slow_path(dst == NULL)) {
-        goto failed;
-    }
-
-    njs_chb_join_to(&chain, dst);
-
-    ret = NJS_OK;
-
-failed:
+    ret = njs_vm_value_string_create_chb(vm, value, &chain);
 
     njs_chb_destroy(&chain);
 
@@ -265,7 +218,18 @@ failed:
 njs_inline njs_bool_t
 njs_query_string_is_native_decoder(njs_function_t *decoder)
 {
-    return decoder->native && decoder->u.native == njs_query_string_unescape;
+    njs_opaque_value_t     function;
+    njs_function_native_t  native;
+
+    if (decoder == NULL) {
+        return 1;
+    }
+
+    njs_value_function_set(njs_value_arg(&function), decoder);
+
+    native = njs_value_native_function(njs_value_arg(&function));
+
+    return native == njs_query_string_unescape;
 }
 
 
@@ -274,80 +238,107 @@ njs_query_string_append(njs_vm_t *vm, nj
     size_t key_size, const u_char *val, size_t val_size,
     njs_function_t *decoder)
 {
-    uint32_t     key_length, val_length;
-    njs_int_t    ret;
-    njs_array_t  *array;
-    njs_value_t  name, value, retval;
+    njs_int_t           ret;
+    njs_value_t         *push;
+    njs_opaque_value_t  array, name, value, retval;
 
     if (njs_query_string_is_native_decoder(decoder)) {
-        ret = njs_query_string_decode(vm, &name, key, key_size);
+        ret = njs_query_string_decode(vm, njs_value_arg(&name), key, key_size);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
 
-        ret = njs_query_string_decode(vm, &value, val, val_size);
+        ret = njs_query_string_decode(vm, njs_value_arg(&value), val, val_size);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
 
     } else {
 
-        key_length = njs_max(njs_utf8_length(key, key_size), 0);
-        ret = njs_string_new(vm, &name, key, key_size, key_length);
+        ret = njs_vm_value_string_create(vm, njs_value_arg(&name), key,
+                                         key_size);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
 
         if (key_size > 0) {
-            ret = njs_function_call(vm, decoder, &njs_value_undefined, &name, 1,
-                                    &name);
+            ret = njs_vm_invoke(vm, decoder, njs_value_arg(&name), 1,
+                                njs_value_arg(&name));
             if (njs_slow_path(ret != NJS_OK)) {
                 return ret;
             }
 
-            if (!njs_is_string(&name)) {
-                njs_value_to_string(vm, &name, &name);
+            if (!njs_value_is_string(njs_value_arg(&name))) {
+                ret = njs_value_to_string(vm, njs_value_arg(&name),
+                                          njs_value_arg(&name));
+                if (njs_slow_path(ret != NJS_OK)) {
+                    return ret;
+                }
             }
         }
 
-        val_length = njs_max(njs_utf8_length(val, val_size), 0);
-        ret = njs_string_new(vm, &value, val, val_size, val_length);
+        ret = njs_vm_value_string_create(vm, njs_value_arg(&value), val,
+                                         val_size);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
 
         if (val_size > 0) {
-            ret = njs_function_call(vm, decoder, &njs_value_undefined, &value,
-                                    1, &value);
+            ret = njs_vm_invoke(vm, decoder, njs_value_arg(&value), 1,
+                                njs_value_arg(&value));
             if (njs_slow_path(ret != NJS_OK)) {
                 return ret;
             }
 
-            if (!njs_is_string(&value)) {
-                njs_value_to_string(vm, &value, &value);
+            if (!njs_value_is_string(njs_value_arg(&value))) {
+                ret = njs_value_to_string(vm, njs_value_arg(&value),
+                                          njs_value_arg(&value));
+                if (njs_slow_path(ret != NJS_OK)) {
+                    return ret;
+                }
             }
         }
     }
 
-    ret = njs_value_property(vm, object, &name, &retval);
+    ret = njs_value_property(vm, object, njs_value_arg(&name),
+                             njs_value_arg(&retval));
 
     if (ret == NJS_OK) {
-        if (njs_is_array(&retval)) {
-            return njs_array_add(vm, njs_array(&retval), &value);
+        if (njs_value_is_array(njs_value_arg(&retval))) {
+            push = njs_vm_array_push(vm, njs_value_arg(&retval));
+            if (njs_slow_path(push == NULL)) {
+                return NJS_ERROR;
+            }
+
+            njs_value_assign(push, njs_value_arg(&value));
+
+            return NJS_OK;
         }
 
-        array = njs_array_alloc(vm, 1, 2, 0);
-        if (njs_slow_path(array == NULL)) {
+        ret = njs_vm_array_alloc(vm, njs_value_arg(&array), 2);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return ret;
+        }
+
+        push = njs_vm_array_push(vm, njs_value_arg(&array));
+        if (njs_slow_path(push == NULL)) {
             return NJS_ERROR;
         }
 
-        array->start[0] = retval;
-        array->start[1] = value;
+        njs_value_assign(push, njs_value_arg(&retval));
 
-        njs_set_array(&value, array);
+        push = njs_vm_array_push(vm, njs_value_arg(&array));
+        if (njs_slow_path(push == NULL)) {
+            return NJS_ERROR;
+        }
+
+        njs_value_assign(push, njs_value_arg(&value));
+
+        njs_value_assign(&value, &array);
     }
 
-    return njs_value_property_set(vm, object, &name, &value);
+    return njs_value_property_set(vm, object, njs_value_arg(&name),
+                                  njs_value_arg(&value));
 }
 
 
@@ -384,12 +375,12 @@ static njs_int_t
 njs_query_string_parse(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused, njs_value_t *retval)
 {
-    int64_t         max_keys;
-    njs_int_t       ret;
-    njs_str_t       str, sep, eq;
-    njs_value_t     value, *this, *string, *options, *arg;
-    njs_value_t     val_sep, val_eq;
-    njs_function_t  *decode;
+    int64_t             max_keys;
+    njs_int_t           ret;
+    njs_str_t           str, sep, eq;
+    njs_value_t         *this, *string, *options, *arg, *val;
+    njs_function_t      *decode;
+    njs_opaque_value_t  value, val_sep, val_eq;
 
     decode = NULL;
     max_keys = 1000;
@@ -397,8 +388,8 @@ njs_query_string_parse(njs_vm_t *vm, njs
     this = njs_argument(args, 0);
     string = njs_arg(args, nargs, 1);
 
-    if (njs_is_string(string)) {
-        njs_string_get(string, &str);
+    if (njs_value_is_string(string)) {
+        njs_value_string_get(string, &str);
 
     } else {
         str = njs_str_value("");
@@ -408,71 +399,68 @@ njs_query_string_parse(njs_vm_t *vm, njs
     eq = njs_eq_default;
 
     arg = njs_arg(args, nargs, 2);
-    if (!njs_is_null_or_undefined(arg)) {
-        ret = njs_value_to_string(vm, &val_sep, arg);
+    if (!njs_value_is_null_or_undefined(arg)) {
+        ret = njs_value_to_string(vm, njs_value_arg(&val_sep), arg);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
 
-        if (njs_string_length(&val_sep) != 0) {
-            njs_string_get(&val_sep, &sep);
+        if (njs_string_length(njs_value_arg(&val_sep)) != 0) {
+            njs_value_string_get(njs_value_arg(&val_sep), &sep);
         }
     }
 
     arg = njs_arg(args, nargs, 3);
-    if (!njs_is_null_or_undefined(arg)) {
-        ret = njs_value_to_string(vm, &val_eq, arg);
+    if (!njs_value_is_null_or_undefined(arg)) {
+        ret = njs_value_to_string(vm, njs_value_arg(&val_eq), arg);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
 
-        if (njs_string_length(&val_eq) != 0) {
-            njs_string_get(&val_eq, &eq);
+        if (njs_string_length(njs_value_arg(&val_eq)) != 0) {
+            njs_value_string_get(njs_value_arg(&val_eq), &eq);
         }
     }
 
     options = njs_arg(args, nargs, 4);
 
-    if (njs_is_object(options)) {
-        ret = njs_value_property(vm, options, njs_value_arg(&njs_max_keys_str),
-                                 &value);
-        if (njs_slow_path(ret == NJS_ERROR)) {
-            return ret;
-        }
-
-        ret = njs_value_to_integer(vm, &value, &max_keys);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
+    if (njs_value_is_object(options)) {
+        val = njs_vm_object_prop(vm, options, &njs_max_keys_str, &value);
 
-        if (max_keys == 0) {
-            max_keys = INT64_MAX;
-        }
-
-        ret = njs_value_property(vm, options,
-                                 njs_value_arg(&njs_decode_uri_str), &value);
-
-        if (ret == NJS_OK) {
-            if (njs_slow_path(!njs_is_function(&value))) {
-                njs_type_error(vm,
-                               "option decodeURIComponent is not a function");
+        if (val != NULL) {
+            if (!njs_value_is_valid_number(val)) {
+                njs_vm_error(vm, "is not a number");
                 return NJS_ERROR;
             }
 
-            decode = njs_function(&value);
+            max_keys = njs_value_number(val);
+
+            if (max_keys == 0) {
+                max_keys = INT64_MAX;
+            }
+        }
+
+        val = njs_vm_object_prop(vm, options, &njs_decode_uri_str, &value);
+
+        if (val != NULL) {
+            if (njs_slow_path(!njs_value_is_function(val))) {
+                njs_vm_error(vm, "option decodeURIComponent is not a function");
+                return NJS_ERROR;
+            }
+
+            decode = njs_value_function(val);
         }
     }
 
     if (decode == NULL) {
-        ret = njs_value_property(vm, this, njs_value_arg(&njs_unescape_str),
-                                 &value);
+        val = njs_vm_object_prop(vm, this, &njs_unescape_str, &value);
 
-        if (ret != NJS_OK || !njs_is_function(&value)) {
-            njs_type_error(vm, "QueryString.unescape is not a function");
+        if (val == NULL || !njs_value_is_function(val)) {
+            njs_vm_error(vm, "QueryString.unescape is not a function");
             return NJS_ERROR;
         }
 
-        decode = njs_function(&value);
+        decode = njs_value_function(val);
     }
 
     return njs_query_string_parser(vm, str.start, str.start + str.length,
@@ -485,9 +473,7 @@ njs_vm_query_string_parse(njs_vm_t *vm, 
     njs_value_t *retval)
 {
     return njs_query_string_parser(vm, start, end, &njs_sep_default,
-                                   &njs_eq_default,
-                                   njs_function(&njs_unescape_default),
-                                   1000, retval);
+                                   &njs_eq_default, NULL, 1000, retval);
 }
 
 
@@ -496,20 +482,16 @@ njs_query_string_parser(njs_vm_t *vm, u_
     const njs_str_t *sep, const njs_str_t *eq, njs_function_t *decode,
     njs_uint_t max_keys, njs_value_t *retval)
 {
-    size_t        size;
-    u_char        *part, *key, *val;
-    njs_int_t     ret;
-    njs_uint_t    count;
-    njs_value_t   obj;
-    njs_object_t  *object;
+    size_t      size;
+    u_char      *part, *key, *val;
+    njs_int_t   ret;
+    njs_uint_t  count;
 
-    object = njs_query_string_object_alloc(vm);
-    if (njs_slow_path(object == NULL)) {
+    ret = njs_vm_object_alloc(vm, retval, NULL);
+    if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
-    njs_set_object(&obj, object);
-
     count = 0;
 
     key = query;
@@ -533,7 +515,7 @@ njs_query_string_parser(njs_vm_t *vm, u_
             val += eq->length;
         }
 
-        ret = njs_query_string_append(vm, &obj, key, size, val, part - val,
+        ret = njs_query_string_append(vm, retval, key, size, val, part - val,
                                       decode);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
@@ -545,8 +527,6 @@ njs_query_string_parser(njs_vm_t *vm, u_
 
     } while (key < end);
 
-    njs_set_object(retval, object);
-
     return NJS_OK;
 }
 
@@ -580,7 +560,7 @@ njs_query_string_encode(njs_chb_t *chain
     }
 
     if (str->length == 0) {
-        return 0;
+        return NJS_OK;
     }
 
     p = str->start;
@@ -601,21 +581,26 @@ njs_query_string_encode(njs_chb_t *chain
     if (size == str->length) {
         memcpy(start, str->start, str->length);
         njs_chb_written(chain, str->length);
-        return str->length;
+        return NJS_OK;
     }
 
     (void) njs_string_encode(escape, str->length, str->start, start);
 
     njs_chb_written(chain, size);
 
-    return size;
+    return NJS_OK;
 }
 
 
 njs_inline njs_bool_t
 njs_query_string_is_native_encoder(njs_function_t *encoder)
 {
-    return encoder->native && encoder->u.native == njs_query_string_escape;
+    njs_opaque_value_t  function;
+
+    njs_value_function_set(njs_value_arg(&function), encoder);
+
+    return njs_value_native_function(njs_value_arg(&function))
+                                                   == njs_query_string_escape;
 }
 
 
@@ -623,11 +608,11 @@ njs_inline njs_int_t
 njs_query_string_encoder_call(njs_vm_t *vm, njs_chb_t *chain,
     njs_function_t *encoder, njs_value_t *string)
 {
-    njs_str_t    str;
-    njs_int_t    ret;
-    njs_value_t  retval;
+    njs_str_t           str;
+    njs_int_t           ret;
+    njs_opaque_value_t  retval;
 
-    if (njs_slow_path(!njs_is_string(string))) {
+    if (njs_slow_path(!njs_value_is_string(string))) {
         ret = njs_value_to_string(vm, string, string);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
@@ -635,87 +620,62 @@ njs_query_string_encoder_call(njs_vm_t *
     }
 
     if (njs_fast_path(njs_query_string_is_native_encoder(encoder))) {
-        njs_string_get(string, &str);
+        njs_value_string_get(string, &str);
         return njs_query_string_encode(chain, &str);
     }
 
-    ret = njs_function_call(vm, encoder, &njs_value_undefined, string, 1,
-                            &retval);
+    ret = njs_vm_invoke(vm, encoder, string, 1, njs_value_arg(&retval));
     if (njs_slow_path(ret != NJS_OK)) {
-        return NJS_ERROR;
+        return ret;
     }
 
-    if (njs_slow_path(!njs_is_string(&retval))) {
-        ret = njs_value_to_string(vm, &retval, &retval);
+    if (njs_slow_path(!njs_value_is_string(njs_value_arg(&retval)))) {
+        ret = njs_value_to_string(vm, njs_value_arg(&retval),
+                                  njs_value_arg(&retval));
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
     }
 
-    njs_string_get(&retval, &str);
-
-    ret = njs_utf8_length(str.start, str.length);
-    if (ret < 0) {
-        njs_type_error(vm, "got non-UTF8 string from encoder");
-        return NJS_ERROR;
-    }
+    njs_value_string_get(njs_value_arg(&retval), &str);
 
     njs_chb_append_str(chain, &str);
 
-    return ret;
+    return NJS_OK;
 }
 
 
 njs_inline njs_int_t
 njs_query_string_push(njs_vm_t *vm, njs_chb_t *chain, njs_value_t *key,
-    njs_value_t *value, njs_string_prop_t *eq, njs_function_t *encoder)
+    njs_value_t *value, njs_str_t *eq, njs_function_t *encoder)
 {
-    double     num;
-    njs_int_t  ret, length;
-
-    length = 0;
+    njs_int_t  ret;
 
     ret = njs_query_string_encoder_call(vm, chain, encoder, key);
-    if (njs_slow_path(ret < 0)) {
+    if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
-    length += ret;
-
-    njs_chb_append(chain, eq->start, eq->size);
-    length += eq->length;
+    njs_chb_append(chain, eq->start, eq->length);
 
-    switch (value->type) {
-    case NJS_NUMBER:
-        num = njs_number(value);
-        if (njs_slow_path(isnan(num) || isinf(num))) {
-            break;
+    if (njs_value_is_valid_number(value)
+        || njs_value_is_boolean(value)
+        || njs_value_is_string(value))
+    {
+        if (!njs_value_is_string(value)) {
+            ret = njs_value_to_string(vm, value, value);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return NJS_ERROR;
+            }
         }
 
-        /* Fall through. */
-
-    case NJS_BOOLEAN:
-        ret = njs_primitive_value_to_string(vm, value, value);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return NJS_ERROR;
-        }
-
-        /* Fall through. */
-
-    case NJS_STRING:
         ret = njs_query_string_encoder_call(vm, chain, encoder, value);
         if (njs_slow_path(ret < 0)) {
             return NJS_ERROR;
         }
-
-        length += ret;
-        break;
-
-    default:
-        break;
     }
 
-    return length;
+    return NJS_OK;
 }
 
 
@@ -723,183 +683,137 @@ static njs_int_t
 njs_query_string_stringify(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused, njs_value_t *retval)
 {
-    u_char             *p;
-    int64_t            len;
-    ssize_t            size;
-    uint32_t           n, i;
-    uint64_t           length;
-    njs_int_t          ret;
-    njs_chb_t          chain;
-    njs_value_t        value, result, *string, *this, *object, *arg, *options;
-    njs_array_t        *keys, *array;
-    njs_function_t     *encode;
-    njs_string_prop_t  sep, eq;
-
-    njs_value_t  val_sep = njs_string("&");
-    njs_value_t  val_eq = njs_string("=");
-
-    (void) njs_string_prop(&sep, &val_sep);
-    (void) njs_string_prop(&eq, &val_eq);
+    int64_t             len, keys_length;
+    uint32_t            n, i;
+    njs_int_t           ret;
+    njs_str_t           sep, eq;
+    njs_chb_t           chain;
+    njs_value_t         *this, *object, *arg, *options, *val, *keys;
+    njs_function_t      *encode;
+    njs_opaque_value_t  value, result, key, *string;
 
     encode = NULL;
+    sep = njs_sep_default;
+    eq = njs_eq_default;
+
     this = njs_argument(args, 0);
     object = njs_arg(args, nargs, 1);
 
-    if (njs_slow_path(!njs_is_object(object))) {
-        njs_value_assign(retval, &njs_string_empty);
+    if (njs_slow_path(!njs_value_is_object(object))) {
+        njs_vm_value_string_set(vm, retval, (u_char *) "", 0);
         return NJS_OK;
     }
 
     arg = njs_arg(args, nargs, 2);
-    if (!njs_is_null_or_undefined(arg)) {
+    if (!njs_value_is_null_or_undefined(arg)) {
         ret = njs_value_to_string(vm, arg, arg);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
 
         if (njs_string_length(arg) > 0) {
-            (void) njs_string_prop(&sep, arg);
+            njs_value_string_get(arg, &sep);
         }
     }
 
     arg = njs_arg(args, nargs, 3);
-    if (!njs_is_null_or_undefined(arg)) {
+    if (!njs_value_is_null_or_undefined(arg)) {
         ret = njs_value_to_string(vm, arg, arg);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
 
         if (njs_string_length(arg) > 0) {
-            (void) njs_string_prop(&eq, arg);
+            njs_value_string_get(arg, &eq);
         }
     }
 
     options = njs_arg(args, nargs, 4);
 
-    if (njs_is_object(options)) {
-        ret = njs_value_property(vm, options,
-                                 njs_value_arg(&njs_encode_uri_str), &value);
+    if (njs_value_is_object(options)) {
+        val = njs_vm_object_prop(vm, options, &njs_encode_uri_str, &value);
 
-        if (ret == NJS_OK) {
-            if (njs_slow_path(!njs_is_function(&value))) {
-                njs_type_error(vm,
-                               "option encodeURIComponent is not a function");
+        if (val != NULL) {
+            if (njs_slow_path(!njs_value_is_function(val))) {
+                njs_vm_error(vm, "option encodeURIComponent is not a function");
                 return NJS_ERROR;
             }
 
-            encode = njs_function(&value);
+            encode = njs_value_function(val);
         }
     }
 
     if (encode == NULL) {
-        ret = njs_value_property(vm, this, njs_value_arg(&njs_escape_str),
-                                 &value);
+        val = njs_vm_object_prop(vm, this, &njs_escape_str, &value);
 
-        if (ret != NJS_OK || !njs_is_function(&value)) {
-            njs_type_error(vm, "QueryString.escape is not a function");
+        if (val == NULL || !njs_value_is_function(val)) {
+            njs_vm_error(vm, "QueryString.escape is not a function");
             return NJS_ERROR;
         }
 
-        encode = njs_function(&value);
+        encode = njs_value_function(val);
     }
 
-    njs_chb_init(&chain, vm->mem_pool);
+    njs_chb_init(&chain, njs_vm_memory_pool(vm));
 
-    keys = njs_value_own_enumerate(vm, object, NJS_ENUM_KEYS, NJS_ENUM_STRING,
-                                   0);
+    keys = njs_vm_object_keys(vm, object, njs_value_arg(&value));
     if (njs_slow_path(keys == NULL)) {
         return NJS_ERROR;
     }
 
-    for (n = 0, length = 0; n < keys->length; n++) {
-        string = &keys->start[n];
+    (void) njs_vm_array_length(vm, keys, &keys_length);
 
-        ret = njs_value_property(vm, object, string, &value);
+    string = (njs_opaque_value_t *) njs_vm_array_start(vm, keys);
+    if (njs_slow_path(string == NULL)) {
+        return NJS_ERROR;
+    }
+
+    for (n = 0; n < keys_length; n++, string++) {
+        ret = njs_value_property(vm, object, njs_value_arg(string),
+                                 njs_value_arg(&value));
         if (njs_slow_path(ret == NJS_ERROR)) {
             goto failed;
         }
 
-        if (njs_is_array(&value)) {
-
-            if (njs_is_fast_array(&value)) {
-                array = njs_array(&value);
-
-                for (i = 0; i < array->length; i++) {
-                    if (chain.last != NULL) {
-                        njs_chb_append(&chain, sep.start, sep.size);
-                        length += sep.length;
-                    }
-
-                    ret = njs_query_string_push(vm, &chain, string,
-                                                &array->start[i], &eq, encode);
-                    if (njs_slow_path(ret < 0)) {
-                        ret = NJS_ERROR;
-                        goto failed;
-                    }
-
-                    length += ret;
-                }
-
-                continue;
-            }
-
-            ret = njs_object_length(vm, &value, &len);
-            if (njs_slow_path(ret == NJS_ERROR)) {
-                goto failed;
-            }
+        if (njs_value_is_array(njs_value_arg(&value))) {
+            (void) njs_vm_array_length(vm, njs_value_arg(&value), &len);
 
             for (i = 0; i < len; i++) {
-                ret = njs_value_property_i64(vm, &value, i, &result);
+                njs_value_number_set(njs_value_arg(&key), i);
+                ret = njs_value_property(vm, njs_value_arg(&value),
+                                         njs_value_arg(&key),
+                                         njs_value_arg(&result));
                 if (njs_slow_path(ret == NJS_ERROR)) {
                     goto failed;
                 }
 
                 if (chain.last != NULL) {
-                    njs_chb_append(&chain, sep.start, sep.size);
-                    length += sep.length;
+                    njs_chb_append(&chain, sep.start, sep.length);
                 }
 
-                ret = njs_query_string_push(vm, &chain, string, &result, &eq,
+                ret = njs_query_string_push(vm, &chain, njs_value_arg(string),
+                                            njs_value_arg(&result), &eq,
                                             encode);
-                if (njs_slow_path(ret < 0)) {
-                    ret = NJS_ERROR;
+                if (njs_slow_path(ret != NJS_OK)) {
                     goto failed;
                 }
-
-                length += ret;
             }
 
             continue;
         }
 
         if (n != 0) {
-            njs_chb_append(&chain, sep.start, sep.size);
-            length += sep.length;
+            njs_chb_append(&chain, sep.start, sep.length);
         }
 
-        ret = njs_query_string_push(vm, &chain, string, &value, &eq, encode);
-        if (njs_slow_path(ret < 0)) {
-            ret = NJS_ERROR;
+        ret = njs_query_string_push(vm, &chain, njs_value_arg(string),
+                                    njs_value_arg(&value), &eq, encode);
+        if (njs_slow_path(ret != NJS_OK)) {
             goto failed;
         }
-
-        length += ret;
     }
 
-    size = njs_chb_size(&chain);
-    if (njs_slow_path(size < 0)) {
-        njs_memory_error(vm);
-        return NJS_ERROR;
-    }
-
-    p = njs_string_alloc(vm, retval, size, length);
-    if (njs_slow_path(p == NULL)) {
-        return NJS_ERROR;
-    }
-
-    njs_chb_join_to(&chain, p);
-
-    ret = NJS_OK;
+    ret = njs_vm_value_string_create_chb(vm, retval, &chain);
 
 failed:
 
@@ -913,45 +827,37 @@ static njs_int_t
 njs_query_string_escape(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused, njs_value_t *retval)
 {
-    u_char       *p;
-    ssize_t      size, length;
-    njs_int_t    ret;
-    njs_str_t    str;
-    njs_chb_t    chain;
-    njs_value_t  *string, value;
+    njs_int_t           ret;
+    njs_str_t           str;
+    njs_chb_t           chain;
+    njs_value_t         *string;
+    njs_opaque_value_t  value;
 
     string = njs_arg(args, nargs, 1);
 
-    if (!njs_is_string(string)) {
-        ret = njs_value_to_string(vm, &value, string);
+    if (!njs_value_is_string(string)) {
+        ret = njs_value_to_string(vm, njs_value_arg(&value), string);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
 
-        string = &value;
+        string = njs_value_arg(&value);
     }
 
-    njs_string_get(string, &str);
+    njs_value_string_get(string, &str);
 
-    njs_chb_init(&chain, vm->mem_pool);
+    njs_chb_init(&chain, njs_vm_memory_pool(vm));
 
-    length = njs_query_string_encode(&chain, &str);
-    if (njs_slow_path(length < 0)) {
+    ret = njs_query_string_encode(&chain, &str);
+    if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
-    size = njs_chb_size(&chain);
-
-    p = njs_string_alloc(vm, retval, size, length);
-    if (njs_slow_path(p == NULL)) {
-        return NJS_ERROR;
-    }
-
-    njs_chb_join_to(&chain, p);
+    ret = njs_vm_value_string_create_chb(vm, retval, &chain);
 
     njs_chb_destroy(&chain);
 
-    return NJS_OK;
+    return ret;
 }
 
 
@@ -959,22 +865,23 @@ static njs_int_t
 njs_query_string_unescape(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused, njs_value_t *retval)
 {
-    njs_int_t    ret;
-    njs_str_t    str;
-    njs_value_t  *string, value;
+    njs_int_t           ret;
+    njs_str_t           str;
+    njs_value_t         *string;
+    njs_opaque_value_t  value;
 
     string = njs_arg(args, nargs, 1);
 
-    if (!njs_is_string(string)) {
-        ret = njs_value_to_string(vm, &value, string);
+    if (!njs_value_is_string(string)) {
+        ret = njs_value_to_string(vm, njs_value_arg(&value), string);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
 
-        string = &value;
+        string = njs_value_arg(&value);
     }
 
-    njs_string_get(string, &str);
+    njs_value_string_get(string, &str);
 
     return njs_query_string_decode(vm, retval, str.start, str.length);
 }
diff -r b2cbf06ba017 -r fd956d2a25a3 src/njs.h
--- a/src/njs.h	Tue May 02 20:50:52 2023 -0700
+++ b/src/njs.h	Tue May 02 20:50:55 2023 -0700
@@ -382,6 +382,10 @@ NJS_EXPORT njs_external_ptr_t njs_vm_ext
 NJS_EXPORT njs_int_t njs_external_property(njs_vm_t *vm,
     njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
     njs_value_t *retval);
+NJS_EXPORT njs_int_t njs_value_property(njs_vm_t *vm, njs_value_t *value,
+    njs_value_t *key, njs_value_t *retval);
+NJS_EXPORT njs_int_t njs_value_property_set(njs_vm_t *vm, njs_value_t *value,
+    njs_value_t *key, njs_value_t *setval);
 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,
@@ -432,6 +436,8 @@ NJS_EXPORT njs_int_t njs_value_buffer_ge
 NJS_EXPORT njs_int_t njs_vm_value_buffer_set(njs_vm_t *vm, njs_value_t *value,
     const u_char *start, uint32_t size);
 
+NJS_EXPORT njs_int_t njs_value_to_string(njs_vm_t *vm, njs_value_t *dst,
+    njs_value_t *value);
 /*
  * Converts a value to bytes.
  */
@@ -477,6 +483,8 @@ NJS_EXPORT void njs_value_function_set(n
 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_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);
diff -r b2cbf06ba017 -r fd956d2a25a3 src/njs_value.c
--- a/src/njs_value.c	Tue May 02 20:50:52 2023 -0700
+++ b/src/njs_value.c	Tue May 02 20:50:55 2023 -0700
@@ -487,6 +487,23 @@ njs_value_function(const njs_value_t *va
 }
 
 
+njs_function_native_t
+njs_value_native_function(const njs_value_t *value)
+{
+    njs_function_t  *function;
+
+    if (njs_is_function(value)) {
+        function = njs_function(value);
+
+        if (function->native) {
+            return function->u.native;
+        }
+    }
+
+    return NULL;
+}


More information about the nginx-devel mailing list