[njs] Using nxt_regex interface in nJSVM.

Igor Sysoev igor at sysoev.ru
Wed Jun 1 12:50:37 UTC 2016


details:   http://hg.nginx.org/njs/rev/c72fd0d1fabc
branches:  
changeset: 113:c72fd0d1fabc
user:      Igor Sysoev <igor at sysoev.ru>
date:      Wed Jun 01 15:31:34 2016 +0300
description:
Using nxt_regex interface in nJSVM.

diffstat:

 Makefile                 |    2 +
 njs/njs_disassembler.c   |    1 -
 njs/njs_lexer_keyword.c  |    1 -
 njs/njs_regexp.c         |  238 ++++++++++++++++++++--------------------------
 njs/njs_regexp.h         |    3 +-
 njs/njs_regexp_pattern.h |    4 +-
 njs/njs_string.c         |   91 +++++++++++++----
 njs/njs_string.h         |    2 +
 njs/njs_vm.h             |   13 ++-
 njs/njscript.c           |   15 +-
 njs/test/njs_unit_test.c |    3 +
 11 files changed, 205 insertions(+), 168 deletions(-)

diffs (773 lines):

diff -r b8084a72d667 -r c72fd0d1fabc Makefile
--- a/Makefile	Wed Jun 01 15:30:50 2016 +0300
+++ b/Makefile	Wed Jun 01 15:31:34 2016 +0300
@@ -36,6 +36,7 @@ NXT_BUILDDIR =	build
 	$(NXT_BUILDDIR)/nxt_rbtree.o \
 	$(NXT_BUILDDIR)/nxt_lvlhsh.o \
 	$(NXT_BUILDDIR)/nxt_random.o \
+	$(NXT_BUILDDIR)/nxt_pcre.o \
 	$(NXT_BUILDDIR)/nxt_malloc.o \
 	$(NXT_BUILDDIR)/nxt_mem_cache_pool.o \
 
@@ -67,6 +68,7 @@ NXT_BUILDDIR =	build
 		$(NXT_BUILDDIR)/nxt_rbtree.o \
 		$(NXT_BUILDDIR)/nxt_lvlhsh.o \
 		$(NXT_BUILDDIR)/nxt_random.o \
+		$(NXT_BUILDDIR)/nxt_pcre.o \
 		$(NXT_BUILDDIR)/nxt_malloc.o \
 		$(NXT_BUILDDIR)/nxt_mem_cache_pool.o \
 
diff -r b8084a72d667 -r c72fd0d1fabc njs/njs_disassembler.c
--- a/njs/njs_disassembler.c	Wed Jun 01 15:30:50 2016 +0300
+++ b/njs/njs_disassembler.c	Wed Jun 01 15:31:34 2016 +0300
@@ -14,7 +14,6 @@
 #include <njscript.h>
 #include <njs_vm.h>
 #include <njs_object.h>
-#include <njs_regexp.h>
 #include <njs_variable.h>
 #include <njs_parser.h>
 #include <stdio.h>
diff -r b8084a72d667 -r c72fd0d1fabc njs/njs_lexer_keyword.c
--- a/njs/njs_lexer_keyword.c	Wed Jun 01 15:30:50 2016 +0300
+++ b/njs/njs_lexer_keyword.c	Wed Jun 01 15:31:34 2016 +0300
@@ -16,7 +16,6 @@
 #include <njs_vm.h>
 #include <njs_number.h>
 #include <njs_object.h>
-#include <njs_regexp.h>
 #include <njs_variable.h>
 #include <njs_parser.h>
 #include <string.h>
diff -r b8084a72d667 -r c72fd0d1fabc njs/njs_regexp.c
--- a/njs/njs_regexp.c	Wed Jun 01 15:30:50 2016 +0300
+++ b/njs/njs_regexp.c	Wed Jun 01 15:31:34 2016 +0300
@@ -14,6 +14,7 @@
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
 #include <nxt_random.h>
