[njs] Decoupling parser structure from the main VM structure.

Dmitry Volyntsev xeioex at nginx.com
Wed Feb 24 14:51:02 UTC 2021


details:   https://hg.nginx.org/njs/rev/1f22e9008cc3
branches:  
changeset: 1610:1f22e9008cc3
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Wed Feb 24 14:48:20 2021 +0000
description:
Decoupling parser structure from the main VM structure.

vm->parser is only needed during parsing phase, so it can be eliminated.
This improves dependencies tracking and readability.

As a side effect it fixes #372 issue on Github: previously, Function
constructor left VM context in inconsistent state if compilation failed.
The direct root cause was that a function object was created, but
because Function constructor ended prematurely the object was not fully
initialized. This is not a problem by itself because usually this
partially created object cannot be referenced. In the accumulative mode,
which is only enabled in CLI, vm->parser was used to store the references
to the variables from the previous iteration.

diffstat:

 src/njs_builtin.c        |   6 +--
 src/njs_function.c       |  22 ++++--------
 src/njs_module.c         |  10 +++--
 src/njs_parser.c         |  84 +++++++++++++++++------------------------------
 src/njs_parser.h         |   9 ++--
 src/njs_regexp.c         |   8 +----
 src/njs_shell.c          |  10 ++--
 src/njs_variable.c       |  23 ++++++------
 src/njs_variable.h       |   4 +-
 src/njs_vm.c             |  67 ++++++++++++--------------------------
 src/njs_vm.h             |   1 -
 src/test/njs_unit_test.c |  20 ++++++++--
 12 files changed, 104 insertions(+), 160 deletions(-)

diffs (695 lines):

