[njs] Improved memory footprint of RegExp.prototype.test().

Dmitry Volyntsev xeioex at nginx.com
Wed Oct 4 20:54:58 UTC 2023


details:   https://hg.nginx.org/njs/rev/a6410aad6eab
branches:  
changeset: 2213:a6410aad6eab
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue Oct 03 00:39:04 2023 -0700
description:
Improved memory footprint of RegExp.prototype.test().

diffstat:

 src/njs_regexp.c |  102 ++++++++++++++++++++++++++++++++++++++----------------
 src/njs_regexp.h |    2 -
 2 files changed, 71 insertions(+), 33 deletions(-)

diffs (228 lines):

diff -r f076da3c7a6f -r a6410aad6eab src/njs_regexp.c
--- a/src/njs_regexp.c	Fri Sep 29 21:41:34 2023 -0700
+++ b/src/njs_regexp.c	Tue Oct 03 00:39:04 2023 -0700
@@ -25,6 +25,9 @@ static u_char *njs_regexp_compile_trace_
     njs_trace_data_t *td, u_char *start);
 static u_char *njs_regexp_match_trace_handler(njs_trace_t *trace,
     njs_trace_data_t *td, u_char *start);
+#define NJS_REGEXP_FLAG_TEST           1
+static njs_int_t njs_regexp_exec(njs_vm_t *vm, njs_value_t *r, njs_value_t *s,
+    unsigned flags, njs_value_t *retval);
 static njs_array_t *njs_regexp_exec_result(njs_vm_t *vm, njs_value_t *r,
     njs_utf8_t utf8, njs_string_prop_t *string, njs_regex_match_data_t *data);
 static njs_int_t njs_regexp_string_create(njs_vm_t *vm, njs_value_t *value,
@@ -849,7 +852,7 @@ njs_regexp_prototype_test(njs_vm_t *vm, 
         return NJS_ERROR;
     }
 
-    ret = njs_regexp_exec(vm, r, string, &value);
+    ret = njs_regexp_exec(vm, r, string, NJS_REGEXP_FLAG_TEST, &value);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
@@ -865,10 +868,11 @@ njs_regexp_prototype_test(njs_vm_t *vm, 
  */
 static njs_int_t
 njs_regexp_builtin_exec(njs_vm_t *vm, njs_value_t *r, njs_value_t *s,
-    njs_value_t *retval)
+    unsigned flags, njs_value_t *retval)
 {
-    size_t                  length, offset;
+    size_t                  c, length, offset;
     int64_t                 last_index;
+    uint32_t                index;
     njs_int_t               ret;
     njs_utf8_t              utf8;
     njs_value_t             value;
@@ -940,6 +944,32 @@ njs_regexp_builtin_exec(njs_vm_t *vm, nj
     ret = njs_regexp_match(vm, &pattern->regex[type], string.start, offset,
                            string.size, match_data);
     if (ret >= 0) {
+        if (pattern->global || pattern->sticky) {
+            c = njs_regex_capture(match_data, 1);
+
+            if (utf8 == NJS_STRING_UTF8) {
+                index = njs_string_index(&string, c);
+
+            } else {
+                index = c;
+            }
+
+            njs_set_number(&value, index);
+            ret = njs_value_property_set(vm, r,
+                                         njs_value_arg(&njs_string_lindex),
+                                         &value);
+            if (njs_slow_path(ret != NJS_OK)) {
+                njs_regex_match_data_free(match_data, vm->regex_generic_ctx);
+                return NJS_ERROR;
+            }
+        }
+
+        if (flags & NJS_REGEXP_FLAG_TEST) {
+            njs_regex_match_data_free(match_data, vm->regex_generic_ctx);
+            njs_set_boolean(retval, 1);
+            return NJS_OK;
+        }
+
         result = njs_regexp_exec_result(vm, r, utf8, &string, match_data);
 
         njs_regex_match_data_free(match_data, vm->regex_generic_ctx);
@@ -975,6 +1005,12 @@ not_found:
 }
 
 
+static njs_exotic_slots_t njs_regexp_prototype_exotic_slots = {
+    .prop_handler = NULL,
+    .keys = NULL,
+};
+
+
 static njs_array_t *
 njs_regexp_exec_result(njs_vm_t *vm, njs_value_t *r, njs_utf8_t utf8,
     njs_string_prop_t *string, njs_regex_match_data_t *match_data)
@@ -986,7 +1022,7 @@ njs_regexp_exec_result(njs_vm_t *vm, njs
     njs_int_t             ret;
     njs_uint_t            i, n;
     njs_array_t           *array;
-    njs_value_t           name, value;
+    njs_value_t           name;
     njs_object_t          *groups;
     njs_regexp_t          *regexp;
     njs_object_prop_t     *prop;
@@ -1005,6 +1041,8 @@ njs_regexp_exec_result(njs_vm_t *vm, njs
         goto fail;
     }
 
+    array->object.slots = &njs_regexp_prototype_exotic_slots;
+
     for (i = 0; i < pattern->ncaptures; i++) {
         n = 2 * i;
         c = njs_regex_capture(match_data, n);
@@ -1048,24 +1086,6 @@ njs_regexp_exec_result(njs_vm_t *vm, njs
 
     njs_set_number(&prop->u.value, index);
 
-    if (pattern->global || pattern->sticky) {
-        c = njs_regex_capture(match_data, 1);
-
-        if (utf8 == NJS_STRING_UTF8) {
-            index = njs_string_index(string, c);
-
-        } else {
-            index = c;
-        }
-
-        njs_set_number(&value, index);
-        ret = njs_value_property_set(vm, r, njs_value_arg(&njs_string_lindex),
-                                     &value);
-        if (njs_slow_path(ret != NJS_OK)) {
-            goto fail;
-        }
-    }
-
     lhq.key_hash = NJS_INDEX_HASH;
     lhq.key = njs_str_value("index");
     lhq.replace = 0;
@@ -1184,16 +1204,18 @@ njs_regexp_prototype_exec(njs_vm_t *vm, 
         return ret;
     }
 
-    return njs_regexp_builtin_exec(vm, r, s, retval);
+    return njs_regexp_builtin_exec(vm, r, s,
+                                   njs_number(njs_arg(args, nargs, 2)), retval);
 }
 
 
-njs_int_t
-njs_regexp_exec(njs_vm_t *vm, njs_value_t *r, njs_value_t *s,
+static njs_int_t
+njs_regexp_exec(njs_vm_t *vm, njs_value_t *r, njs_value_t *s, unsigned flags,
     njs_value_t *retval)
 {
     njs_int_t    ret;
     njs_value_t  exec;
+    njs_value_t  arguments[2];
 
     static const njs_value_t  string_exec = njs_string("exec");
 
@@ -1203,12 +1225,30 @@ njs_regexp_exec(njs_vm_t *vm, njs_value_
     }
 
     if (njs_is_function(&exec)) {
-        ret = njs_function_call(vm, njs_function(&exec), r, s, 1, retval);
+        njs_value_assign(&arguments[0], s);
+
+        if (flags) {
+            njs_set_number(&arguments[1], flags);
+        }
+
+        ret = njs_function_call(vm, njs_function(&exec), r, arguments,
+                                flags ? 2 : 1, retval);
         if (njs_slow_path(ret == NJS_ERROR)) {
             return NJS_ERROR;
         }
 
-        if (njs_slow_path(!njs_is_object(retval) && !njs_is_null(retval))) {
+        if (njs_slow_path(!njs_is_null(retval)
+                          && (flags & NJS_REGEXP_FLAG_TEST
+                              && !njs_is_boolean(retval))))
+        {
+            njs_type_error(vm, "unexpected \"%s\" retval in njs_regexp_exec()",
+                           njs_type_string(retval->type));
+            return NJS_ERROR;
+        }
+
+        if (njs_slow_path(!njs_is_null(retval)
+                          && (!flags && !njs_is_object(retval))))
+        {
             njs_type_error(vm, "unexpected \"%s\" retval in njs_regexp_exec()",
                            njs_type_string(retval->type));
             return NJS_ERROR;
@@ -1222,7 +1262,7 @@ njs_regexp_exec(njs_vm_t *vm, njs_value_
         return NJS_ERROR;
     }
 
-    return njs_regexp_builtin_exec(vm, r, s, retval);
+    return njs_regexp_builtin_exec(vm, r, s, flags, retval);
 }
 
 
@@ -1319,7 +1359,7 @@ njs_regexp_prototype_symbol_replace(njs_
             goto exception;
         }
 
-        ret = njs_regexp_exec(vm, rx, string, r);
+        ret = njs_regexp_exec(vm, rx, string, 0, r);
         if (njs_slow_path(ret != NJS_OK)) {
             goto exception;
         }
@@ -1630,7 +1670,7 @@ njs_regexp_prototype_symbol_split(njs_vm
     length = njs_string_prop(&s, string);
 
     if (njs_slow_path(s.size == 0)) {
-        ret = njs_regexp_exec(vm, rx, string, &z);
+        ret = njs_regexp_exec(vm, rx, string, NJS_REGEXP_FLAG_TEST, &z);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
@@ -1659,7 +1699,7 @@ njs_regexp_prototype_symbol_split(njs_vm
             return NJS_ERROR;
         }
 
-        ret = njs_regexp_exec(vm, rx, string, &z);
+        ret = njs_regexp_exec(vm, rx, string, 0, &z);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
diff -r f076da3c7a6f -r a6410aad6eab src/njs_regexp.h
--- a/src/njs_regexp.h	Fri Sep 29 21:41:34 2023 -0700
+++ b/src/njs_regexp.h	Tue Oct 03 00:39:04 2023 -0700
@@ -17,8 +17,6 @@ njs_regexp_pattern_t *njs_regexp_pattern
 njs_int_t njs_regexp_match(njs_vm_t *vm, njs_regex_t *regex,
     const u_char *subject, size_t off, size_t len, njs_regex_match_data_t *d);
 njs_regexp_t *njs_regexp_alloc(njs_vm_t *vm, njs_regexp_pattern_t *pattern);
-njs_int_t njs_regexp_exec(njs_vm_t *vm, njs_value_t *r, njs_value_t *s,
-    njs_value_t *retval);
 njs_int_t njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
 njs_int_t njs_regexp_prototype_symbol_replace(njs_vm_t *vm,


More information about the nginx-devel mailing list