+#include <nxt_pcre.h>
 #include <nxt_malloc.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
@@ -30,17 +31,51 @@
 #include <string.h>
 
 
+static void *njs_regexp_malloc(size_t size, void *memory_data);
+static void njs_regexp_free(void *p, void *memory_data);
 static njs_regexp_flags_t njs_regexp_flags(u_char **start, u_char *end,
     nxt_bool_t bound);
-static int njs_regexp_pattern_compile(pcre **code, pcre_extra **extra,
+static int njs_regexp_pattern_compile(njs_vm_t *vm, nxt_regex_t *regex,
     u_char *source, int options);
 static njs_ret_t njs_regexp_exec_result(njs_vm_t *vm, njs_regexp_t *regexp,
-    u_char *string, int *captures, nxt_uint_t utf8);
+    u_char *string, nxt_regex_match_data_t *match_data, nxt_uint_t utf8);
 static njs_ret_t njs_regexp_string_create(njs_vm_t *vm, njs_value_t *value,
     u_char *start, uint32_t size, int32_t length);
 
 
 njs_ret_t
+njs_regexp_init(njs_vm_t *vm)
+{
+    vm->regex_context = nxt_regex_context_create(njs_regexp_malloc,
+                                          njs_regexp_free, vm->mem_cache_pool);
+    if (nxt_slow_path(vm->regex_context == NULL)) {
+        return NXT_ERROR;
+    }
+
+    vm->single_match_data = nxt_regex_match_data(NULL, vm->regex_context);
+    if (nxt_slow_path(vm->single_match_data == NULL)) {
+        return NXT_ERROR;
+    }
+
+    return NXT_OK;
+}
+
+
+static void *
+njs_regexp_malloc(size_t size, void *memory_data)
+{
+    return nxt_mem_cache_alloc(memory_data, size);
+}
+
+
+static void
+njs_regexp_free(void *p, void *memory_data)
+{
+    nxt_mem_cache_free(memory_data, p);
+}
+
+
+njs_ret_t
 njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
 {
@@ -205,18 +240,14 @@ njs_regexp_pattern_create(njs_vm_t *vm, 
     size += ((flags & NJS_REGEXP_IGNORE_CASE) != 0);
     size += ((flags & NJS_REGEXP_MULTILINE) != 0);
 
-    pattern = nxt_mem_cache_alloc(vm->mem_cache_pool,
-                                  sizeof(njs_regexp_pattern_t)
-                                  + 1 + length + size + 1);
+    pattern = nxt_mem_cache_zalloc(vm->mem_cache_pool,
+                                   sizeof(njs_regexp_pattern_t)
+                                   + 1 + length + size + 1);
     if (nxt_slow_path(pattern == NULL)) {
         return NULL;
     }
 
     pattern->flags = size;
-    pattern->code[0] = NULL;
-    pattern->code[1] = NULL;
-    pattern->extra[0] = NULL;
-    pattern->extra[1] = NULL;
     pattern->next = NULL;
 
     p = (u_char *) pattern + sizeof(njs_regexp_pattern_t);
@@ -254,18 +285,16 @@ njs_regexp_pattern_create(njs_vm_t *vm, 
 
     *p++ = '\0';
 
-    ret = njs_regexp_pattern_compile(&pattern->code[0], &pattern->extra[0],
+    ret = njs_regexp_pattern_compile(vm, &pattern->regex[0],
                                      &pattern->source[1], options);
-
     if (nxt_slow_path(ret < 0)) {
         return NULL;
     }
 
     pattern->ncaptures = ret;
 
-    ret = njs_regexp_pattern_compile(&pattern->code[1], &pattern->extra[1],
+    ret = njs_regexp_pattern_compile(vm, &pattern->regex[1],
                                      &pattern->source[1], options | PCRE_UTF8);
-
     if (nxt_fast_path(ret >= 0)) {
 
         if (nxt_slow_path((u_int) ret != pattern->ncaptures)) {
@@ -273,75 +302,35 @@ njs_regexp_pattern_create(njs_vm_t *vm, 
                            "and UTF-8 versions of RegExp \"%s\" vary: %d vs %d",
                            &pattern->source[1], pattern->ncaptures, ret);
 
-            njs_regexp_pattern_free(pattern);
+            nxt_mem_cache_free(vm->mem_cache_pool, pattern);
             return NULL;
         }
 
     } else if (ret != NXT_DECLINED) {
-        njs_regexp_pattern_free(pattern);
+        nxt_mem_cache_free(vm->mem_cache_pool, pattern);
         return NULL;
     }
 
     *end = '/';
 
-    pattern->next = vm->pattern;
-    vm->pattern = pattern;
-
     return pattern;
 }
 
 
 static int
-njs_regexp_pattern_compile(pcre **code, pcre_extra **extra, u_char *source,
+njs_regexp_pattern_compile(njs_vm_t *vm, nxt_regex_t *regex, u_char *source,
     int options)
 {
-    int         ret, erroff, captures;
-    u_char      *error;
-    const char  *errstr;
-
-    *code = pcre_compile((char *) source, options, &errstr, &erroff, NULL);
-
-    if (nxt_slow_path(*code == NULL)) {
-
-        if ((options & PCRE_UTF8) != 0) {
-            return NXT_DECLINED;
-        }
+    nxt_int_t  ret;
 
-        error = source + erroff;
+    /* Zero length means a zero-terminated string. */
+    ret = nxt_regex_compile(regex, source, 0, options, vm->regex_context);
 
-        if (*error != '\0') {
-            nxt_thread_log_error(NXT_LOG_ERR,
-                                 "pcre_compile(\"%s\") failed: %s at \"%s\"",
-                                 source, errstr, error);
-        } else {
-            nxt_thread_log_error(NXT_LOG_ERR,
-                                 "pcre_compile(\"%s\") failed: %s",
-                                 source, errstr);
-        }
-
-        return NXT_ERROR;
+    if (nxt_fast_path(ret == NXT_OK)) {
+        return regex->ncaptures;
     }
 
-    *extra = pcre_study(*code, 0, &errstr);
-
-    if (nxt_slow_path(errstr != NULL)) {
-        nxt_thread_log_error(NXT_LOG_ERR, "pcre_study(\"%s\") failed: %s",
-                             source, errstr);
-        return NXT_ERROR;
-    }
-
-    ret = pcre_fullinfo(*code, NULL, PCRE_INFO_CAPTURECOUNT, &captures);
-
-    if (nxt_fast_path(ret >= 0)) {
-        /* Reserve additional elements for the first "$0" capture. */
-        return captures + 1;
-    }
-
-    nxt_thread_log_error(NXT_LOG_ERR,
-                   "pcre_fullinfo(\"%s\", PCRE_INFO_CAPTURECOUNT) failed: %d",
-                   source, ret);
-
-    return NXT_ERROR;
+    return njs_string_exception(vm, NJS_SYNTAX_ERROR, vm->regex_context->error);
 }
 
 
@@ -491,16 +480,15 @@ njs_regexp_prototype_test(njs_vm_t *vm, 
 
     pattern = args[0].data.u.regexp->pattern;
 
-    if (pattern->code[n] != NULL) {
-        ret = pcre_exec(pattern->code[n], pattern->extra[n],
-                        (char *) string.start, string.size, 0, 0, NULL, 0);
-
+    if (nxt_regex_is_valid(&pattern->regex[n])) {
+        ret = nxt_regex_match(&pattern->regex[n], string.start, string.size,
+                              vm->single_match_data, vm->regex_context);
         if (ret >= 0) {
             retval = &njs_value_true;
 
-        } else if (ret != PCRE_ERROR_NOMATCH) {
-            vm->exception = &njs_exception_internal_error;
-            return NXT_ERROR;
+        } else if (ret != NGX_REGEX_NOMATCH) {
+            return njs_string_exception(vm, NJS_INTERNAL_ERROR,
+                                        vm->regex_context->error);
         }
     }
 
@@ -514,13 +502,13 @@ njs_ret_t
 njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
 {
-    int                   *captures, ncaptures;
-    njs_ret_t             ret;
-    nxt_uint_t            n, utf8;
-    njs_value_t           *value;
-    njs_regexp_t          *regexp;
-    njs_string_prop_t     string;
-    njs_regexp_pattern_t  *pattern;
+    njs_ret_t               ret;
+    nxt_uint_t              n, utf8;
+    njs_value_t             *value;
+    njs_regexp_t            *regexp;
+    njs_string_prop_t       string;
+    njs_regexp_pattern_t    *pattern;
+    nxt_regex_match_data_t  *match_data;
 
     if (!njs_is_regexp(&args[0])) {
         vm->exception = &njs_exception_type_error;
@@ -553,27 +541,28 @@ njs_regexp_prototype_exec(njs_vm_t *vm, 
 
     pattern = regexp->pattern;
 
-    if (pattern->code[n] != NULL) {
+    if (nxt_regex_is_valid(&pattern->regex[n])) {
         string.start += regexp->last_index;
         string.size -= regexp->last_index;
 
-        /* Each capture is stored in 3 vector elements. */
-        ncaptures = pattern->ncaptures * 3;
-
-        captures = alloca(ncaptures * sizeof(int));
-
-        ret = pcre_exec(pattern->code[n], pattern->extra[n],
-                        (char *) string.start, string.size,
-                        0, 0, captures, ncaptures);
-
-        if (ret >= 0) {
-            return njs_regexp_exec_result(vm, regexp, string.start,
-                                          captures, utf8);
+        match_data = nxt_regex_match_data(&pattern->regex[n],
+                                          vm->regex_context);
+        if (nxt_slow_path(match_data == NULL)) {
+            return NXT_ERROR;
         }
 
-        if (nxt_slow_path(ret != PCRE_ERROR_NOMATCH)) {
-            vm->exception = &njs_exception_internal_error;
-            return NXT_ERROR;
+        ret = nxt_regex_match(&pattern->regex[n], string.start, string.size,
+                              match_data, vm->regex_context);
+        if (ret >= 0) {
+            return njs_regexp_exec_result(vm, regexp, string.start, match_data,
+                                          utf8);
+        }
+
+        if (nxt_slow_path(ret != NGX_REGEX_NOMATCH)) {
+            nxt_regex_match_data_free(match_data, vm->regex_context);
+
+            return njs_string_exception(vm, NJS_INTERNAL_ERROR,
+                                        vm->regex_context->error);
         }
     }
 
@@ -586,8 +575,9 @@ njs_regexp_prototype_exec(njs_vm_t *vm, 
 
 static njs_ret_t
 njs_regexp_exec_result(njs_vm_t *vm, njs_regexp_t *regexp, u_char *string,
-    int *captures, nxt_uint_t utf8)
+    nxt_regex_match_data_t *match_data, nxt_uint_t utf8)
 {
+    int                 *captures;
     u_char              *start;
     int32_t             size, length;
     njs_ret_t           ret;
@@ -601,9 +591,11 @@ njs_regexp_exec_result(njs_vm_t *vm, njs
 
     array = njs_array_alloc(vm, regexp->pattern->ncaptures, 0);
     if (nxt_slow_path(array == NULL)) {
-        return NXT_ERROR;
+        goto fail;
     }
 
+    captures = nxt_regex_captures(match_data);
+
     for (i = 0; i < regexp->pattern->ncaptures; i++) {
         n = 2 * i;
 
@@ -626,7 +618,7 @@ njs_regexp_exec_result(njs_vm_t *vm, njs
             ret = njs_regexp_string_create(vm, &array->start[i],
                                            start, size, length);
             if (nxt_slow_path(ret != NXT_OK)) {
-                return NXT_ERROR;
+                goto fail;
             }
 
         } else {
@@ -636,7 +628,7 @@ njs_regexp_exec_result(njs_vm_t *vm, njs
 
     prop = njs_object_prop_alloc(vm, &njs_string_index);
     if (nxt_slow_path(prop == NULL)) {
-        return NXT_ERROR;
+        goto fail;
     }
 
     /* TODO: Non UTF-8 position */
@@ -657,13 +649,12 @@ njs_regexp_exec_result(njs_vm_t *vm, njs
 
     ret = nxt_lvlhsh_insert(&array->object.hash, &lhq);
     if (nxt_slow_path(ret != NXT_OK)) {
-        /* Only NXT_ERROR can be returned here. */
-        return ret;
+        goto fail;
     }
 
     prop = njs_object_prop_alloc(vm, &njs_string_input);
     if (nxt_slow_path(prop == NULL)) {
-        return NXT_ERROR;
+        goto fail;
     }
 
     njs_string_copy(&prop->value, &regexp->string);
@@ -674,16 +665,25 @@ njs_regexp_exec_result(njs_vm_t *vm, njs
     lhq.value = prop;
 
     ret = nxt_lvlhsh_insert(&array->object.hash, &lhq);
-    if (nxt_slow_path(ret != NXT_OK)) {
-        /* Only NXT_ERROR can be returned here. */
-        return ret;
+
+    if (nxt_fast_path(ret == NXT_OK)) {
+        vm->retval.data.u.array = array;
+        vm->retval.type = NJS_ARRAY;
+        vm->retval.data.truth = 1;
+
+        ret = NXT_OK;
+        goto done;
     }
 
-    vm->retval.data.u.array = array;
-    vm->retval.type = NJS_ARRAY;
-    vm->retval.data.truth = 1;
+fail:
 
-    return NXT_OK;
+    ret = NXT_ERROR;
+
+done:
+
+    nxt_regex_match_data_free(match_data, vm->regex_context);
+
+    return ret;
 }
 
 
@@ -789,29 +789,3 @@ const njs_object_init_t  njs_regexp_prot
     njs_regexp_prototype_properties,
     nxt_nitems(njs_regexp_prototype_properties),
 };
-
-
-void
-njs_regexp_pattern_free(njs_regexp_pattern_t *pattern)
-{
-    /*
-     * pcre_free() is enough to free PCRE extra study data.
-     * pcre_free_study() is required for JIT optimization, pcreapi(3):
-     *
-     *   When you are finished with a pattern,  you can free  the memory used
-     *   for the study data by calling  pcre_free_study().  This function was
-     *   added to the API for release 8.20.  For earlier versions, the memory
-     *   could be freed with pcre_free(), just like the pattern itself.  This
-     *   will still work in cases where JIT optimization is not used,  but it
-     *   is advisable to change to the new function when convenient.
-     */
-    while (pattern != NULL) {
-        pcre_free(pattern->extra[0]);
-        pcre_free(pattern->code[0]);
-
-        pcre_free(pattern->extra[1]);
-        pcre_free(pattern->code[1]);
-
-        pattern = pattern->next;
-    }
-}
diff -r b8084a72d667 -r c72fd0d1fabc njs/njs_regexp.h
--- a/njs/njs_regexp.h	Wed Jun 01 15:30:50 2016 +0300
+++ b/njs/njs_regexp.h	Wed Jun 01 15:31:34 2016 +0300
@@ -32,6 +32,7 @@ struct njs_regexp_s {
 };
 
 
+njs_ret_t njs_regexp_init(njs_vm_t *vm);
 njs_ret_t njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args,
     nxt_uint_t nargs, njs_index_t unused);
 nxt_int_t njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser,
@@ -41,7 +42,7 @@ njs_regexp_pattern_t *njs_regexp_pattern
 njs_regexp_t *njs_regexp_alloc(njs_vm_t *vm, njs_regexp_pattern_t *pattern);
 njs_ret_t njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args,
     nxt_uint_t nargs, njs_index_t unused);
-void njs_regexp_pattern_free(njs_regexp_pattern_t *pattern);
+
 
 extern const njs_object_init_t  njs_regexp_constructor_init;
 extern const njs_object_init_t  njs_regexp_prototype_init;
diff -r b8084a72d667 -r c72fd0d1fabc njs/njs_regexp_pattern.h
--- a/njs/njs_regexp_pattern.h	Wed Jun 01 15:30:50 2016 +0300
+++ b/njs/njs_regexp_pattern.h	Wed Jun 01 15:31:34 2016 +0300
@@ -11,8 +11,8 @@
 
 
 struct njs_regexp_pattern_s {
-    pcre                  *code[2];
-    pcre_extra            *extra[2];
+    nxt_regex_t           regex[2];
+
     njs_regexp_pattern_t  *next;
     /*
      * A pattern source is used by RegExp.toString() method and
diff -r b8084a72d667 -r c72fd0d1fabc njs/njs_string.c
--- a/njs/njs_string.c	Wed Jun 01 15:30:50 2016 +0300
+++ b/njs/njs_string.c	Wed Jun 01 15:31:34 2016 +0300
@@ -14,6 +14,7 @@
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
 #include <nxt_random.h>
+#include <nxt_pcre.h>
 #include <nxt_malloc.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
@@ -1409,12 +1410,11 @@ static njs_ret_t
 njs_string_prototype_search(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
 {
-    int                   ret;
+    int                   ret, *captures;
     nxt_int_t             index;
     nxt_uint_t            n;
     njs_string_prop_t     string;
     njs_regexp_pattern_t  *pattern;
-    int                   captures[3];
 
     index = 0;
 
@@ -1450,17 +1450,16 @@ njs_string_prototype_search(njs_vm_t *vm
 
         n = (string.length != 0 && string.length != string.size);
 
-        if (pattern->code[n] != NULL) {
-            ret = pcre_exec(pattern->code[n], pattern->extra[n],
-                            (char *) string.start, string.size,
-                            0, 0, captures, 3);
-
+        if (nxt_regex_is_valid(&pattern->regex[n])) {
+            ret = nxt_regex_match(&pattern->regex[n], string.start, string.size,
+                                  vm->single_match_data, vm->regex_context);
             if (ret >= 0) {
+                captures = nxt_regex_captures(vm->single_match_data);
                 index = njs_string_index(&string, captures[0]);
 
-            } else if (ret != PCRE_ERROR_NOMATCH) {
-                vm->exception = &njs_exception_internal_error;
-                return NXT_ERROR;
+            } else if (ret != NGX_REGEX_NOMATCH) {
+                return njs_string_exception(vm, NJS_INTERNAL_ERROR,
+                                            vm->regex_context->error);
             }
         }
     }
@@ -1489,7 +1488,7 @@ njs_string_prototype_match(njs_vm_t *vm,
     njs_array_t           *array;
     njs_string_prop_t     string;
     njs_regexp_pattern_t  *pattern;
-    int                   captures[3];
+    int                   *captures;
 
     if (nargs == 1) {
         goto empty;
@@ -1549,14 +1548,12 @@ njs_string_prototype_match(njs_vm_t *vm,
         }
     }
 
-    if (pattern->code[n] != NULL) {
+    if (nxt_regex_is_valid(&pattern->regex[n])) {
         array = NULL;
 
         do {
-            ret = pcre_exec(pattern->code[n], pattern->extra[n],
-                            (char *) string.start, string.size,
-                            0, 0, captures, 3);
-
+            ret = nxt_regex_match(&pattern->regex[n], string.start, string.size,
+                                  vm->single_match_data, vm->regex_context);
             if (ret >= 0) {
                 if (array != NULL) {
                     if (array->length == array->size) {
@@ -1577,6 +1574,7 @@ njs_string_prototype_match(njs_vm_t *vm,
                     vm->retval.data.truth = 1;
                 }
 
+                captures = nxt_regex_captures(vm->single_match_data);
                 start = &string.start[captures[0]];
 
                 string.start += captures[1];
@@ -1595,8 +1593,10 @@ njs_string_prototype_match(njs_vm_t *vm,
 
                 default:
                     length = nxt_utf8_length(start, size);
+
                     if (nxt_slow_path(length < 0)) {
-                        goto error;
+                        vm->exception = &njs_exception_internal_error;
+                        return NXT_ERROR;
                     }
 
                     break;
@@ -1610,11 +1610,12 @@ njs_string_prototype_match(njs_vm_t *vm,
 
                 array->length++;
 
-            } else if (ret == PCRE_ERROR_NOMATCH) {
+            } else if (ret == NGX_REGEX_NOMATCH) {
                 break;
 
             } else {
-                goto error;
+                return njs_string_exception(vm, NJS_INTERNAL_ERROR,
+                                            vm->regex_context->error);
             }
 
         } while (string.size > 0);
@@ -1626,12 +1627,6 @@ njs_string_prototype_match(njs_vm_t *vm,
 
     return NXT_OK;
 
-error:
-
-    vm->exception = &njs_exception_internal_error;
-
-    return NXT_ERROR;
-
 empty:
 
     array = njs_array_alloc(vm, 1, 0);
@@ -2049,3 +2044,49 @@ njs_value_index(njs_vm_t *vm, njs_parser
 
     return (njs_index_t) value;
 }
+
+
+nxt_int_t
+njs_string_exception(njs_vm_t *vm, njs_exception_error_t exception, u_char *msg)
+{
+    u_char       *p, *start;
+    uint32_t     msg_length, size, length;
+    nxt_str_t    *error;
+    njs_value_t  *value;
+
+    static nxt_str_t  errors[] = {
+        nxt_string("SyntaxError: "),
+        nxt_string("InternalError: "),
+    };
+
+    value = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_value_t));
+    if (nxt_slow_path(value == NULL)) {
+        return NXT_ERROR;
+    }
+
+    error = &errors[exception];
+
+    msg_length = (msg != NULL) ? strlen((char *) msg) : 0;
+    length = nxt_utf8_length(msg, msg_length);
+
+    size = error->len + msg_length;
+    length += error->len;
+
+    start = njs_string_alloc(vm, value, size, length);
+
+    if (nxt_fast_path(start != NULL)) {
+        memcpy(start, error->data, error->len);
+        p = start + error->len;
+
+        memcpy(p, msg, msg_length);
+
+        if (size != length && length >= NJS_STRING_MAP_OFFSET) {
+            njs_string_offset_map_init(start, size);
+        }
+    }
+
+    vm->exception = value;
+
+    return NXT_ERROR;
+}
+
diff -r b8084a72d667 -r c72fd0d1fabc njs/njs_string.h
--- a/njs/njs_string.h	Wed Jun 01 15:30:50 2016 +0300
+++ b/njs/njs_string.h	Wed Jun 01 15:31:34 2016 +0300
@@ -107,6 +107,8 @@ double njs_string_to_number(njs_value_t 
 
 njs_index_t njs_value_index(njs_vm_t *vm, njs_parser_t *parser,
     const njs_value_t *src);
+nxt_int_t njs_string_exception(njs_vm_t *vm, njs_exception_error_t exception,
+    u_char *msg);
 
 extern const njs_object_init_t  njs_string_constructor_init;
 extern const njs_object_init_t  njs_string_prototype_init;
diff -r b8084a72d667 -r c72fd0d1fabc njs/njs_vm.h
--- a/njs/njs_vm.h	Wed Jun 01 15:30:50 2016 +0300
+++ b/njs/njs_vm.h	Wed Jun 01 15:31:34 2016 +0300
@@ -8,6 +8,9 @@
 #define _NJS_VM_H_INCLUDED_
 
 
+#include <nxt_regex.h>
+
+
 /*
  * Negative return values handled by nJSVM interpreter as special events.
  * The values must be in range from -1 to -11, because -12 is minimal jump
@@ -790,7 +793,9 @@ struct njs_vm_s {
 
     njs_vm_shared_t          *shared;
     njs_parser_t             *parser;
-    njs_regexp_pattern_t     *pattern;
+
+    nxt_regex_context_t      *regex_context;
+    nxt_regex_match_data_t   *single_match_data;
 
     nxt_array_t              *code;  /* of njs_vm_code_t */
 
@@ -822,6 +827,12 @@ struct njs_vm_shared_s {
 };
 
 
+typedef enum {
+    NJS_SYNTAX_ERROR = 0,
+    NJS_INTERNAL_ERROR,
+} njs_exception_error_t;
+
+
 nxt_int_t njs_vmcode_interpreter(njs_vm_t *vm);
 
 void njs_value_retain(njs_value_t *value);
diff -r b8084a72d667 -r c72fd0d1fabc njs/njscript.c
--- a/njs/njscript.c	Wed Jun 01 15:30:50 2016 +0300
+++ b/njs/njscript.c	Wed Jun 01 15:31:34 2016 +0300
@@ -116,12 +116,16 @@ njs_vm_create(nxt_mem_cache_pool_t *mcp,
     if (nxt_fast_path(vm != NULL)) {
         vm->mem_cache_pool = mcp;
 
+        ret = njs_regexp_init(vm);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return NULL;
+        }
+
         if (shared != NULL && *shared != NULL) {
             vm->shared = *shared;
 
         } else {
             vm->shared = nxt_mem_cache_zalloc(mcp, sizeof(njs_vm_shared_t));
-
             if (nxt_slow_path(vm->shared == NULL)) {
                 return NULL;
             }
@@ -133,7 +137,6 @@ njs_vm_create(nxt_mem_cache_pool_t *mcp,
             nxt_lvlhsh_init(&vm->shared->keywords_hash);
 
             ret = njs_lexer_keywords_init(mcp, &vm->shared->keywords_hash);
-
             if (nxt_slow_path(ret != NXT_OK)) {
                 return NULL;
             }
@@ -141,7 +144,6 @@ njs_vm_create(nxt_mem_cache_pool_t *mcp,
             nxt_lvlhsh_init(&vm->shared->values_hash);
 
             ret = njs_builtin_objects_create(vm);
-
             if (nxt_slow_path(ret != NXT_OK)) {
                 return NULL;
             }
@@ -161,8 +163,6 @@ njs_vm_create(nxt_mem_cache_pool_t *mcp,
 void
 njs_vm_destroy(njs_vm_t *vm)
 {
-    njs_regexp_pattern_free(vm->pattern);
-
     nxt_mem_cache_pool_destroy(vm->mem_cache_pool);
 }
 
@@ -312,6 +312,11 @@ njs_vm_clone(njs_vm_t *vm, nxt_mem_cache
         memcpy(values + NJS_INDEX_GLOBAL_OFFSET, vm->global_scope,
                vm->scope_size);
 
+        ret = njs_regexp_init(nvm);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            goto fail;
+        }
+
         ret = njs_builtin_objects_clone(nvm);
         if (nxt_slow_path(ret != NXT_OK)) {
             goto fail;
diff -r b8084a72d667 -r c72fd0d1fabc njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Wed Jun 01 15:30:50 2016 +0300
+++ b/njs/test/njs_unit_test.c	Wed Jun 01 15:31:34 2016 +0300
@@ -3369,6 +3369,9 @@ static njs_unit_test_t  njs_test[] =
 
     /* RegExp. */
 
+    { nxt_string("/(/.test('')"),
+      nxt_string("SyntaxError: pcre_compile(\"(\") failed: missing )") },
+
     { nxt_string("/^$/.test('')"),
       nxt_string("true") },
 



More information about the nginx-devel mailing list