diff -r 4197cc28ea9c -r 1f22e9008cc3 src/njs_builtin.c
--- a/src/njs_builtin.c	Fri Feb 19 17:27:44 2021 +0000
+++ b/src/njs_builtin.c	Wed Feb 24 14:48:20 2021 +0000
@@ -613,10 +613,6 @@ njs_vm_expression_completions(njs_vm_t *
     njs_lvlhsh_query_t   lhq;
     njs_variable_node_t  var_node;
 
-    if (njs_slow_path(vm->parser == NULL)) {
-        return NULL;
-    }
-
     p = expression->start;
     end = p + expression->length;
 
@@ -635,7 +631,7 @@ njs_vm_expression_completions(njs_vm_t *
 
     var_node.key = (uintptr_t) lhq.value;
 
-    node = njs_rbtree_find(&vm->parser->scope->variables, &var_node.node);
+    node = njs_rbtree_find(vm->variables_hash, &var_node.node);
     if (njs_slow_path(node == NULL)) {
         return NULL;
     }
diff -r 4197cc28ea9c -r 1f22e9008cc3 src/njs_function.c
--- a/src/njs_function.c	Fri Feb 19 17:27:44 2021 +0000
+++ b/src/njs_function.c	Wed Feb 24 14:48:20 2021 +0000
@@ -874,7 +874,7 @@ njs_function_constructor(njs_vm_t *vm, n
     njs_str_t               str, file;
     njs_uint_t              i;
     njs_lexer_t             lexer;
-    njs_parser_t            *parser;
+    njs_parser_t            parser;
     njs_vm_code_t           *code;
     njs_function_t          *function;
     njs_generator_t         generator;
@@ -926,15 +926,6 @@ njs_function_constructor(njs_vm_t *vm, n
         return NJS_ERROR;
     }
 
-    vm->options.accumulative = 1;
-
-    parser = njs_mp_zalloc(vm->mem_pool, sizeof(njs_parser_t));
-    if (njs_slow_path(parser == NULL)) {
-        return NJS_ERROR;
-    }
-
-    vm->parser = parser;
-
     file = njs_str_value("runtime");
 
     ret = njs_lexer_init(vm, &lexer, &file, str.start, str.start + str.length);
@@ -942,10 +933,11 @@ njs_function_constructor(njs_vm_t *vm, n
         return ret;
     }
 
-    parser->vm = vm;
-    parser->lexer = &lexer;
+    njs_memzero(&parser, sizeof(njs_parser_t));
 
-    ret = njs_parser(parser, NULL);
+    parser.lexer = &lexer;
+
+    ret = njs_parser(vm, &parser, NULL);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
@@ -957,7 +949,7 @@ njs_function_constructor(njs_vm_t *vm, n
          * the global object in a portable way.
          */
 
-        node = parser->node;
+        node = parser.node;
         type = &safe_ast[0];
 
         for (; *type != NJS_TOKEN_ILLEGAL; type++, node = node->right) {
@@ -971,7 +963,7 @@ njs_function_constructor(njs_vm_t *vm, n
         }
     }
 
-    scope = parser->scope;
+    scope = parser.scope;
 
     ret = njs_variables_copy(vm, &scope->variables, vm->variables_hash);
     if (njs_slow_path(ret != NJS_OK)) {
diff -r 4197cc28ea9c -r 1f22e9008cc3 src/njs_module.c
--- a/src/njs_module.c	Fri Feb 19 17:27:44 2021 +0000
+++ b/src/njs_module.c	Wed Feb 24 14:48:20 2021 +0000
@@ -40,7 +40,7 @@ static njs_int_t njs_module_read(njs_vm_
 static njs_module_t *njs_module_find(njs_vm_t *vm, njs_str_t *name,
     njs_bool_t local);
 static njs_module_t *njs_module_add(njs_vm_t *vm, njs_str_t *name);
-static njs_int_t njs_module_insert(njs_vm_t *vm, njs_module_t *module);
+static njs_int_t njs_module_insert(njs_parser_t *parser, njs_module_t *module);
 
 
 njs_int_t
@@ -273,7 +273,7 @@ njs_parser_module_after(njs_parser_t *pa
     module = (njs_module_t *) parser->target;
 
     if (module->index == 0) {
-        ret = njs_module_insert(parser->vm, module);
+        ret = njs_module_insert(parser, module);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
@@ -564,12 +564,14 @@ njs_module_add(njs_vm_t *vm, njs_str_t *
 
 
 static njs_int_t
-njs_module_insert(njs_vm_t *vm, njs_module_t *module)
+njs_module_insert(njs_parser_t *parser, njs_module_t *module)
 {
+    njs_vm_t            *vm;
     njs_module_t        **value;
     njs_parser_scope_t  *scope;
 
-    scope = njs_parser_global_scope(vm);
+    scope = njs_parser_global_scope(parser);
+    vm = parser->vm;
 
     module->index = njs_scope_next_index(vm, scope, NJS_SCOPE_INDEX_LOCAL,
                                          &njs_value_undefined);
diff -r 4197cc28ea9c -r 1f22e9008cc3 src/njs_parser.c
--- a/src/njs_parser.c	Fri Feb 19 17:27:44 2021 +0000
+++ b/src/njs_parser.c	Wed Feb 24 14:48:20 2021 +0000
@@ -503,23 +503,26 @@ njs_parser_reject(njs_parser_t *parser)
 
 
 njs_int_t
-njs_parser(njs_parser_t *parser, njs_parser_t *prev)
+njs_parser(njs_vm_t *vm, njs_parser_t *parser, njs_rbtree_t *prev_vars)
 {
     njs_int_t          ret;
     njs_lexer_token_t  *token;
 
+    parser->vm = vm;
+
+    njs_set_undefined(&vm->retval);
+
     ret = njs_parser_scope_begin(parser, NJS_SCOPE_GLOBAL);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
-    if (prev != NULL) {
+    if (prev_vars != NULL) {
         /*
          * Copy the global scope variables from the previous
          * iteration of the accumulative mode.
          */
-        ret = njs_variables_copy(parser->vm, &parser->scope->variables,
-                                 &prev->scope->variables);
+        ret = njs_variables_copy(vm, &parser->scope->variables, prev_vars);
         if (ret != NJS_OK) {
             return ret;
         }
@@ -551,7 +554,7 @@ njs_parser(njs_parser_t *parser, njs_par
         return NJS_ERROR;
     }
 
-    if (njs_is_error(&parser->vm->retval)) {
+    if (njs_is_error(&vm->retval)) {
         return NJS_ERROR;
     }
 
@@ -1196,11 +1199,14 @@ njs_parser_regexp_literal(njs_parser_t *
 {
     u_char                *p;
     njs_str_t             text;
+    njs_int_t             ret;
     njs_lexer_t           *lexer;
-    njs_value_t           *value;
+    njs_value_t           *value, retval;
     njs_regexp_flags_t    flags;
     njs_regexp_pattern_t  *pattern;
 
+    static const njs_value_t  string_message = njs_string("message");
+
     value = &parser->node->u.value;
     lexer = parser->lexer;
 
@@ -1269,6 +1275,18 @@ njs_parser_regexp_literal(njs_parser_t *
                                                 text.length, flags);
 
             if (njs_slow_path(pattern == NULL)) {
+                ret = njs_value_property(parser->vm, &parser->vm->retval,
+                                         njs_value_arg(&string_message),
+                                         &retval);
+                if (njs_slow_path(ret != NJS_OK)) {
+                    return NJS_ERROR;
+                }
+
+                njs_string_get(&retval, &text);
+                njs_value_undefined_set(&parser->vm->retval);
+
+                njs_parser_syntax_error(parser, "%V", &text);
+
                 return NJS_ERROR;
             }
 
@@ -6460,7 +6478,7 @@ njs_parser_function_declaration(njs_pars
 
     njs_lexer_consume_token(parser->lexer, 1);
 
-    var = njs_variable_add(parser->vm, parser->scope, unique_id,
+    var = njs_variable_add(parser, parser->scope, unique_id,
                            NJS_VARIABLE_FUNCTION);
     if (var == NULL) {
         return NJS_ERROR;
@@ -6552,7 +6570,7 @@ njs_parser_function_expression(njs_parse
     }
 
     if (njs_lexer_token_is_binding_identifier(token)) {
-        var = njs_variable_add(parser->vm, parser->scope, token->unique_id,
+        var = njs_variable_add(parser, parser->scope, token->unique_id,
                                NJS_VARIABLE_SHIM);
         if (var == NULL) {
             return NJS_ERROR;
@@ -6649,7 +6667,7 @@ njs_parser_formal_parameters(njs_parser_
     default:
         /* SingleNameBinding */
         if (njs_lexer_token_is_binding_identifier(token)) {
-            arg = njs_variable_add(parser->vm, parser->scope,
+            arg = njs_variable_add(parser, parser->scope,
                                    token->unique_id, NJS_VARIABLE_VAR);
             if (arg == NULL) {
                 return NJS_ERROR;
@@ -6764,7 +6782,7 @@ njs_parser_arrow_function(njs_parser_t *
                                 njs_parser_arrow_function_args_after);
 
     } else if (njs_lexer_token_is_binding_identifier(token)) {
-        arg = njs_variable_add(parser->vm, parser->scope,
+        arg = njs_variable_add(parser, parser->scope,
                                token->unique_id, NJS_VARIABLE_VAR);
         if (arg == NULL) {
             return NJS_ERROR;
@@ -7517,7 +7535,7 @@ njs_parser_variable_node(njs_parser_t *p
     njs_variable_t     *var;
     njs_parser_node_t  *node;
 
-    var = njs_variable_add(parser->vm, parser->scope, unique_id, type);
+    var = njs_variable_add(parser, parser->scope, unique_id, type);
     if (njs_slow_path(var == NULL)) {
         return NULL;
     }
@@ -7590,7 +7608,7 @@ njs_parser_reference(njs_parser_t *parse
                     return NULL;
                 }
 
-                var = njs_variable_add(parser->vm, scope, token->unique_id,
+                var = njs_variable_add(parser, scope, token->unique_id,
                                        NJS_VARIABLE_VAR);
                 if (njs_slow_path(var == NULL)) {
                     return NULL;
@@ -7625,7 +7643,7 @@ njs_parser_reference(njs_parser_t *parse
             return NULL;
         }
 
-        var = njs_variable_add(parser->vm, scope, token->unique_id,
+        var = njs_variable_add(parser, scope, token->unique_id,
                                NJS_VARIABLE_VAR);
         if (njs_slow_path(var == NULL)) {
             return NULL;
@@ -8319,46 +8337,6 @@ njs_parser_unexpected_token(njs_vm_t *vm
 }
 
 
-u_char *
-njs_parser_trace_handler(njs_trace_t *trace, njs_trace_data_t *td,
-    u_char *start)
-{
-    u_char        *p;
-    size_t        size;
-    njs_vm_t      *vm;
-    njs_lexer_t   *lexer;
-    njs_parser_t  *parser;
-
-    size = njs_length("InternalError: ");
-    memcpy(start, "InternalError: ", size);
-    p = start + size;
-
-    vm = trace->data;
-
-    trace = trace->next;
-    p = trace->handler(trace, td, p);
-
-    parser = vm->parser;
-
-    if (parser != NULL && parser->lexer != NULL) {
-        lexer = parser->lexer;
-
-        if (lexer->file.length != 0) {
-            njs_internal_error(vm, "%s in %V:%uD", start, &lexer->file,
-                               parser->lexer->token->line);
-        } else {
-            njs_internal_error(vm, "%s in %uD", start,
-                               parser->lexer->token->line);
-        }
-
-    } else {
-        njs_internal_error(vm, "%s", start);
-    }
-
-    return p;
-}
-
-
 static void
 njs_parser_scope_error(njs_vm_t *vm, njs_parser_scope_t *scope,
     njs_object_type_t type, uint32_t line, const char *fmt, va_list args)
diff -r 4197cc28ea9c -r 1f22e9008cc3 src/njs_parser.h
--- a/src/njs_parser.h	Fri Feb 19 17:27:44 2021 +0000
+++ b/src/njs_parser.h	Wed Feb 24 14:48:20 2021 +0000
@@ -110,7 +110,8 @@ njs_int_t njs_parser_failed_state(njs_pa
 
 intptr_t njs_parser_scope_rbtree_compare(njs_rbtree_node_t *node1,
     njs_rbtree_node_t *node2);
-njs_int_t njs_parser(njs_parser_t *parser, njs_parser_t *prev);
+njs_int_t njs_parser(njs_vm_t *vm, njs_parser_t *parser,
+    njs_rbtree_t *prev_vars);
 
 njs_int_t njs_parser_module_lambda(njs_parser_t *parser,
     njs_lexer_token_t *token, njs_queue_link_t *current);
@@ -121,8 +122,6 @@ njs_token_type_t njs_parser_unexpected_t
     njs_str_t *name, njs_token_type_t type);
 njs_int_t njs_parser_string_create(njs_vm_t *vm, njs_lexer_token_t *token,
     njs_value_t *value);
-u_char *njs_parser_trace_handler(njs_trace_t *trace, njs_trace_data_t *td,
-    u_char *start);
 void njs_parser_lexer_error(njs_parser_t *parser,
     njs_object_type_t type, const char *fmt, ...);
 void njs_parser_node_error(njs_vm_t *vm, njs_parser_node_t *node,
@@ -201,11 +200,11 @@ njs_parser_node_string(njs_vm_t *vm, njs
 
 
 njs_inline njs_parser_scope_t *
-njs_parser_global_scope(njs_vm_t *vm)
+njs_parser_global_scope(njs_parser_t *parser)
 {
     njs_parser_scope_t  *scope;
 
-    scope = vm->parser->scope;
+    scope = parser->scope;
 
     while (scope->type != NJS_SCOPE_GLOBAL) {
         scope = scope->parent;
diff -r 4197cc28ea9c -r 1f22e9008cc3 src/njs_regexp.c
--- a/src/njs_regexp.c	Fri Feb 19 17:27:44 2021 +0000
+++ b/src/njs_regexp.c	Wed Feb 24 14:48:20 2021 +0000
@@ -536,13 +536,7 @@ njs_regexp_compile_trace_handler(njs_tra
     trace = trace->next;
     p = trace->handler(trace, td, start);
 
-    if (vm->parser != NULL && vm->parser->lexer != NULL) {
-        njs_syntax_error(vm, "%*s in %uD", p - start, start,
-                         vm->parser->lexer->line);
-
-    } else {
-        njs_syntax_error(vm, "%*s", p - start, start);
-    }
+    njs_syntax_error(vm, "%*s", p - start, start);
 
     return p;
 }
diff -r 4197cc28ea9c -r 1f22e9008cc3 src/njs_shell.c
--- a/src/njs_shell.c	Fri Feb 19 17:27:44 2021 +0000
+++ b/src/njs_shell.c	Wed Feb 24 14:48:20 2021 +0000
@@ -996,8 +996,8 @@ njs_completion_generator(const char *tex
         cmpl->length = njs_strlen(text);
         cmpl->suffix_completions = NULL;
 
-        if (vm->parser != NULL) {
-            cmpl->node = njs_rbtree_min(&vm->parser->scope->variables);
+        if (vm->variables_hash != NULL) {
+            cmpl->node = njs_rbtree_min(vm->variables_hash);
         }
     }
 
@@ -1005,12 +1005,12 @@ next:
 
     switch (cmpl->phase) {
     case NJS_COMPLETION_VAR:
-        if (vm->parser == NULL) {
+        variables = vm->variables_hash;
+
+        if (variables == NULL) {
             njs_next_phase(cmpl);
         }
 
-        variables = &vm->parser->scope->variables;
-
         while (njs_rbtree_is_there_successor(variables, cmpl->node)) {
             var_node = (njs_variable_node_t *) cmpl->node;
 
diff -r 4197cc28ea9c -r 1f22e9008cc3 src/njs_variable.c
--- a/src/njs_variable.c	Fri Feb 19 17:27:44 2021 +0000
+++ b/src/njs_variable.c	Wed Feb 24 14:48:20 2021 +0000
@@ -9,7 +9,7 @@
 #include <njs_main.h>
 
 
-static njs_variable_t *njs_variable_scope_add(njs_vm_t *vm,
+static njs_variable_t *njs_variable_scope_add(njs_parser_t *parser,
     njs_parser_scope_t *scope, uintptr_t unique_id, njs_variable_type_t type);
 static njs_int_t njs_variable_reference_resolve(njs_vm_t *vm,
     njs_variable_reference_t *vr, njs_parser_scope_t *node_scope);
@@ -18,12 +18,12 @@ static njs_variable_t *njs_variable_allo
 
 
 njs_variable_t *
-njs_variable_add(njs_vm_t *vm, njs_parser_scope_t *scope, uintptr_t unique_id,
-    njs_variable_type_t type)
+njs_variable_add(njs_parser_t *parser, njs_parser_scope_t *scope,
+    uintptr_t unique_id, njs_variable_type_t type)
 {
     njs_variable_t  *var;
 
-    var = njs_variable_scope_add(vm, scope, unique_id, type);
+    var = njs_variable_scope_add(parser, scope, unique_id, type);
     if (njs_slow_path(var == NULL)) {
         return NULL;
     }
@@ -33,7 +33,7 @@ njs_variable_add(njs_vm_t *vm, njs_parse
         do {
             scope = scope->parent;
 
-            var = njs_variable_scope_add(vm, scope, unique_id, type);
+            var = njs_variable_scope_add(parser, scope, unique_id, type);
             if (njs_slow_path(var == NULL)) {
                 return NULL;
             }
@@ -78,7 +78,7 @@ njs_variables_copy(njs_vm_t *vm, njs_rbt
 
 
 static njs_variable_t *
-njs_variable_scope_add(njs_vm_t *vm, njs_parser_scope_t *scope,
+njs_variable_scope_add(njs_parser_t *parser, njs_parser_scope_t *scope,
     uintptr_t unique_id, njs_variable_type_t type)
 {
     njs_variable_t           *var;
@@ -104,7 +104,7 @@ njs_variable_scope_add(njs_vm_t *vm, njs
 
         if (scope->type == NJS_SCOPE_GLOBAL) {
 
-            if (vm->options.module) {
+            if (parser->vm->options.module) {
                 if (type == NJS_VARIABLE_FUNCTION
                     || var->type == NJS_VARIABLE_FUNCTION)
                 {
@@ -116,12 +116,12 @@ njs_variable_scope_add(njs_vm_t *vm, njs
         return var;
     }
 
-    var = njs_variable_alloc(vm, unique_id, type);
+    var = njs_variable_alloc(parser->vm, unique_id, type);
     if (njs_slow_path(var == NULL)) {
         goto memory_error;
     }
 
-    var_node_new = njs_variable_node_alloc(vm, var, unique_id);
+    var_node_new = njs_variable_node_alloc(parser->vm, var, unique_id);
     if (njs_slow_path(var_node_new == NULL)) {
         goto memory_error;
     }
@@ -132,7 +132,7 @@ njs_variable_scope_add(njs_vm_t *vm, njs
 
 memory_error:
 
-    njs_memory_error(vm);
+    njs_memory_error(parser->vm);
 
     return NULL;
 
@@ -140,8 +140,7 @@ fail:
 
     entry = njs_lexer_entry(unique_id);
 
-    njs_parser_syntax_error(vm->parser,
-                            "\"%V\" has already been declared",
+    njs_parser_syntax_error(parser, "\"%V\" has already been declared",
                             &entry->name);
     return NULL;
 }
diff -r 4197cc28ea9c -r 1f22e9008cc3 src/njs_variable.h
--- a/src/njs_variable.h	Fri Feb 19 17:27:44 2021 +0000
+++ b/src/njs_variable.h	Wed Feb 24 14:48:20 2021 +0000
@@ -55,8 +55,8 @@ typedef struct {
 } njs_variable_node_t;
 
 
-njs_variable_t *njs_variable_add(njs_vm_t *vm, njs_parser_scope_t *scope,
-    uintptr_t unique_id, njs_variable_type_t type);
+njs_variable_t *njs_variable_add(njs_parser_t *parser,
+    njs_parser_scope_t *scope, uintptr_t unique_id, njs_variable_type_t type);
 njs_int_t njs_variables_copy(njs_vm_t *vm, njs_rbtree_t *variables,
     njs_rbtree_t *prev_variables);
 njs_variable_t * njs_label_add(njs_vm_t *vm, njs_parser_scope_t *scope,
diff -r 4197cc28ea9c -r 1f22e9008cc3 src/njs_vm.c
--- a/src/njs_vm.c	Fri Feb 19 17:27:44 2021 +0000
+++ b/src/njs_vm.c	Wed Feb 24 14:48:20 2021 +0000
@@ -68,7 +68,6 @@ njs_vm_create(njs_vm_opt_t *options)
 
     vm->trace.level = NJS_LEVEL_TRACE;
     vm->trace.size = 2048;
-    vm->trace.handler = njs_parser_trace_handler;
     vm->trace.data = vm;
 
     njs_set_undefined(&vm->retval);
@@ -113,66 +112,48 @@ njs_vm_destroy(njs_vm_t *vm)
 njs_int_t
 njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end)
 {
-    njs_int_t           ret;
-    njs_str_t           ast;
-    njs_chb_t           chain;
-    njs_lexer_t         lexer;
-    njs_parser_t        *parser, *prev;
-    njs_vm_code_t       *code;
-    njs_generator_t     generator;
-    njs_parser_scope_t  *scope;
-
-    if (vm->parser != NULL && !vm->options.accumulative) {
-        return NJS_ERROR;
-    }
+    njs_int_t        ret;
+    njs_str_t        ast;
+    njs_chb_t        chain;
+    njs_lexer_t      lexer;
+    njs_parser_t     parser;
+    njs_vm_code_t    *code;
+    njs_generator_t  generator;
 
     if (vm->modules != NULL && vm->options.accumulative) {
         njs_module_reset(vm);
     }
 
-    parser = njs_mp_zalloc(vm->mem_pool, sizeof(njs_parser_t));
-    if (njs_slow_path(parser == NULL)) {
-        return NJS_ERROR;
-    }
-
-    prev = vm->parser;
-    vm->parser = parser;
-
     ret = njs_lexer_init(vm, &lexer, &vm->options.file, *start, end);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
-    parser->vm = vm;
-    parser->lexer = &lexer;
+    njs_memzero(&parser, sizeof(njs_parser_t));
 
-    njs_set_undefined(&vm->retval);
+    parser.lexer = &lexer;
 
-    ret = njs_parser(parser, prev);
+    ret = njs_parser(vm, &parser, vm->variables_hash);
     if (njs_slow_path(ret != NJS_OK)) {
-        goto fail;
-    }
-
-    parser->lexer = NULL;
-
-    scope = parser->scope;
-
-    ret = njs_variables_scope_reference(vm, scope);
-    if (njs_slow_path(ret != NJS_OK)) {
-        goto fail;
+        return NJS_ERROR;
     }
 
     *start = lexer.start;
 
+    ret = njs_variables_scope_reference(vm, parser.scope);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
     njs_memzero(&generator, sizeof(njs_generator_t));
 
-    code = njs_generate_scope(vm, &generator, scope, &njs_entry_main);
+    code = njs_generate_scope(vm, &generator, parser.scope, &njs_entry_main);
     if (njs_slow_path(code == NULL)) {
         if (!njs_is_error(&vm->retval)) {
             njs_internal_error(vm, "njs_generate_scope() failed");
         }
 
-        goto fail;
+        return NJS_ERROR;
     }
 
     vm->main_index = code - (njs_vm_code_t *) vm->codes->start;
@@ -180,7 +161,7 @@ njs_vm_compile(njs_vm_t *vm, u_char **st
     vm->global_scope = generator.local_scope;
     vm->scope_size = generator.scope_size;
 
-    vm->variables_hash = &scope->variables;
+    vm->variables_hash = &parser.scope->variables;
 
     if (vm->options.init && !vm->options.accumulative) {
         ret = njs_vm_init(vm);
@@ -195,7 +176,7 @@ njs_vm_compile(njs_vm_t *vm, u_char **st
 
     if (njs_slow_path(vm->options.ast)) {
         njs_chb_init(&chain, vm->mem_pool);
-        ret = njs_parser_serialize_ast(parser->node, &chain);
+        ret = njs_parser_serialize_ast(parser.node, &chain);
         if (njs_slow_path(ret == NJS_ERROR)) {
             return ret;
         }
@@ -210,13 +191,7 @@ njs_vm_compile(njs_vm_t *vm, u_char **st
         njs_mp_free(vm->mem_pool, ast.start);
     }
 
-    return ret;
-
-fail:
-
-    vm->parser = prev;
-
-    return NJS_ERROR;
+    return NJS_OK;
 }
 
 
diff -r 4197cc28ea9c -r 1f22e9008cc3 src/njs_vm.h
--- a/src/njs_vm.h	Fri Feb 19 17:27:44 2021 +0000
+++ b/src/njs_vm.h	Wed Feb 24 14:48:20 2021 +0000
@@ -218,7 +218,6 @@ struct njs_vm_s {
     size_t                   stack_size;
 
     njs_vm_shared_t          *shared;
-    njs_parser_t             *parser;
 
     njs_regex_context_t      *regex_context;
     njs_regex_match_data_t   *single_match_data;
diff -r 4197cc28ea9c -r 1f22e9008cc3 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Fri Feb 19 17:27:44 2021 +0000
+++ b/src/test/njs_unit_test.c	Wed Feb 24 14:48:20 2021 +0000
@@ -12696,25 +12696,26 @@ static njs_unit_test_t  njs_test[] =
       njs_str("1") },
 
     { njs_str("var sum = new Function('a', 'b', 'return a + b');"
-                 "sum(2, 4);"),
+              "sum(2, 4);"),
       njs_str("6") },
 
     { njs_str("var sum = new Function('a, b', 'return a + b');"
-                 "sum(2, 4);"),
+              "sum(2, 4);"),
       njs_str("6") },
 
     { njs_str("var sum = new Function('a, b', 'c', 'return a + b + c');"
-                 "sum(2, 4, 4);"),
+              "sum(2, 4, 4);"),
       njs_str("10") },
 
     { njs_str("(new Function({ toString() { return '...a'; }}, { toString() { return 'return a;' }}))(1,2,3)"),
       njs_str("1,2,3") },
 
     { njs_str("var x = 10; function foo() { var x = 20; return new Function('return x;'); }"
-                 "var f = foo(); f()"),
+              "var f = foo(); f()"),
       njs_str("10") },
 
-    { njs_str("var fn = (function() { return new Function('return this'); }).call({}), o = {}; fn.call(o) == o && fn.bind(o).call(this) == o"),
+    { njs_str("var fn = (function() { return new Function('return this'); }).call({}), o = {}; "
+              "fn.call(o) == o && fn.bind(o).call(this) == o"),
       njs_str("true") },
 
     { njs_str("(new Function('return this'))() === globalThis"),
@@ -12733,6 +12734,10 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("var o = {}; (new Function('return this')).call(o) === o"),
       njs_str("true") },
 
+    { njs_str("(new Function('function foo(){return 1}; return foo()'))();"
+              "foo"),
+      njs_str("ReferenceError: \"foo\" is not defined") },
+
     { njs_str("this.NN = {}; var f = Function('eval = 42;'); f()"),
       njs_str("SyntaxError: Identifier \"eval\" is forbidden as left-hand in assignment in runtime:1") },
 
@@ -20315,6 +20320,11 @@ static njs_unit_test_t  njs_shell_test[]
               "Number.prototype.test" ENTER),
       njs_str("test") },
 
+    { njs_str("try {(new Function('function foo(){return 1}; ()=>{}breakhere'))} catch (e) {}" ENTER
+              "foo()" ENTER),
+      njs_str("ReferenceError: \"foo\" is not defined\n"
+              "    at main (:1)\n") },
+
     /* Error handling */
 
     { njs_str("var a = ;" ENTER


More information about the nginx-devel mailing list