[njs] Removed recursion from code generator.

Alexander Borisov alexander.borisov at nginx.com
Thu Jul 15 17:34:49 UTC 2021


details:   https://hg.nginx.org/njs/rev/efdc5f18195e
branches:  
changeset: 1680:efdc5f18195e
user:      Alexander Borisov <alexander.borisov at nginx.com>
date:      Thu Jul 15 20:32:40 2021 +0300
description:
Removed recursion from code generator.

diffstat:

 src/njs_generator.c      |  3118 ++++++++++++++++++++++++++++++---------------
 src/njs_generator.h      |    10 +
 src/test/njs_unit_test.c |    53 +-
 3 files changed, 2141 insertions(+), 1040 deletions(-)

diffs (truncated from 4386 to 1000 lines):

diff -r 1ed302b68909 -r efdc5f18195e src/njs_generator.c
--- a/src/njs_generator.c	Thu Jul 15 14:51:57 2021 +0000
+++ b/src/njs_generator.c	Thu Jul 15 20:32:40 2021 +0300
@@ -12,6 +12,15 @@
 
 typedef struct njs_generator_patch_s   njs_generator_patch_t;
 
+typedef enum {
+    NJS_GENERATOR_LOOP = 1,
+    NJS_GENERATOR_SWITCH = 2,
+    NJS_GENERATOR_BLOCK = 4,
+    NJS_GENERATOR_TRY = 8,
+#define NJS_GENERATOR_ALL          (NJS_GENERATOR_LOOP | NJS_GENERATOR_SWITCH)
+} njs_generator_block_type_t;
+
+
 struct njs_generator_patch_s {
     /*
      * The jump_offset field points to jump offset field which contains a small
@@ -26,15 +35,6 @@ struct njs_generator_patch_s {
 };
 
 
-typedef enum {
-    NJS_GENERATOR_LOOP = 1,
-    NJS_GENERATOR_SWITCH = 2,
-    NJS_GENERATOR_BLOCK = 4,
-    NJS_GENERATOR_TRY = 8,
-#define NJS_GENERATOR_ALL          (NJS_GENERATOR_LOOP | NJS_GENERATOR_SWITCH)
-} njs_generator_block_type_t;
-
-
 struct njs_generator_block_s {
     njs_generator_block_type_t      type;    /* 4 bits */
     njs_str_t                       label;
@@ -54,12 +54,50 @@ struct njs_generator_block_s {
 };
 
 
-static njs_int_t njs_generator(njs_vm_t *vm, njs_generator_t *generator,
-    njs_parser_node_t *node);
+typedef struct {
+    njs_generator_state_func_t  state;
+    njs_queue_link_t            link;
+    njs_parser_node_t           *node;
+    void                        *context;
+} njs_generator_stack_entry_t;
+
+
+typedef struct {
+    njs_generator_patch_t       *patch;
+    njs_generator_patch_t       **last;
+    njs_vmcode_jump_t           *jump;
+    njs_jump_off_t              jump_offset;
+    njs_index_t                 index;
+} njs_generator_switch_ctx_t;
+
+
+typedef struct {
+    njs_jump_off_t              jump_offset;
+    njs_jump_off_t              loop_offset;
+    njs_vmcode_jump_t           *jump;
+    njs_variable_t              *var;
+    njs_index_t                 index;
+} njs_generator_loop_ctx_t;
+
+
+typedef struct {
+    njs_index_t                 exception_index;
+    njs_jump_off_t              try_offset;
+    njs_jump_off_t              catch_offset;
+    njs_generator_block_t       *try_block;
+    njs_generator_block_t       *catch_block;
+    njs_str_t                   try_cont_label;
+    njs_str_t                   try_exit_label;
+    njs_str_t                   catch_cont_label;
+    njs_str_t                   catch_exit_label;
+} njs_generator_try_ctx_t;
+
+
 static u_char *njs_generate_reserve(njs_vm_t *vm, njs_generator_t *generator,
     size_t size);
 static njs_int_t njs_generate_code_map(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node, u_char *code);
+
 static njs_int_t njs_generate_name(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node);
 static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator,
@@ -67,26 +105,72 @@ static njs_int_t njs_generate_variable(n
     njs_variable_t **retvar);
 static njs_int_t njs_generate_var_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_var_statement_after(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_let(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node, njs_variable_t *var);
 static njs_int_t njs_generate_if_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_if_statement_cond(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_if_statement_then(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_if_statement_else(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_cond_expression(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_cond_expression_handler(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_cond_expression_true(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_cond_expression_false(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_switch_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_switch_expression(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *swtch);
+static njs_int_t njs_generate_switch_case(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *swtch);
+static njs_int_t njs_generate_switch_case_after(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *branch);
+static njs_int_t njs_generate_switch_case_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *branch);
+static njs_int_t njs_generate_switch_default(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *branch);
+static njs_int_t njs_generate_switch_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *swtch);
 static njs_int_t njs_generate_while_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_while_condition(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_while_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_do_while_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_do_while_condition(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_do_while_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_for_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_for_init(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node);
+static njs_int_t njs_generate_for_body(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node);
+static njs_int_t njs_generate_for_update(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_for_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node);
 static njs_int_t njs_generate_for_let_update(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node, size_t depth);
 static njs_int_t njs_generate_for_resolve_closure(njs_vm_t *vm,
     njs_parser_node_t *node, size_t depth);
 static njs_int_t njs_generate_for_in_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_for_in_object(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_for_in_body(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_start_block(njs_vm_t *vm,
     njs_generator_t *generator, njs_generator_block_type_t type,
     const njs_str_t *label);
@@ -117,20 +201,40 @@ static njs_int_t njs_generate_statement(
     njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_block_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_block_statement_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_children(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node);
 static njs_int_t njs_generate_stop_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_stop_statement_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_comma_expression(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_comma_expression_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_assignment(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_assignment_name(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_assignment_prop(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_assignment_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_operation_assignment(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_operation_assignment_name(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_operation_assignment_prop(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_operation_assignment_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_object(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node);
 static njs_int_t njs_generate_property_accessor(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_property_accessor_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_array(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node);
 static njs_int_t njs_generate_function_expression(njs_vm_t *vm,
@@ -141,41 +245,92 @@ static njs_int_t njs_generate_regexp(njs
     njs_parser_node_t *node);
 static njs_int_t njs_generate_template_literal(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_template_literal_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_test_jump_expression(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_test_jump_expression_after(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_test_jump_expression_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_3addr_operation(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node, njs_bool_t swap);
+static njs_int_t njs_generate_3addr_operation_name(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_3addr_operation_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_2addr_operation(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_2addr_operation_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_typeof_operation(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_typeof_operation_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_inc_dec_operation(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node, njs_bool_t post);
+static njs_int_t njs_generate_inc_dec_operation_prop(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_function_declaration(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_function_scope(njs_vm_t *vm,
     njs_function_lambda_t *lambda, njs_parser_node_t *node,
     const njs_str_t *name);
+static njs_int_t njs_generate_scope_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static int64_t njs_generate_lambda_variables(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_return_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_return_statement_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_function_call(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_function_call_arguments(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_function_call_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_method_call(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_method_call_arguments(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_method_call_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_call(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node);
 static njs_int_t njs_generate_move_arguments(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_try_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_try_left(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node);
+static njs_int_t njs_generate_try_catch(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_try_finally(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_try_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node);
 static njs_int_t njs_generate_throw_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_throw_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_import_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_import_statement_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_export_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_export_statement_end(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_wo_dest(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_wo_dest_after(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_global_reference(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node, njs_bool_t exception);
+static njs_int_t njs_generate_reference_error(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+
 static njs_index_t njs_generate_dest_index(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
 static njs_index_t njs_generate_object_dest_index(njs_vm_t *vm,
@@ -186,14 +341,14 @@ static njs_index_t njs_generate_temp_ind
     njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_children_indexes_release(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_children_indexes_release_pop(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_node_index_release(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
+static njs_int_t njs_generate_node_index_release_pop(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_index_release(njs_vm_t *vm,
     njs_generator_t *generator, njs_index_t index);
-static njs_int_t njs_generate_global_reference(njs_vm_t *vm,
-    njs_generator_t *generator, njs_parser_node_t *node, njs_bool_t exception);
-static njs_int_t njs_generate_reference_error(njs_vm_t *vm,
-    njs_generator_t *generator, njs_parser_node_t *node);
 
 
 #define njs_generate_code(generator, type, _code, _op, nargs, nd)             \
@@ -278,11 +433,77 @@ static const njs_str_t  return_label = n
 static const njs_str_t  undef_label  = { 0xffffffff, (u_char *) "" };
 
 
+njs_inline void
+njs_generator_next(njs_generator_t *generator, njs_generator_state_func_t state,
+    njs_parser_node_t *node)
+{
+    generator->state = state;
+    generator->node = node;
+}
+
+
+njs_inline njs_int_t
+njs_generator_after(njs_vm_t *vm, njs_generator_t *generator,
+    njs_queue_link_t *link, njs_parser_node_t *node,
+    njs_generator_state_func_t state, void *ctx, size_t size)
+{
+    njs_generator_stack_entry_t  *entry;
+
+    entry = njs_mp_alloc(vm->mem_pool, sizeof(njs_parser_stack_entry_t));
+    if (njs_slow_path(entry == NULL)) {
+        return NJS_ERROR;
+    }
+
+    entry->state = state;
+    entry->node = node;
+    entry->context = ctx;
+
+    njs_queue_insert_before(link, &entry->link);
+
+    if (size > 0) {
+        entry->context = njs_mp_alloc(vm->mem_pool, size);
+        if (njs_slow_path(entry->context == NULL)) {
+            return NJS_ERROR;
+        }
+
+        memcpy(entry->context, ctx, size);
+    }
+
+    return NJS_OK;
+}
+
+
+njs_inline njs_int_t
+njs_generator_stack_pop(njs_vm_t *vm, njs_generator_t *generator, void *ctx)
+{
+    njs_queue_link_t             *link;
+    njs_generator_stack_entry_t  *entry;
+
+    entry = njs_queue_link_data(njs_queue_first(&generator->stack),
+                                njs_generator_stack_entry_t, link);
+
+    link = njs_queue_first(&generator->stack);
+    njs_queue_remove(link);
+
+    if (ctx != NULL) {
+        njs_mp_free(vm->mem_pool, ctx);
+    }
+
+    generator->context = entry->context;
+
+    njs_generator_next(generator, entry->state, entry->node);
+
+    njs_mp_free(vm->mem_pool, entry);
+
+    return NJS_OK;
+}
+
+
 static njs_int_t
 njs_generate(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node)
 {
     if (node == NULL) {
-        return NJS_OK;
+        return njs_generator_stack_pop(vm, generator, NULL);
     }
 
     switch (node->token_type) {
@@ -420,11 +641,11 @@ njs_generate(njs_vm_t *vm, njs_generator
             return NJS_ERROR;
         }
 
-        return NJS_OK;
+        return njs_generator_stack_pop(vm, generator, NULL);
 
     case NJS_TOKEN_OBJECT_VALUE:
         node->index = node->u.object->index;
-        return NJS_OK;
+        return njs_generator_stack_pop(vm, generator, NULL);
 
     case NJS_TOKEN_OBJECT:
         return njs_generate_object(vm, generator, node);
@@ -449,7 +670,7 @@ njs_generate(njs_vm_t *vm, njs_generator
         return njs_generate_template_literal(vm, generator, node);
 
     case NJS_TOKEN_EXTERNAL:
-        return NJS_OK;
+        return njs_generator_stack_pop(vm, generator, NULL);
 
     case NJS_TOKEN_NAME:
     case NJS_TOKEN_ARGUMENTS:
@@ -490,40 +711,11 @@ njs_generate(njs_vm_t *vm, njs_generator
 }
 
 
-njs_inline njs_int_t
-njs_generator(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node)
-{
-    njs_int_t  ret;
-
-    if (njs_slow_path(generator->count++ > NJS_GENERATE_MAX_DEPTH)) {
-        njs_range_error(vm, "Maximum call stack size exceeded");
-        return NJS_ERROR;
-    }
-
-    ret = njs_generate(vm, generator, node);
-
-    generator->count--;
-
-    return ret;
-}
-
-
 static njs_int_t
-njs_generate_wo_dest(njs_vm_t *vm, njs_generator_t *generator,
+njs_generator_pop(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t           ret;
-    njs_parser_scope_t  *scope;
-
-    scope = njs_function_scope(node->scope);
-
-    scope->dest_disable = 1;
-
-    ret = njs_generator(vm, generator, node);
-
-    scope->dest_disable = 0;
-
-    return ret;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -625,6 +817,7 @@ static njs_int_t
 njs_generate_name(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
+    njs_int_t                   ret;
     njs_variable_t              *var;
     njs_parser_scope_t          *scope;
     njs_vmcode_variable_t       *variable;
@@ -632,7 +825,12 @@ njs_generate_name(njs_vm_t *vm, njs_gene
 
     var = njs_variable_reference(vm, node);
     if (njs_slow_path(var == NULL)) {
-        return njs_generate_global_reference(vm, generator, node, 1);
+        ret = njs_generate_global_reference(vm, generator, node, 1);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return ret;
+        }
+
+        return njs_generator_stack_pop(vm, generator, NULL);
     }
 
     if (var->function && var->type == NJS_VARIABLE_FUNCTION) {
@@ -643,7 +841,7 @@ njs_generate_name(njs_vm_t *vm, njs_gene
     }
 
     if (var->init) {
-        return NJS_OK;
+        return njs_generator_stack_pop(vm, generator, NULL);
     }
 
     if (var->type == NJS_VARIABLE_LET || var->type == NJS_VARIABLE_CONST) {
@@ -656,7 +854,7 @@ njs_generate_name(njs_vm_t *vm, njs_gene
         }
     }
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -738,7 +936,6 @@ njs_generate_var_statement(njs_vm_t *vm,
     njs_int_t          ret;
     njs_variable_t     *var;
     njs_parser_node_t  *lvalue, *expr;
-    njs_vmcode_move_t  *move;
 
     lvalue = node->left;
 
@@ -767,7 +964,7 @@ njs_generate_var_statement(njs_vm_t *vm,
 
         var->init = 1;
 
-        return NJS_OK;
+        return njs_generator_stack_pop(vm, generator, NULL);
     }
 
     if (var->type == NJS_VARIABLE_LET || var->type == NJS_VARIABLE_CONST) {
@@ -776,15 +973,33 @@ njs_generate_var_statement(njs_vm_t *vm,
             return ret;
         }
 
-        ret = njs_generate_let(vm, generator, node, var);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
-
     } else {
         expr->dest = lvalue;
 
-        ret = njs_generator(vm, generator, expr);
+        njs_generator_next(generator, njs_generate, expr);
+    }
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_var_statement_after, var, 0);
+}
+
+
+static njs_int_t
+njs_generate_var_statement_after(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t          ret;
+    njs_variable_t     *var;
+    njs_parser_node_t  *lvalue, *expr;
+    njs_vmcode_move_t  *move;
+
+    lvalue = node->left;
+    expr = node->right;
+    var = generator->context;
+
+    if (var->type == NJS_VARIABLE_LET || var->type == NJS_VARIABLE_CONST) {
+        ret = njs_generate_let(vm, generator, node, var);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
@@ -804,7 +1019,7 @@ njs_generate_var_statement(njs_vm_t *vm,
     node->index = expr->index;
     node->temporary = expr->temporary;
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -826,18 +1041,24 @@ static njs_int_t
 njs_generate_if_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
+    /* The condition expression. */
+
+    njs_generator_next(generator, njs_generate, node->left);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_if_statement_cond, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_if_statement_cond(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
     njs_int_t               ret;
-    njs_jump_off_t          jump_offset, label_offset;
-    njs_vmcode_jump_t       *jump;
+    njs_jump_off_t          jump_offset;
     njs_vmcode_cond_jump_t  *cond_jump;
 
-    /* The condition expression. */
-
-    ret = njs_generator(vm, generator, node->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
-
     njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
                       NJS_VMCODE_IF_FALSE_JUMP, 2, node);
     cond_jump->cond = node->left->index;
@@ -848,7 +1069,6 @@ njs_generate_if_statement(njs_vm_t *vm, 
     }
 
     jump_offset = njs_code_offset(generator, cond_jump);
-    label_offset = jump_offset + offsetof(njs_vmcode_cond_jump_t, offset);
 
     if (node->right != NULL && node->right->token_type == NJS_TOKEN_BRANCHING) {
 
@@ -856,22 +1076,12 @@ njs_generate_if_statement(njs_vm_t *vm, 
 
         node = node->right;
 
-        ret = njs_generator(vm, generator, node->left);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
-
-        ret = njs_generate_node_index_release(vm, generator, node->left);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
-
-        njs_generate_code_jump(generator, jump, 0);
-
-        njs_code_set_offset(generator, label_offset, jump_offset);
-
-        jump_offset = njs_code_offset(generator, jump);
-        label_offset = jump_offset + offsetof(njs_vmcode_jump_t, offset);
+        njs_generator_next(generator, njs_generate, node->left);
+
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), node,
+                                   njs_generate_if_statement_then,
+                                   &jump_offset, sizeof(njs_jump_off_t));
     }
 
     /*
@@ -879,19 +1089,63 @@ njs_generate_if_statement(njs_vm_t *vm, 
      * or the "else" branch in a case of "if/then/else" statement.
      */
 
-    ret = njs_generator(vm, generator, node->right);
+    njs_generator_next(generator, njs_generate, node->right);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_if_statement_else,
+                               &jump_offset, sizeof(njs_jump_off_t));
+}
+
+
+static njs_int_t
+njs_generate_if_statement_then(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t          ret;
+    njs_jump_off_t     *jump_offset, label_offset;
+    njs_vmcode_jump_t  *jump;
+
+    ret = njs_generate_node_index_release(vm, generator, node->left);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
+    jump_offset = (njs_jump_off_t *) generator->context;
+    label_offset = *jump_offset + offsetof(njs_vmcode_cond_jump_t, offset);
+
+    njs_generate_code_jump(generator, jump, 0);
+    njs_code_set_offset(generator, label_offset, *jump_offset);
+
+    *jump_offset = njs_code_offset(generator, jump);
+
+    njs_generator_next(generator, njs_generate, node->right);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_if_statement_else,
+                               jump_offset, 0);
+}
+
+
+static njs_int_t
+njs_generate_if_statement_else(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t       ret;
+    njs_jump_off_t  *jump_offset, label_offset;
+
+    jump_offset = (njs_jump_off_t *) generator->context;
+    label_offset = *jump_offset + offsetof(njs_vmcode_cond_jump_t, offset);
+
     ret = njs_generate_node_index_release(vm, generator, node->right);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
-    njs_code_set_offset(generator, label_offset, jump_offset);
-
-    return NJS_OK;
+    njs_code_set_offset(generator, label_offset, *jump_offset);
+
+    return njs_generator_stack_pop(vm, generator, generator->context);
 }
 
 
@@ -899,40 +1153,53 @@ static njs_int_t
 njs_generate_cond_expression(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t               ret;
-    njs_jump_off_t          jump_offset, cond_jump_offset;
-    njs_parser_node_t       *branch;
-    njs_vmcode_move_t       *move;
-    njs_vmcode_jump_t       *jump;
+    njs_generator_next(generator, njs_generate, node->left);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_cond_expression_handler, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_cond_expression_handler(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_jump_off_t          jump_offset;
     njs_vmcode_cond_jump_t  *cond_jump;
 
-    /* The condition expression. */
-
-    ret = njs_generator(vm, generator, node->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
-
     njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
                       NJS_VMCODE_IF_FALSE_JUMP, 2, node);
 
-    cond_jump_offset = njs_code_offset(generator, cond_jump);
+    jump_offset = njs_code_offset(generator, cond_jump);
     cond_jump->cond = node->left->index;
 
     node->index = njs_generate_dest_index(vm, generator, node);
     if (njs_slow_path(node->index == NJS_INDEX_ERROR)) {
-        return node->index;
-    }
+        return NJS_ERROR;
+    }
+
+    njs_generator_next(generator, njs_generate, node->right->left);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_cond_expression_true,
+                               &jump_offset, sizeof(njs_jump_off_t));
+}
+
+
+static njs_int_t
+njs_generate_cond_expression_true(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t          ret;
+    njs_jump_off_t     jump_offset;
+    njs_parser_node_t  *branch;
+    njs_vmcode_move_t  *move;
+    njs_vmcode_jump_t  *jump;
 
     branch = node->right;
 
-    /* The "true" branch. */
-
-    ret = njs_generator(vm, generator, branch->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
-
     /*
      * Branches usually uses node->index as destination, however,
      * if branch expression is a literal, variable or assignment,
@@ -953,28 +1220,41 @@ njs_generate_cond_expression(njs_vm_t *v
     jump_offset = njs_code_offset(generator, jump);
 
     njs_code_set_jump_offset(generator, njs_vmcode_cond_jump_t,
-                             cond_jump_offset);
-
-    /* The "false" branch. */
-
-    ret = njs_generator(vm, generator, branch->right);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+                             *((njs_jump_off_t *) generator->context));
+
+    njs_generator_next(generator, njs_generate, branch->right);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_cond_expression_false,
+                               &jump_offset, sizeof(njs_jump_off_t));
+}
+
+
+static njs_int_t
+njs_generate_cond_expression_false(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t          ret;
+    njs_parser_node_t  *branch;
+    njs_vmcode_move_t  *move;
+
+    branch = node->right;
 
     if (node->index != branch->right->index) {
         njs_generate_code_move(generator, move, node->index,
                                branch->right->index, node);
     }
 
-    njs_code_set_jump_offset(generator, njs_vmcode_cond_jump_t, jump_offset);
+    njs_code_set_jump_offset(generator, njs_vmcode_cond_jump_t,
+                             *((njs_jump_off_t *) generator->context));
 
     ret = njs_generate_node_index_release(vm, generator, branch->right);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, generator->context);
 }
 
 
@@ -982,33 +1262,40 @@ static njs_int_t
 njs_generate_switch_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *swtch)
 {
-    njs_int_t                ret;
-    njs_jump_off_t           jump_offset;
-    njs_index_t              index;
-    njs_parser_node_t        *node, *expr, *branch;
-    njs_vmcode_move_t        *move;
-    njs_vmcode_jump_t        *jump;
-    njs_generator_patch_t    *patch, *next, *patches, **last;
-    njs_vmcode_equal_jump_t  *equal;
+    njs_generator_switch_ctx_t  ctx;
 
     /* The "switch" expression. */
 
+    njs_generator_next(generator, njs_generate, swtch->left);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), swtch,
+                               njs_generate_switch_expression,
+                               &ctx, sizeof(njs_generator_switch_ctx_t));
+}
+
+
+static njs_int_t
+njs_generate_switch_expression(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *swtch)
+{
+    njs_int_t                   ret;
+    njs_parser_node_t           *expr;
+    njs_vmcode_move_t           *move;
+    njs_generator_switch_ctx_t  *ctx;
+
+    ctx = generator->context;
+
     expr = swtch->left;
-
-    ret = njs_generator(vm, generator, expr);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
-
-    index = expr->index;
+    ctx->index = expr->index;
 
     if (!expr->temporary) {
-        index = njs_generate_temp_index_get(vm, generator, swtch);
-        if (njs_slow_path(index == NJS_INDEX_ERROR)) {
+        ctx->index = njs_generate_temp_index_get(vm, generator, swtch);
+        if (njs_slow_path(ctx->index == NJS_INDEX_ERROR)) {
             return NJS_ERROR;
         }
 
-        njs_generate_code_move(generator, move, index, expr->index, swtch);
+        njs_generate_code_move(generator, move, ctx->index, expr->index, swtch);
     }
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_SWITCH,
@@ -1017,95 +1304,198 @@ njs_generate_switch_statement(njs_vm_t *
         return ret;
     }
 
-    patches = NULL;
-    last = &patches;
-
-    for (branch = swtch->right; branch != NULL; branch = branch->left) {
-
-        if (branch->token_type != NJS_TOKEN_DEFAULT) {
-
-            /* The "case" expression. */
-
-            node = branch->right;
-
-            ret = njs_generator(vm, generator, node->left);
-            if (njs_slow_path(ret != NJS_OK)) {
-                return ret;
-            }
-
-            njs_generate_code(generator, njs_vmcode_equal_jump_t, equal,
-                              NJS_VMCODE_IF_EQUAL_JUMP, 3, branch);
-            equal->offset = offsetof(njs_vmcode_equal_jump_t, offset);
-            equal->value1 = index;
-            equal->value2 = node->left->index;
-
-            ret = njs_generate_node_index_release(vm, generator, node->left);
-            if (njs_slow_path(ret != NJS_OK)) {
-                return ret;
-            }
-
-            patch = njs_mp_alloc(vm->mem_pool, sizeof(njs_generator_patch_t));
-            if (njs_slow_path(patch == NULL)) {
-                return NJS_ERROR;
-            }
-
-            patch->jump_offset = njs_code_offset(generator, equal)
-                                 + offsetof(njs_vmcode_equal_jump_t, offset);
-            patch->label = no_label;
-
-            *last = patch;
-            last = &patch->next;
+    ctx->patch = NULL;
+    ctx->last = &ctx->patch;
+
+    if (swtch->right != NULL) {
+
+        /* The "case" expression. */
+
+        njs_generator_next(generator, njs_generate_switch_case, swtch->right);
+
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), swtch,
+                                   njs_generate_switch_case_end, ctx, 0);
+    }
+
+    return njs_generate_switch_case_end(vm, generator, swtch);
+}
+
+
+static njs_int_t
+njs_generate_switch_case(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *branch)
+{
+    if (branch->token_type == NJS_TOKEN_DEFAULT) {
+        if (branch->left == NULL) {
+            return njs_generator_stack_pop(vm, generator, NULL);
         }
-    }
+
+        branch = branch->left;
+    }
+
+    njs_generator_next(generator, njs_generate, branch->right->left);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), branch,
+                               njs_generate_switch_case_after,
+                               generator->context, 0);
+}
+
+
+static njs_int_t
+njs_generate_switch_case_after(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *branch)
+{
+    njs_int_t                   ret;
+    njs_parser_node_t           *node;
+    njs_generator_patch_t       *patch;
+    njs_vmcode_equal_jump_t     *equal;
+    njs_generator_switch_ctx_t  *ctx;
+
+    ctx = generator->context;
+    node = branch->right;
+
+    njs_generate_code(generator, njs_vmcode_equal_jump_t, equal,
+                      NJS_VMCODE_IF_EQUAL_JUMP, 3, branch);
+    equal->offset = offsetof(njs_vmcode_equal_jump_t, offset);
+    equal->value1 = ctx->index;
+    equal->value2 = node->left->index;
+
+    ret = njs_generate_node_index_release(vm, generator, node->left);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    patch = njs_mp_alloc(vm->mem_pool, sizeof(njs_generator_patch_t));
+    if (njs_slow_path(patch == NULL)) {
+        return NJS_ERROR;


More information about the nginx-devel mailing list