details: https://hg.nginx.org/njs/rev/a6410aad6eab branches: changeset: 2213:a6410aad6eab user: Dmitry Volyntsev <xei...@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, _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel