]> git.kaiwu.me - njs.git/commitdiff
Removed recursion from code generator.
authorAlexander Borisov <alexander.borisov@nginx.com>
Thu, 15 Jul 2021 17:32:40 +0000 (20:32 +0300)
committerAlexander Borisov <alexander.borisov@nginx.com>
Thu, 15 Jul 2021 17:32:40 +0000 (20:32 +0300)
src/njs_generator.c
src/njs_generator.h
src/test/njs_unit_test.c

index 0a021db60a0beaef1ead7bbb61a95e6f58b402dd..1bfdbb6e3e7f730c12e86f9d4036303666f70ba0 100644 (file)
 
 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(njs_vm_t *vm, njs_generator_t *generator,
     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_vm_t *vm,
     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_vm_t *vm, njs_generator_t *generator,
     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_index_get(njs_vm_t *vm,
     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 = njs_str("@return");
 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_t *generator, njs_parser_node_t *node)
             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_t *generator, njs_parser_node_t *node)
         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_t *generator, njs_parser_node_t *node)
 }
 
 
-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_generator_t *generator,
 
     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_generator_t *generator,
     }
 
     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_generator_t *generator,
         }
     }
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -738,7 +936,6 @@ njs_generate_var_statement(njs_vm_t *vm, njs_generator_t *generator,
     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, njs_generator_t *generator,
 
         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, njs_generator_t *generator,
             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, njs_generator_t *generator,
     node->index = expr->index;
     node->temporary = expr->temporary;
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -826,17 +1041,23 @@ static njs_int_t
 njs_generate_if_statement(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_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_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;
+    njs_vmcode_cond_jump_t  *cond_jump;
 
     njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
                       NJS_VMCODE_IF_FALSE_JUMP, 2, node);
@@ -848,7 +1069,6 @@ njs_generate_if_statement(njs_vm_t *vm, njs_generator_t *generator,
     }
 
     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, njs_generator_t *generator,
 
         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);
+        njs_generator_next(generator, njs_generate, node->left);
 
-        jump_offset = njs_code_offset(generator, jump);
-        label_offset = jump_offset + offsetof(njs_vmcode_jump_t, offset);
+        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, njs_generator_t *generator,
      * 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);
+    njs_code_set_offset(generator, label_offset, *jump_offset);
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, generator->context);
 }
 
 
@@ -899,39 +1153,52 @@ 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_vmcode_cond_jump_t  *cond_jump;
+    njs_generator_next(generator, njs_generate, node->left);
 
-    /* The condition expression. */
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_cond_expression_handler, NULL, 0);
+}
 
-    ret = njs_generator(vm, generator, node->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+
+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;
 
     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;
     }
 
-    branch = node->right;
+    njs_generator_next(generator, njs_generate, node->right->left);
 
-    /* The "true" branch. */
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_cond_expression_true,
+                               &jump_offset, sizeof(njs_jump_off_t));
+}
 
-    ret = njs_generator(vm, generator, branch->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+
+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;
 
     /*
      * Branches usually uses node->index as destination, however,
@@ -953,28 +1220,41 @@ njs_generate_cond_expression(njs_vm_t *vm, njs_generator_t *generator,
     jump_offset = njs_code_offset(generator, jump);
 
     njs_code_set_jump_offset(generator, njs_vmcode_cond_jump_t,
-                             cond_jump_offset);
+                             *((njs_jump_off_t *) generator->context));
 
-    /* The "false" branch. */
+    njs_generator_next(generator, njs_generate, branch->right);
 
-    ret = njs_generator(vm, generator, branch->right);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    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. */
 
-    expr = swtch->left;
+    njs_generator_next(generator, njs_generate, swtch->left);
 
-    ret = njs_generator(vm, generator, expr);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    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;
 
-    index = expr->index;
+    ctx = generator->context;
+
+    expr = swtch->left;
+    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 *vm, njs_generator_t *generator,
         return ret;
     }
 
-    patches = NULL;
-    last = &patches;
+    ctx->patch = NULL;
+    ctx->last = &ctx->patch;
 
-    for (branch = swtch->right; branch != NULL; branch = branch->left) {
+    if (swtch->right != NULL) {
 
-        if (branch->token_type != NJS_TOKEN_DEFAULT) {
+        /* The "case" expression. */
 
-            /* The "case" expression. */
+        njs_generator_next(generator, njs_generate_switch_case, swtch->right);
 
-            node = branch->right;
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), swtch,
+                                   njs_generate_switch_case_end, ctx, 0);
+    }
 
-            ret = njs_generator(vm, generator, node->left);
-            if (njs_slow_path(ret != NJS_OK)) {
-                return ret;
-            }
+    return njs_generate_switch_case_end(vm, generator, swtch);
+}
 
-            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;
-            }
+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);
+        }
 
-            patch = njs_mp_alloc(vm->mem_pool, sizeof(njs_generator_patch_t));
-            if (njs_slow_path(patch == NULL)) {
-                return NJS_ERROR;
-            }
+        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;
+    }
+
+    patch->jump_offset = njs_code_offset(generator, equal)
+                         + offsetof(njs_vmcode_equal_jump_t, offset);
+    patch->label = no_label;
+
+    *ctx->last = patch;
+    ctx->last = &patch->next;
 
-            patch->jump_offset = njs_code_offset(generator, equal)
-                                 + offsetof(njs_vmcode_equal_jump_t, offset);
-            patch->label = no_label;
+    if (branch->left == NULL) {
+        return njs_generator_stack_pop(vm, generator, NULL);
+    }
+
+    branch = branch->left;
 
-            *last = patch;
-            last = &patch->next;
+    if (branch->token_type == NJS_TOKEN_DEFAULT) {
+        branch = branch->left;
+
+        if (branch == NULL) {
+            return njs_generator_stack_pop(vm, generator, NULL);
         }
     }
 
+    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, ctx, 0);
+}
+
+static njs_int_t
+njs_generate_switch_case_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *swtch)
+{
+    njs_int_t                   ret;
+    njs_parser_node_t           *branch;
+    njs_generator_switch_ctx_t  *ctx;
+
+    ctx = generator->context;
+
     /* Release either temporary index or temporary expr->index. */
-    ret = njs_generate_index_release(vm, generator, index);
+    ret = njs_generate_index_release(vm, generator, ctx->index);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
-    njs_generate_code_jump(generator, jump,
+    njs_generate_code_jump(generator, ctx->jump,
                            offsetof(njs_vmcode_jump_t, offset));
 
-    jump_offset = njs_code_offset(generator, jump);
+    ctx->jump_offset = njs_code_offset(generator, ctx->jump);
+
+    branch = swtch->right;
+
+    if (branch != NULL) {
+        njs_generator_next(generator, njs_generate_switch_default, branch);
 
-    patch = patches;
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), swtch,
+                                   njs_generate_switch_end, ctx, 0);
+    }
 
-    for (branch = swtch->right; branch != NULL; branch = branch->left) {
+    return njs_generate_switch_end(vm, generator, swtch);
+}
 
-        if (branch->token_type == NJS_TOKEN_DEFAULT) {
-            njs_code_set_jump_offset(generator, njs_vmcode_jump_t, jump_offset);
-            jump = NULL;
-            node = branch;
 
-        } else {
-            njs_code_update_offset(generator, patch);
+static njs_int_t
+njs_generate_switch_default(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *branch)
+{
+    njs_parser_node_t           *node;
+    njs_generator_patch_t       *next;
+    njs_generator_switch_ctx_t  *ctx;
 
-            next = patch->next;
+    ctx = generator->context;
 
-            njs_mp_free(vm->mem_pool, patch);
+    if (branch->token_type == NJS_TOKEN_DEFAULT) {
+        njs_code_set_jump_offset(generator, njs_vmcode_jump_t,
+                                 ctx->jump_offset);
+        ctx->jump = NULL;
+        node = branch;
 
-            patch = next;
-            node = branch->right;
-        }
+    } else {
+        njs_code_update_offset(generator, ctx->patch);
 
-        /* The "case/default" statements. */
+        next = ctx->patch->next;
 
-        ret = njs_generator(vm, generator, node->right);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
+        njs_mp_free(vm->mem_pool, ctx->patch);
+
+        ctx->patch = next;
+        node = branch->right;
+    }
+
+    njs_generator_next(generator, njs_generate, node->right);
+
+    branch = branch->left;
+
+    if (branch == NULL) {
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), branch,
+                                   njs_generator_pop, NULL, 0);
     }
 
-    if (jump != NULL) {
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), branch,
+                               njs_generate_switch_default, ctx, 0);
+}
+
+
+static njs_int_t
+njs_generate_switch_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *swtch)
+{
+    njs_generator_switch_ctx_t  *ctx;
+
+    ctx = generator->context;
+
+    if (ctx->jump != NULL) {
         /* A "switch" without default case. */
-        njs_code_set_jump_offset(generator, njs_vmcode_jump_t, jump_offset);
+        njs_code_set_jump_offset(generator, njs_vmcode_jump_t,
+                                 ctx->jump_offset);
     }
 
     /* Patch "break" statements offsets. */
     njs_generate_patch_block_exit(vm, generator);
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, ctx);
 }
 
 
@@ -1113,11 +1503,9 @@ static njs_int_t
 njs_generate_while_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t               ret;
-    njs_jump_off_t          jump_offset, loop_offset;
-    njs_parser_node_t       *condition;
-    njs_vmcode_jump_t       *jump;
-    njs_vmcode_cond_jump_t  *cond_jump;
+    njs_int_t                 ret;
+    njs_vmcode_jump_t         *jump;
+    njs_generator_loop_ctx_t  ctx;
 
     /*
      * Set a jump to the loop condition.  This jump is executed once just on
@@ -1126,9 +1514,7 @@ njs_generate_while_statement(njs_vm_t *vm, njs_generator_t *generator,
      */
 
     njs_generate_code_jump(generator, jump, 0);
-    jump_offset = njs_code_offset(generator, jump);
-
-    /* The loop body. */
+    ctx.jump_offset = njs_code_offset(generator, jump);
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_LOOP,
                                    &node->name);
@@ -1136,34 +1522,61 @@ njs_generate_while_statement(njs_vm_t *vm, njs_generator_t *generator,
         return ret;
     }
 
-    loop_offset = njs_code_offset(generator, generator->code_end);
+    ctx.loop_offset = njs_code_offset(generator, generator->code_end);
 
-    ret = njs_generator(vm, generator, node->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    njs_generator_next(generator, njs_generate, node->left);
 
-    /* The loop condition. */
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_while_condition,
+                               &ctx, sizeof(njs_generator_loop_ctx_t));
+}
+
+
+static njs_int_t
+njs_generate_while_condition(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_generator_loop_ctx_t  *ctx;
+
+    ctx = generator->context;
 
     njs_generate_patch_block(vm, generator, generator->block->continuation);
 
-    njs_code_set_jump_offset(generator, njs_vmcode_jump_t, jump_offset);
+    njs_code_set_jump_offset(generator, njs_vmcode_jump_t, ctx->jump_offset);
 
-    condition = node->right;
+    njs_generator_next(generator, njs_generate, node->right);
 
-    ret = njs_generator(vm, generator, condition);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_while_end, ctx, 0);
+}
+
+
+static njs_int_t
+njs_generate_while_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t                 ret;
+    njs_vmcode_cond_jump_t    *cond_jump;
+    njs_generator_loop_ctx_t  *ctx;
+
+    ctx = generator->context;
 
     njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
-                      NJS_VMCODE_IF_TRUE_JUMP, 2, condition);
-    cond_jump->offset = loop_offset - njs_code_offset(generator, cond_jump);
-    cond_jump->cond = condition->index;
+                      NJS_VMCODE_IF_TRUE_JUMP, 2, node->right);
+    cond_jump->offset = ctx->loop_offset - njs_code_offset(generator,
+                                                           cond_jump);
+    cond_jump->cond = node->right->index;
 
     njs_generate_patch_block_exit(vm, generator);
 
-    return njs_generate_node_index_release(vm, generator, condition);
+    ret = njs_generate_node_index_release(vm, generator, node->right);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    return njs_generator_stack_pop(vm, generator, ctx);
 }
 
 
@@ -1171,12 +1584,8 @@ static njs_int_t
 njs_generate_do_while_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t               ret;
-    njs_jump_off_t          loop_offset;
-    njs_parser_node_t       *condition;
-    njs_vmcode_cond_jump_t  *cond_jump;
-
-    /* The loop body. */
+    njs_int_t                 ret;
+    njs_generator_loop_ctx_t  ctx;
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_LOOP,
                                    &node->name);
@@ -1184,32 +1593,56 @@ njs_generate_do_while_statement(njs_vm_t *vm, njs_generator_t *generator,
         return ret;
     }
 
-    loop_offset = njs_code_offset(generator, generator->code_end);
+    ctx.loop_offset = njs_code_offset(generator, generator->code_end);
 
-    ret = njs_generator(vm, generator, node->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    njs_generator_next(generator, njs_generate, node->left);
 
-    /* The loop condition. */
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_do_while_condition,
+                               &ctx, sizeof(njs_generator_loop_ctx_t));
+}
 
+
+static njs_int_t
+njs_generate_do_while_condition(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
     njs_generate_patch_block(vm, generator, generator->block->continuation);
 
-    condition = node->right;
+    njs_generator_next(generator, njs_generate, node->right);
 
-    ret = njs_generator(vm, generator, condition);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_do_while_end,
+                               generator->context, 0);
+}
+
+
+static njs_int_t
+njs_generate_do_while_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t                 ret;
+    njs_vmcode_cond_jump_t    *cond_jump;
+    njs_generator_loop_ctx_t  *ctx;
+
+    ctx = generator->context;
 
     njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
-                      NJS_VMCODE_IF_TRUE_JUMP, 2, condition);
-    cond_jump->offset = loop_offset - njs_code_offset(generator, cond_jump);
-    cond_jump->cond = condition->index;
+                      NJS_VMCODE_IF_TRUE_JUMP, 2, node->right);
+    cond_jump->offset = ctx->loop_offset
+                        - njs_code_offset(generator, cond_jump);
+    cond_jump->cond = node->right->index;
 
     njs_generate_patch_block_exit(vm, generator);
 
-    return njs_generate_node_index_release(vm, generator, condition);
+    ret = njs_generate_node_index_release(vm, generator, node->right);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    return njs_generator_stack_pop(vm, generator, ctx);
 }
 
 
@@ -1217,11 +1650,8 @@ static njs_int_t
 njs_generate_for_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t               ret;
-    njs_jump_off_t          jump_offset, loop_offset;
-    njs_parser_node_t       *condition, *update, *init;
-    njs_vmcode_jump_t       *jump;
-    njs_vmcode_cond_jump_t  *cond_jump;
+    njs_int_t                 ret;
+    njs_generator_loop_ctx_t  ctx;
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_LOOP,
                                    &node->name);
@@ -1229,23 +1659,33 @@ njs_generate_for_statement(njs_vm_t *vm, njs_generator_t *generator,
         return ret;
     }
 
-    jump = NULL;
+    ctx.jump = NULL;
 
-    /* The loop initialization. */
+    njs_generator_next(generator, njs_generate, node->left);
 
-    ret = njs_generator(vm, generator, node->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_for_init,
+                               &ctx, sizeof(njs_generator_loop_ctx_t));
+}
+
+
+static njs_int_t
+njs_generate_for_init(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t                 ret;
+    njs_parser_node_t         *condition;
+    njs_generator_loop_ctx_t  *ctx;
+
+    ctx = generator->context;
 
     ret = njs_generate_node_index_release(vm, generator, node->left);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
-    init = node->left;
-    node = node->right;
-    condition = node->left;
+    condition = node->right->left;
 
     /*
      * Closures can occur in conditional and loop updates.  This must be
@@ -1257,8 +1697,7 @@ njs_generate_for_statement(njs_vm_t *vm, njs_generator_t *generator,
         return ret;
     }
 
-    /* GCC complains about uninitialized jump_offset. */
-    jump_offset = 0;
+    ctx->jump_offset = 0;
 
     if (condition != NULL) {
         /*
@@ -1266,24 +1705,36 @@ njs_generate_for_statement(njs_vm_t *vm, njs_generator_t *generator,
          * executed once just after the loop initialization and eliminates
          * execution of one additional jump inside the loop per each iteration.
          */
-        njs_generate_code_jump(generator, jump, 0);
-        jump_offset = njs_code_offset(generator, jump);
+        njs_generate_code_jump(generator, ctx->jump, 0);
+        ctx->jump_offset = njs_code_offset(generator, ctx->jump);
     }
 
     /* The loop body. */
 
-    loop_offset = njs_code_offset(generator, generator->code_end);
+    ctx->loop_offset = njs_code_offset(generator, generator->code_end);
 
-    node = node->right;
+    njs_generator_next(generator, njs_generate, node->right->right->left);
 
-    ret = njs_generator(vm, generator, node->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_for_body, ctx, 0);
+}
+
+
+static njs_int_t
+njs_generate_for_body(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t                 ret;
+    njs_parser_node_t         *update, *init;
+    njs_generator_loop_ctx_t  *ctx;
+
+    ctx = generator->context;
 
     /* The loop update. */
 
-    update = node->right;
+    init = node->left;
+    update = node->right->right->right;
 
     ret = njs_generate_for_resolve_closure(vm, update, generator->count);
     if (njs_slow_path(ret != NJS_OK)) {
@@ -1297,10 +1748,26 @@ njs_generate_for_statement(njs_vm_t *vm, njs_generator_t *generator,
 
     njs_generate_patch_block(vm, generator, generator->block->continuation);
 
-    ret = njs_generator(vm, generator, update);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    njs_generator_next(generator, njs_generate, update);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_for_update, ctx, 0);
+}
+
+
+static njs_int_t
+njs_generate_for_update(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t                 ret;
+    njs_parser_node_t         *condition, *update;
+    njs_generator_loop_ctx_t  *ctx;
+
+    ctx = generator->context;
+
+    update = node->right->right->right;
+    condition = node->right->left;
 
     ret = njs_generate_node_index_release(vm, generator, update);
     if (njs_slow_path(ret != NJS_OK)) {
@@ -1310,29 +1777,57 @@ njs_generate_for_statement(njs_vm_t *vm, njs_generator_t *generator,
     /* The loop condition. */
 
     if (condition != NULL) {
-        njs_code_set_jump_offset(generator, njs_vmcode_jump_t, jump_offset);
+        njs_code_set_jump_offset(generator, njs_vmcode_jump_t,
+                                 ctx->jump_offset);
+
+        njs_generator_next(generator, njs_generate, condition);
+
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), node,
+                                   njs_generate_for_end, ctx, 0);
+    }
+
+    return njs_generate_for_end(vm, generator, node);
+}
 
-        ret = njs_generator(vm, generator, condition);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
 
+static njs_int_t
+njs_generate_for_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t                 ret;
+    njs_parser_node_t         *condition;
+    njs_vmcode_cond_jump_t    *cond_jump;
+    njs_generator_loop_ctx_t  *ctx;
+
+    ctx = generator->context;
+
+    condition = node->right->left;
+
+    if (condition != NULL) {
         njs_generate_code(generator, njs_vmcode_cond_jump_t, cond_jump,
                           NJS_VMCODE_IF_TRUE_JUMP, 2, condition);
-        cond_jump->offset = loop_offset - njs_code_offset(generator, cond_jump);
+        cond_jump->offset = ctx->loop_offset
+                            - njs_code_offset(generator, cond_jump);
         cond_jump->cond = condition->index;
 
         njs_generate_patch_block_exit(vm, generator);
 
-        return njs_generate_node_index_release(vm, generator, condition);
+        ret = njs_generate_node_index_release(vm, generator, condition);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return ret;
+        }
+
+        return njs_generator_stack_pop(vm, generator, ctx);
     }
 
-    njs_generate_code_jump(generator, jump,
-                           loop_offset - njs_code_offset(generator, jump));
+    njs_generate_code_jump(generator, ctx->jump,
+                           ctx->loop_offset - njs_code_offset(generator,
+                                                              ctx->jump));
 
     njs_generate_patch_block_exit(vm, generator);
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, ctx);
 }
 
 
@@ -1423,13 +1918,9 @@ static njs_int_t
 njs_generate_for_in_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t                  ret;
-    njs_index_t                index;
-    njs_variable_t             *var;
-    njs_jump_off_t             loop_offset, prop_offset;
-    njs_parser_node_t          *foreach, *name;
-    njs_vmcode_prop_next_t     *prop_next;
-    njs_vmcode_prop_foreach_t  *prop_foreach;
+    njs_int_t                 ret;
+    njs_parser_node_t         *foreach, *name;
+    njs_generator_loop_ctx_t  ctx;
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_LOOP,
                                    &node->name);
@@ -1446,52 +1937,92 @@ njs_generate_for_in_statement(njs_vm_t *vm, njs_generator_t *generator,
         name = name->left;
 
         ret = njs_generate_variable_wo_dest(vm, generator, name,
-                                            NJS_DECLARATION, &var);
+                                            NJS_DECLARATION, &ctx.var);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
 
         foreach->left->index = name->index;
 
-        ret = njs_generator(vm, generator, foreach->right);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
+        njs_generator_next(generator, njs_generate, foreach->right);
 
-        var->init = 1;
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), node,
+                                   njs_generate_for_in_object,
+                                   &ctx, sizeof(njs_generator_loop_ctx_t));
+    }
 
-    } else {
-        ret = njs_generator(vm, generator, foreach->left);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
+    njs_generator_next(generator, njs_generate, foreach->left);
 
-        ret = njs_generator(vm, generator, foreach->right);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
+    ret = njs_generator_after(vm, generator,
+                              njs_queue_first(&generator->stack), node,
+                              njs_generate_for_in_object,
+                              &ctx, sizeof(njs_generator_loop_ctx_t));
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack),
+                               foreach->right, njs_generate, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_for_in_object(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_parser_node_t          *foreach, *name;
+    njs_generator_loop_ctx_t   *ctx;
+    njs_vmcode_prop_foreach_t  *prop_foreach;
+
+    ctx = generator->context;
+
+    foreach = node->left;
+    name = foreach->left->right;
+
+    if (name != NULL) {
+        ctx->var->init = 1;
     }
 
     njs_generate_code(generator, njs_vmcode_prop_foreach_t, prop_foreach,
                       NJS_VMCODE_PROPERTY_FOREACH, 2, foreach);
-    prop_offset = njs_code_offset(generator, prop_foreach);
+    ctx->jump_offset = njs_code_offset(generator, prop_foreach);
     prop_foreach->object = foreach->right->index;
 
-    index = njs_generate_temp_index_get(vm, generator, foreach->right);
-    if (njs_slow_path(index == NJS_INDEX_ERROR)) {
+    ctx->index = njs_generate_temp_index_get(vm, generator, foreach->right);
+    if (njs_slow_path(ctx->index == NJS_INDEX_ERROR)) {
         return NJS_ERROR;
     }
 
-    prop_foreach->next = index;
+    prop_foreach->next = ctx->index;
 
     /* The loop body. */
 
-    loop_offset = njs_code_offset(generator, generator->code_end);
+    ctx->loop_offset = njs_code_offset(generator, generator->code_end);
 
-    ret = njs_generator(vm, generator, node->right);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    njs_generator_next(generator, njs_generate, node->right);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_for_in_body, ctx, 0);
+}
+
+
+static njs_int_t
+njs_generate_for_in_body(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t                 ret;
+    njs_jump_off_t            prop_offset;
+    njs_parser_node_t         *foreach, *name;
+    njs_vmcode_prop_next_t    *prop_next;
+    njs_generator_loop_ctx_t  *ctx;
+
+    ctx = generator->context;
+
+    foreach = node->left;
+    name = foreach->left->right;
 
     /* The loop iterator. */
 
@@ -1505,15 +2036,16 @@ njs_generate_for_in_statement(njs_vm_t *vm, njs_generator_t *generator,
 
     njs_generate_patch_block(vm, generator, generator->block->continuation);
 
-    njs_code_set_jump_offset(generator, njs_vmcode_prop_foreach_t, prop_offset);
+    njs_code_set_jump_offset(generator, njs_vmcode_prop_foreach_t,
+                             ctx->jump_offset);
 
     njs_generate_code(generator, njs_vmcode_prop_next_t, prop_next,
                       NJS_VMCODE_PROPERTY_NEXT, 3, node->left->left);
     prop_offset = njs_code_offset(generator, prop_next);
     prop_next->retval = foreach->left->index;
     prop_next->object = foreach->right->index;
-    prop_next->next = index;
-    prop_next->offset = loop_offset - prop_offset;
+    prop_next->next = ctx->index;
+    prop_next->offset = ctx->loop_offset - prop_offset;
 
     njs_generate_patch_block_exit(vm, generator);
 
@@ -1526,7 +2058,12 @@ njs_generate_for_in_statement(njs_vm_t *vm, njs_generator_t *generator,
         return ret;
     }
 
-    return njs_generate_index_release(vm, generator, index);
+    ret = njs_generate_index_release(vm, generator, ctx->index);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    return njs_generator_stack_pop(vm, generator, ctx);
 }
 
 
@@ -1769,7 +2306,7 @@ njs_generate_continue_statement(njs_vm_t *vm, njs_generator_t *generator,
         return NJS_ERROR;
     }
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 
 syntax_error:
 
@@ -1814,7 +2351,7 @@ njs_generate_break_statement(njs_vm_t *vm, njs_generator_t *generator,
         return NJS_ERROR;
     }
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 
 syntax_error:
 
@@ -1838,7 +2375,7 @@ njs_generate_debugger_statement(njs_vm_t *vm, njs_generator_t *generator,
         return debugger->retval;
     }
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -1848,6 +2385,7 @@ njs_generate_statement(njs_vm_t *vm, njs_generator_t *generator,
 {
     njs_int_t              ret;
     njs_variable_t         *var;
+    njs_queue_link_t       *link;
     njs_parser_node_t      *right;
     njs_vmcode_variable_t  *code;
 
@@ -1868,7 +2406,7 @@ njs_generate_statement(njs_vm_t *vm, njs_generator_t *generator,
         }
 
         if (node->left == NULL) {
-            return NJS_OK;
+            return njs_generator_stack_pop(vm, generator, NULL);
         }
 
         node = node->left;
@@ -1876,21 +2414,23 @@ njs_generate_statement(njs_vm_t *vm, njs_generator_t *generator,
 
 statement:
 
-    ret = njs_generate_children(vm, generator, node);
+    link = njs_queue_first(&generator->stack);
 
-    if (njs_fast_path(ret == NJS_OK)) {
-        return njs_generate_node_index_release(vm, generator, right);
+    ret = njs_generate_children(vm, generator, node);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
     }
 
-    return ret;
+    return njs_generator_after(vm, generator, link, right,
+                               njs_generate_node_index_release_pop, NULL, 0);
 }
 
-
 static njs_int_t
 njs_generate_block_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t  ret;
+    njs_int_t         ret;
+    njs_queue_link_t  *link;
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_BLOCK,
                                    &node->name);
@@ -1898,14 +2438,25 @@ njs_generate_block_statement(njs_vm_t *vm, njs_generator_t *generator,
         return ret;
     }
 
+    link = njs_queue_first(&generator->stack);
+
     ret = njs_generate_statement(vm, generator, node);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
+    return njs_generator_after(vm, generator, link, node,
+                               njs_generate_block_statement_end, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_block_statement_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
     njs_generate_patch_block_exit(vm, generator);
 
-    return ret;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -1915,17 +2466,18 @@ njs_generate_children(njs_vm_t *vm, njs_generator_t *generator,
 {
     njs_int_t  ret;
 
-    ret = njs_generator(vm, generator, node->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    njs_generator_next(generator, njs_generate, node->left);
 
-    ret = njs_generate_node_index_release(vm, generator, node->left);
+    ret = njs_generator_after(vm, generator,
+                              njs_queue_first(&generator->stack), node->right,
+                              njs_generate, NULL, 0);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
-    return njs_generator(vm, generator, node->right);
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node->left,
+                               njs_generate_node_index_release_pop, NULL, 0);
 }
 
 
@@ -1934,31 +2486,45 @@ njs_generate_stop_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
     njs_int_t          ret;
-    njs_index_t        index;
-    njs_vmcode_stop_t  *stop;
+    njs_queue_link_t   *link;
+
+    link = njs_queue_first(&generator->stack);
 
     ret = njs_generate_children(vm, generator, node);
+    if (njs_fast_path(ret != NJS_OK)) {
+        return ret;
+    }
 
-    if (njs_fast_path(ret == NJS_OK)) {
-        njs_generate_code(generator, njs_vmcode_stop_t, stop,
-                          NJS_VMCODE_STOP, 1, node);
+    return njs_generator_after(vm, generator, link, node,
+                               njs_generate_stop_statement_end, NULL, 0);
+}
 
-        index = njs_scope_undefined_index(vm, 0);
-        node = node->right;
 
-        if (node != NULL) {
-            if ((node->index != NJS_INDEX_NONE
-                 && node->token_type != NJS_TOKEN_FUNCTION_DECLARATION)
-                || node->token_type == NJS_TOKEN_THIS)
-            {
-                index = node->index;
-            }
-        }
+static njs_int_t
+njs_generate_stop_statement_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_index_t        index;
+    njs_vmcode_stop_t  *stop;
+
+    njs_generate_code(generator, njs_vmcode_stop_t, stop,
+                      NJS_VMCODE_STOP, 1, node);
 
-        stop->retval = index;
+    index = njs_scope_undefined_index(vm, 0);
+    node = node->right;
+
+    if (node != NULL) {
+        if ((node->index != NJS_INDEX_NONE
+             && node->token_type != NJS_TOKEN_FUNCTION_DECLARATION)
+            || node->token_type == NJS_TOKEN_THIS)
+        {
+            index = node->index;
+        }
     }
 
-    return ret;
+    stop->retval = index;
+
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -1966,15 +2532,28 @@ static njs_int_t
 njs_generate_comma_expression(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t  ret;
+    njs_int_t         ret;
+    njs_queue_link_t  *link;
 
-    ret = njs_generate_children(vm, generator, node);
+    link = njs_queue_first(&generator->stack);
 
-    if (njs_fast_path(ret == NJS_OK)) {
-        node->index = node->right->index;
+    ret = njs_generate_children(vm, generator, node);
+    if (njs_fast_path(ret != NJS_OK)) {
+        return ret;
     }
 
-    return ret;
+    return njs_generator_after(vm, generator, link, node,
+                               njs_generate_comma_expression_end, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_comma_expression_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    node->index = node->right->index;
+
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -1983,12 +2562,9 @@ njs_generate_assignment(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
     njs_int_t              ret;
-    njs_index_t            index, src;
     njs_variable_t         *var;
-    njs_parser_node_t      *lvalue, *expr, *object, *property;
-    njs_vmcode_move_t      *move;
+    njs_parser_node_t      *lvalue, *expr;
     njs_vmcode_variable_t  *var_code;
-    njs_vmcode_prop_set_t  *prop_set;
 
     lvalue = node->left;
     expr = node->right;
@@ -2007,51 +2583,79 @@ njs_generate_assignment(njs_vm_t *vm, njs_generator_t *generator,
                               NJS_VMCODE_ASSIGNMENT_ERROR, 0, node);
             var_code->dst = var->index;
 
-            return NJS_OK;
+            return njs_generator_stack_pop(vm, generator, NULL);
         }
 
         expr->dest = lvalue;
 
-        ret = njs_generator(vm, generator, expr);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
-
-        /*
-         * lvalue and expression indexes are equal if the expression is an
-         * empty object or expression result is stored directly in variable.
-         */
-        if (lvalue->index != expr->index) {
-            njs_generate_code_move(generator, move, lvalue->index, expr->index,
-                                   expr);
-        }
-
-        node->index = expr->index;
-        node->temporary = expr->temporary;
+        njs_generator_next(generator, njs_generate, expr);
 
-        return NJS_OK;
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), node,
+                                   njs_generate_assignment_name, NULL, 0);
     }
 
     /* lvalue->token == NJS_TOKEN_PROPERTY(_INIT) */
 
     /* Object. */
 
-    object = lvalue->left;
+    njs_generator_next(generator, njs_generate, lvalue->left);
 
-    ret = njs_generator(vm, generator, object);
+    ret = njs_generator_after(vm, generator,
+                              njs_queue_first(&generator->stack), node,
+                              njs_generate_assignment_prop, NULL, 0);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
     /* Property. */
 
-    property = lvalue->right;
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack),
+                               lvalue->right, njs_generate, NULL, 0);
+}
 
-    ret = njs_generator(vm, generator, property);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
+
+static njs_int_t
+njs_generate_assignment_name(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_parser_node_t  *lvalue, *expr;
+    njs_vmcode_move_t  *move;
+
+    lvalue = node->left;
+    expr = node->right;
+
+    /*
+     * lvalue and expression indexes are equal if the expression is an
+     * empty object or expression result is stored directly in variable.
+     */
+    if (lvalue->index != expr->index) {
+        njs_generate_code_move(generator, move, lvalue->index, expr->index,
+                               expr);
     }
 
+    node->index = expr->index;
+    node->temporary = expr->temporary;
+
+    return njs_generator_stack_pop(vm, generator, NULL);
+}
+
+
+static njs_int_t
+njs_generate_assignment_prop(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_index_t        index, src;
+    njs_parser_node_t  *lvalue, *expr, *object, *property;
+    njs_vmcode_move_t  *move;
+
+    lvalue = node->left;
+    expr = node->right;
+
+    object = lvalue->left;
+    property = lvalue->right;
+
     if (njs_slow_path(njs_parser_has_side_effect(expr))) {
         /*
          * Preserve object and property values stored in variables in a case
@@ -2080,10 +2684,26 @@ njs_generate_assignment(njs_vm_t *vm, njs_generator_t *generator,
         }
     }
 
-    ret = njs_generator(vm, generator, expr);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    njs_generator_next(generator, njs_generate, expr);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_assignment_end, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_assignment_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_parser_node_t      *lvalue, *expr, *object, *property;
+    njs_vmcode_prop_set_t  *prop_set;
+
+    lvalue = node->left;
+    expr = node->right;
+
+    object = lvalue->left;
+    property = lvalue->right;
 
     switch (lvalue->token_type) {
     case NJS_TOKEN_PROPERTY_INIT:
@@ -2109,7 +2729,7 @@ njs_generate_assignment(njs_vm_t *vm, njs_generator_t *generator,
     node->index = expr->index;
     node->temporary = expr->temporary;
 
-    return njs_generate_children_indexes_release(vm, generator, lvalue);
+    return njs_generate_children_indexes_release_pop(vm, generator, lvalue);
 }
 
 
@@ -2118,14 +2738,11 @@ njs_generate_operation_assignment(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
     njs_int_t              ret;
-    njs_index_t            index, src;
+    njs_index_t            index;
     njs_variable_t         *var;
-    njs_parser_node_t      *lvalue, *expr, *object, *property;
+    njs_parser_node_t      *lvalue, *expr;
     njs_vmcode_move_t      *move;
-    njs_vmcode_3addr_t     *code;
     njs_vmcode_variable_t  *var_code;
-    njs_vmcode_prop_get_t  *prop_get;
-    njs_vmcode_prop_set_t  *prop_set;
 
     lvalue = node->left;
 
@@ -2142,7 +2759,7 @@ njs_generate_operation_assignment(njs_vm_t *vm, njs_generator_t *generator,
                               NJS_VMCODE_ASSIGNMENT_ERROR, 0, node);
             var_code->dst = var->index;
 
-            return NJS_OK;
+            return njs_generator_stack_pop(vm, generator, NULL);
         }
 
         index = lvalue->index;
@@ -2163,49 +2780,83 @@ njs_generate_operation_assignment(njs_vm_t *vm, njs_generator_t *generator,
             move->dst = index;
         }
 
-        ret = njs_generator(vm, generator, expr);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
-
-        njs_generate_code(generator, njs_vmcode_3addr_t, code,
-                          node->u.operation, 3, expr);
-        code->dst = lvalue->index;
-        code->src1 = index;
-        code->src2 = expr->index;
-
-        node->index = lvalue->index;
+        njs_generator_next(generator, njs_generate, expr);
 
-        if (lvalue->index != index) {
-            ret = njs_generate_index_release(vm, generator, index);
-            if (njs_slow_path(ret != NJS_OK)) {
-                return ret;
-            }
-        }
-
-        return njs_generate_node_index_release(vm, generator, expr);
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), node,
+                                   njs_generate_operation_assignment_name,
+                                   &index, sizeof(njs_index_t));
     }
 
     /* lvalue->token == NJS_TOKEN_PROPERTY */
 
     /* Object. */
 
-    object = lvalue->left;
+    njs_generator_next(generator, njs_generate, lvalue->left);
 
-    ret = njs_generator(vm, generator, object);
+    ret = njs_generator_after(vm, generator,
+                              njs_queue_first(&generator->stack), node,
+                              njs_generate_operation_assignment_prop, NULL, 0);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
     /* Property. */
 
-    property = lvalue->right;
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack),
+                               lvalue->right, njs_generate, NULL, 0);
+}
 
-    ret = njs_generator(vm, generator, property);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
+
+static njs_int_t
+njs_generate_operation_assignment_name(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t           ret;
+    njs_index_t         index;
+    njs_parser_node_t   *lvalue, *expr;
+    njs_vmcode_3addr_t  *code;
+
+    lvalue = node->left;
+    expr = node->right;
+
+    index = *((njs_index_t *) generator->context);
+
+    njs_generate_code(generator, njs_vmcode_3addr_t, code,
+                      node->u.operation, 3, expr);
+    code->dst = lvalue->index;
+    code->src1 = index;
+    code->src2 = expr->index;
+
+    node->index = lvalue->index;
+
+    if (lvalue->index != index) {
+        ret = njs_generate_index_release(vm, generator, index);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return ret;
+        }
     }
 
+    njs_mp_free(vm->mem_pool, generator->context);
+
+    return njs_generate_node_index_release_pop(vm, generator, expr);
+}
+
+
+static njs_int_t
+njs_generate_operation_assignment_prop(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_index_t            index, src;
+    njs_parser_node_t      *lvalue, *object, *property;
+    njs_vmcode_move_t      *move;
+    njs_vmcode_prop_get_t  *prop_get;
+
+    lvalue = node->left;
+    object = lvalue->left;
+    property = lvalue->right;
+
     if (njs_slow_path(njs_parser_has_side_effect(node->right))) {
         /*
          * Preserve object and property values stored in variables in a case
@@ -2245,12 +2896,25 @@ njs_generate_operation_assignment(njs_vm_t *vm, njs_generator_t *generator,
     prop_get->object = object->index;
     prop_get->property = property->index;
 
-    expr = node->right;
+    njs_generator_next(generator, njs_generate, node->right);
 
-    ret = njs_generator(vm, generator, expr);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_operation_assignment_end, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_operation_assignment_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t              ret;
+    njs_parser_node_t      *lvalue, *expr;
+    njs_vmcode_3addr_t     *code;
+    njs_vmcode_prop_set_t  *prop_set;
+
+    lvalue = node->left;
+    expr = node->right;
 
     njs_generate_code(generator, njs_vmcode_3addr_t, code,
                       node->u.operation, 3, expr);
@@ -2261,15 +2925,15 @@ njs_generate_operation_assignment(njs_vm_t *vm, njs_generator_t *generator,
     njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
                       NJS_VMCODE_PROPERTY_SET, 3, expr);
     prop_set->value = node->index;
-    prop_set->object = object->index;
-    prop_set->property = property->index;
+    prop_set->object = lvalue->left->index;
+    prop_set->property = lvalue->right->index;
 
     ret = njs_generate_children_indexes_release(vm, generator, lvalue);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
-    return njs_generate_node_index_release(vm, generator, expr);
+    return njs_generate_node_index_release_pop(vm, generator, expr);
 }
 
 
@@ -2289,7 +2953,12 @@ njs_generate_object(njs_vm_t *vm, njs_generator_t *generator,
     object->retval = node->index;
 
     /* Initialize object. */
-    return njs_generator(vm, generator, node->left);
+
+    njs_generator_next(generator, njs_generate, node->left);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack),
+                               NULL, njs_generator_pop, NULL, 0);
 }
 
 
@@ -2297,42 +2966,50 @@ static njs_int_t
 njs_generate_property_accessor(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t                   ret;
-    njs_parser_node_t           *lvalue, *function, *object, *property;
-    njs_vmcode_prop_accessor_t  *accessor;
+    njs_int_t  ret;
 
-    lvalue = node->left;
-    function = node->right;
-
-    object = lvalue->left;
+    njs_generator_next(generator, njs_generate, node->left->left);
 
-    ret = njs_generator(vm, generator, object);
+    ret = njs_generator_after(vm, generator,
+                              njs_queue_first(&generator->stack), node,
+                              njs_generate_property_accessor_end, NULL, 0);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
-    property = lvalue->right;
-
-    ret = njs_generator(vm, generator, property);
+    ret = njs_generator_after(vm, generator,
+                              njs_queue_first(&generator->stack),
+                              node->right, njs_generate, NULL, 0);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
-    ret = njs_generator(vm, generator, function);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack),
+                               node->left->right, njs_generate, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_property_accessor_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_parser_node_t           *lvalue, *function;
+    njs_vmcode_prop_accessor_t  *accessor;
+
+    lvalue = node->left;
+    function = node->right;
 
     njs_generate_code(generator, njs_vmcode_prop_accessor_t, accessor,
                       NJS_VMCODE_PROPERTY_ACCESSOR, 3, function);
 
     accessor->value = function->index;
-    accessor->object = object->index;
-    accessor->property = property->index;
+    accessor->object = lvalue->left->index;
+    accessor->property = lvalue->right->index;
     accessor->type = (node->token_type == NJS_TOKEN_PROPERTY_GETTER)
                      ? NJS_OBJECT_PROP_GETTER : NJS_OBJECT_PROP_SETTER;
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -2354,7 +3031,12 @@ njs_generate_array(njs_vm_t *vm, njs_generator_t *generator,
     array->length = node->u.length;
 
     /* Initialize array. */
-    return njs_generator(vm, generator, node->left);
+
+    njs_generator_next(generator, njs_generate, node->left);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack),
+                               NULL, njs_generator_pop, NULL, 0);
 }
 
 
@@ -2370,7 +3052,12 @@ njs_generate_function_expression(njs_vm_t *vm, njs_generator_t *generator,
 
     var = njs_variable_reference(vm, node->left);
     if (njs_slow_path(var == NULL)) {
-        return njs_generate_reference_error(vm, generator, node->left);
+        ret = njs_generate_reference_error(vm, generator, node->left);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return ret;
+        }
+
+        return njs_generator_stack_pop(vm, generator, NULL);
     }
 
     lambda = node->u.value.data.u.lambda;
@@ -2396,7 +3083,7 @@ njs_generate_function_expression(njs_vm_t *vm, njs_generator_t *generator,
 
     function->retval = node->index;
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -2431,7 +3118,7 @@ njs_generate_function(njs_vm_t *vm, njs_generator_t *generator,
 
     function->retval = node->index;
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -2451,7 +3138,7 @@ njs_generate_regexp(njs_vm_t *vm, njs_generator_t *generator,
     regexp->retval = node->index;
     regexp->pattern = node->u.value.data.u.data;
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -2459,13 +3146,19 @@ static njs_int_t
 njs_generate_template_literal(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t                      ret;
-    njs_vmcode_template_literal_t  *code;
+    njs_generator_next(generator, njs_generate, node->left);
 
-    ret = njs_generator(vm, generator, node->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_template_literal_end, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_template_literal_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_vmcode_template_literal_t  *code;
 
     njs_generate_code(generator, njs_vmcode_template_literal_t, code,
                       NJS_VMCODE_TEMPLATE_LITERAL, 1, node);
@@ -2473,7 +3166,7 @@ njs_generate_template_literal(njs_vm_t *vm, njs_generator_t *generator,
 
     node->index = node->left->index;
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -2481,16 +3174,22 @@ static njs_int_t
 njs_generate_test_jump_expression(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t               ret;
+    njs_generator_next(generator, njs_generate, node->left);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_test_jump_expression_after,
+                               NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_test_jump_expression_after(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node)
+{
     njs_jump_off_t          jump_offset;
-    njs_vmcode_move_t       *move;
     njs_vmcode_test_jump_t  *test_jump;
 
-    ret = njs_generator(vm, generator, node->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
-
     njs_generate_code(generator, njs_vmcode_test_jump_t, test_jump,
                       node->u.operation, 2, node);
     jump_offset = njs_code_offset(generator, test_jump);
@@ -2503,10 +3202,21 @@ njs_generate_test_jump_expression(njs_vm_t *vm, njs_generator_t *generator,
 
     test_jump->retval = node->index;
 
-    ret = njs_generator(vm, generator, node->right);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    njs_generator_next(generator, njs_generate, node->right);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_test_jump_expression_end,
+                               &jump_offset, sizeof(njs_jump_off_t));
+}
+
+
+static njs_int_t
+njs_generate_test_jump_expression_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t          ret;
+    njs_vmcode_move_t  *move;
 
     /*
      * The right expression usually uses node->index as destination,
@@ -2519,9 +3229,15 @@ njs_generate_test_jump_expression(njs_vm_t *vm, njs_generator_t *generator,
                                node->right->index, node);
     }
 
-    njs_code_set_jump_offset(generator, njs_vmcode_test_jump_t, jump_offset);
+    njs_code_set_jump_offset(generator, njs_vmcode_test_jump_t,
+                             *((njs_jump_off_t *) generator->context));
 
-    return njs_generate_children_indexes_release(vm, generator, node);
+    ret = njs_generate_children_indexes_release(vm, generator, node);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    return njs_generator_stack_pop(vm, generator, generator->context);
 }
 
 
@@ -2529,45 +3245,83 @@ 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)
 {
-    njs_int_t           ret;
-    njs_index_t         index;
-    njs_parser_node_t   *left, *right;
-    njs_vmcode_move_t   *move;
-    njs_vmcode_3addr_t  *code;
+    njs_int_t          ret;
+    njs_parser_node_t  *left, *right;
 
     left = node->left;
+    right = node->right;
+
+    njs_generator_next(generator, njs_generate, left);
 
-    ret = njs_generator(vm, generator, left);
+    if (left->token_type == NJS_TOKEN_NAME) {
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), node,
+                                   njs_generate_3addr_operation_name,
+                                   &swap, sizeof(njs_bool_t));
+    }
+
+    ret = njs_generator_after(vm, generator,
+                              njs_queue_first(&generator->stack), node,
+                              njs_generate_3addr_operation_end, &swap,
+                              sizeof(njs_bool_t));
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
-    right = node->right;
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), right,
+                               njs_generate, NULL, 0);
+}
 
-    if (left->token_type == NJS_TOKEN_NAME) {
 
-        if (njs_slow_path(njs_parser_has_side_effect(right))) {
-            njs_generate_code(generator, njs_vmcode_move_t, move,
-                              NJS_VMCODE_MOVE, 2, node);
-            move->src = left->index;
+static njs_int_t
+njs_generate_3addr_operation_name(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_index_t        index;
+    njs_parser_node_t  *left;
+    njs_vmcode_move_t  *move;
 
-            index = njs_generate_node_temp_index_get(vm, generator, left);
-            if (njs_slow_path(index == NJS_INDEX_ERROR)) {
-                return NJS_ERROR;
-            }
+    left = node->left;
 
-            move->dst = index;
+    if (njs_slow_path(njs_parser_has_side_effect(node->right))) {
+        njs_generate_code(generator, njs_vmcode_move_t, move,
+                          NJS_VMCODE_MOVE, 2, node);
+        move->src = left->index;
+
+        index = njs_generate_node_temp_index_get(vm, generator, left);
+        if (njs_slow_path(index == NJS_INDEX_ERROR)) {
+            return NJS_ERROR;
         }
-    }
 
-    ret = njs_generator(vm, generator, right);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
+        move->dst = index;
     }
 
+    njs_generator_next(generator, njs_generate, node->right);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_3addr_operation_end,
+                               generator->context, 0);
+}
+
+
+static njs_int_t
+njs_generate_3addr_operation_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_bool_t          swap;
+    njs_parser_node_t   *left, *right;
+    njs_vmcode_3addr_t  *code;
+
+    left = node->left;
+    right = node->right;
+
     njs_generate_code(generator, njs_vmcode_3addr_t, code,
                       node->u.operation, 3, node);
 
+    swap = *((njs_bool_t *) generator->context);
+
     if (!swap) {
         code->src1 = left->index;
         code->src2 = right->index;
@@ -2591,7 +3345,7 @@ njs_generate_3addr_operation(njs_vm_t *vm, njs_generator_t *generator,
     njs_thread_log_debug("CODE3  %p, %p, %p",
                          code->dst, code->src1, code->src2);
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, generator->context);
 }
 
 
@@ -2599,13 +3353,19 @@ static njs_int_t
 njs_generate_2addr_operation(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t           ret;
-    njs_vmcode_2addr_t  *code;
+    njs_generator_next(generator, njs_generate, node->left);
 
-    ret = njs_generator(vm, generator, node->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_2addr_operation_end, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_2addr_operation_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_vmcode_2addr_t  *code;
 
     njs_generate_code(generator, njs_vmcode_2addr_t, code,
                       node->u.operation, 2, node);
@@ -2620,7 +3380,7 @@ njs_generate_2addr_operation(njs_vm_t *vm, njs_generator_t *generator,
 
     njs_thread_log_debug("CODE2  %p, %p", code->dst, code->src);
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -2628,27 +3388,36 @@ static njs_int_t
 njs_generate_typeof_operation(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t           ret;
-    njs_parser_node_t   *expr;
-    njs_vmcode_2addr_t  *code;
+    njs_int_t          ret;
+    njs_parser_node_t  *expr;
 
     expr = node->left;
 
-    if (expr->token_type == NJS_TOKEN_NAME) {
-        ret = njs_generate_variable(vm, generator, expr, NJS_TYPEOF, NULL);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return NJS_ERROR;
-        }
+    if (expr->token_type != NJS_TOKEN_NAME) {
+        njs_generator_next(generator, njs_generate, node->left);
 
-    } else {
-        ret = njs_generator(vm, generator, node->left);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), node,
+                                   njs_generate_typeof_operation_end, NULL, 0);
+    }
+
+    ret = njs_generate_variable(vm, generator, expr, NJS_TYPEOF, NULL);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
     }
 
+    return njs_generate_typeof_operation_end(vm, generator, node);
+}
+
+
+static njs_int_t
+njs_generate_typeof_operation_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_vmcode_2addr_t  *code;
+
     njs_generate_code(generator, njs_vmcode_2addr_t, code,
-                      node->u.operation, 2, expr);
+                      node->u.operation, 2, node->left);
     code->src = node->left->index;
 
     node->index = njs_generate_dest_index(vm, generator, node);
@@ -2660,7 +3429,7 @@ njs_generate_typeof_operation(njs_vm_t *vm, njs_generator_t *generator,
 
     njs_thread_log_debug("CODE2  %p, %p", code->dst, code->src);
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -2669,13 +3438,11 @@ njs_generate_inc_dec_operation(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node, njs_bool_t post)
 {
     njs_int_t              ret;
-    njs_index_t            index, dest_index;
+    njs_index_t            index;
     njs_variable_t         *var;
     njs_parser_node_t      *lvalue;
     njs_vmcode_3addr_t     *code;
     njs_vmcode_variable_t  *var_code;
-    njs_vmcode_prop_get_t  *prop_get;
-    njs_vmcode_prop_set_t  *prop_set;
 
     lvalue = node->left;
 
@@ -2692,7 +3459,7 @@ njs_generate_inc_dec_operation(njs_vm_t *vm, njs_generator_t *generator,
                               NJS_VMCODE_ASSIGNMENT_ERROR, 0, node);
             var_code->dst = var->index;
 
-            return NJS_OK;
+            return njs_generator_stack_pop(vm, generator, NULL);
         }
 
         index = njs_generate_dest_index(vm, generator, node);
@@ -2708,24 +3475,44 @@ njs_generate_inc_dec_operation(njs_vm_t *vm, njs_generator_t *generator,
         code->src1 = lvalue->index;
         code->src2 = lvalue->index;
 
-        return NJS_OK;
+        return njs_generator_stack_pop(vm, generator, NULL);
     }
 
     /* lvalue->token == NJS_TOKEN_PROPERTY */
 
     /* Object. */
 
-    ret = njs_generator(vm, generator, lvalue->left);
+    njs_generator_next(generator, njs_generate, lvalue->left);
+
+    ret = njs_generator_after(vm, generator,
+                              njs_queue_first(&generator->stack), node,
+                              njs_generate_inc_dec_operation_prop,
+                              &post, sizeof(njs_bool_t));
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
     /* Property. */
 
-    ret = njs_generator(vm, generator, lvalue->right);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack),
+                               lvalue->right, njs_generate, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_inc_dec_operation_prop(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t              ret;
+    njs_bool_t             post;
+    njs_index_t            index, dest_index;
+    njs_parser_node_t      *lvalue;
+    njs_vmcode_3addr_t     *code;
+    njs_vmcode_prop_get_t  *prop_get;
+    njs_vmcode_prop_set_t  *prop_set;
+
+    lvalue = node->left;
 
     if (node->dest != NULL) {
         dest_index = node->dest->index;
@@ -2743,6 +3530,8 @@ njs_generate_inc_dec_operation(njs_vm_t *vm, njs_generator_t *generator,
 
 found:
 
+    post = *((njs_bool_t *) generator->context);
+
     index = post ? njs_generate_temp_index_get(vm, generator, node)
                  : dest_index;
 
@@ -2775,7 +3564,9 @@ found:
         }
     }
 
-    return njs_generate_children_indexes_release(vm, generator, lvalue);
+    njs_mp_free(vm->mem_pool, generator->context);
+
+    return njs_generate_children_indexes_release_pop(vm, generator, lvalue);
 }
 
 
@@ -2791,7 +3582,12 @@ njs_generate_function_declaration(njs_vm_t *vm, njs_generator_t *generator,
 
     var = njs_variable_reference(vm, node);
     if (njs_slow_path(var == NULL)) {
-        return njs_generate_reference_error(vm, generator, node);
+        ret = njs_generate_reference_error(vm, generator, node);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return ret;
+        }
+
+        return njs_generator_stack_pop(vm, generator, NULL);
     }
 
     if (njs_is_function(&var->value)) {
@@ -2821,7 +3617,7 @@ njs_generate_function_declaration(njs_vm_t *vm, njs_generator_t *generator,
 
     njs_set_function(&var->value, function);
 
-    return ret;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -2875,6 +3671,7 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
 {
     u_char         *p;
     int64_t        nargs;
+    njs_int_t      ret;
     njs_uint_t     index;
     njs_vm_code_t  *code;
 
@@ -2928,10 +3725,25 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
 
     scope->closures = generator->closures;
 
-    if (njs_slow_path(njs_generator(vm, generator, scope->top) != NJS_OK)) {
+    njs_queue_init(&generator->stack);
+
+    njs_generator_next(generator, njs_generate, scope->top);
+
+    ret = njs_generator_after(vm, generator,
+                              njs_queue_first(&generator->stack), NULL,
+                              njs_generate_scope_end, NULL, 0);
+    if (njs_slow_path(ret != NJS_OK)) {
         return NULL;
     }
 
+    do {
+        ret = generator->state(vm, generator, generator->node);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return NULL;
+        }
+
+    } while (generator->state != NULL);
+
     code = njs_arr_item(vm->codes, index);
     code->start = generator->code_start;
     code->end = generator->code_end;
@@ -2944,6 +3756,15 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
 }
 
 
+static njs_int_t
+njs_generate_scope_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    generator->state = NULL;
+    return NJS_OK;
+}
+
+
 static int64_t
 njs_generate_lambda_variables(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
@@ -2987,7 +3808,18 @@ static njs_int_t
 njs_generate_return_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t                ret;
+    njs_generator_next(generator, njs_generate, node->right);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_return_statement_end, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_return_statement_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
     njs_index_t              index;
     const njs_str_t          *dest;
     njs_vmcode_return_t      *code;
@@ -2995,11 +3827,6 @@ njs_generate_return_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_generator_block_t    *block, *immediate, *top;
     njs_vmcode_try_return_t  *try_return;
 
-    ret = njs_generator(vm, generator, node->right);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
-
     if (node->right != NULL) {
         index = node->right->index;
 
@@ -3021,7 +3848,7 @@ njs_generate_return_statement(njs_vm_t *vm, njs_generator_t *generator,
         code->retval = index;
         node->index = index;
 
-        return NJS_OK;
+        return njs_generator_stack_pop(vm, generator, NULL);
     }
 
     if (immediate->type == NJS_GENERATOR_TRY && immediate->exit != NULL) {
@@ -3060,7 +3887,7 @@ njs_generate_return_statement(njs_vm_t *vm, njs_generator_t *generator,
         return NJS_ERROR;
     }
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -3068,30 +3895,44 @@ static njs_int_t
 njs_generate_function_call(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t                    ret, nargs;
-    njs_jump_off_t               func_offset;
-    njs_variable_t               *var;
-    njs_parser_node_t            *name;
-    njs_vmcode_function_frame_t  *func;
+    njs_int_t       ret;
+    njs_variable_t  *var;
 
     var = NULL;
 
     if (node->left != NULL) {
         /* Generate function code in function expression. */
-        ret = njs_generator(vm, generator, node->left);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
 
-        name = node->left;
+        njs_generator_next(generator, njs_generate, node->left);
 
-    } else {
-        ret = njs_generate_variable(vm, generator, node, NJS_REFERENCE, &var);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), node,
+                                   njs_generate_function_call_arguments,
+                                   NULL, 0);
+    }
 
-        name = node;
+    ret = njs_generate_variable(vm, generator, node, NJS_REFERENCE, &var);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    return njs_generate_function_call_arguments(vm, generator, node);
+}
+
+
+static njs_int_t
+njs_generate_function_call_arguments(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t                    ret;
+    njs_jump_off_t               func_offset;
+    njs_parser_node_t            *name;
+    njs_vmcode_function_frame_t  *func;
+
+    name = node;
+
+    if (node->left != NULL) {
+        name = node->left;
     }
 
     njs_generate_code(generator, njs_vmcode_function_frame_t, func,
@@ -3099,48 +3940,82 @@ njs_generate_function_call(njs_vm_t *vm, njs_generator_t *generator,
     func_offset = njs_code_offset(generator, func);
     func->ctor = node->ctor;
     func->name = name->index;
+    func->nargs = 0;
 
-    nargs = njs_generate_move_arguments(vm, generator, node);
-    if (njs_slow_path(nargs < 0)) {
-        return nargs;
-    }
-
-    func = njs_code_ptr(generator, njs_vmcode_function_frame_t, func_offset);
-    func->nargs = nargs;
+    njs_generator_next(generator, njs_generate,
+                       (node->right != NULL ? node->right->left : NULL));
 
-    ret = njs_generate_call(vm, generator, node);
-    if (njs_fast_path(ret != NJS_OK)) {
+    ret = njs_generator_after(vm, generator,
+                              njs_queue_first(&generator->stack), node,
+                              njs_generate_function_call_end, NULL, 0);
+    if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
-    return NJS_OK;
+    if (node->right == NULL) {
+        return NJS_OK;
+    }
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node->right,
+                               njs_generate_move_arguments,
+                               &func_offset, sizeof(njs_jump_off_t));
 }
 
 
 static njs_int_t
-njs_generate_method_call(njs_vm_t *vm, njs_generator_t *generator,
+njs_generate_function_call_end(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t                  ret, nargs;
-    njs_jump_off_t             method_offset;
-    njs_parser_node_t          *prop;
-    njs_vmcode_method_frame_t  *method;
+    njs_int_t  ret;
+
+    ret = njs_generate_call(vm, generator, node);
+    if (njs_fast_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    return njs_generator_stack_pop(vm, generator, generator->context);
+}
+
+
+static njs_int_t
+njs_generate_method_call(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t          ret;
+    njs_parser_node_t  *prop;
 
     prop = node->left;
 
     /* Object. */
 
-    ret = njs_generator(vm, generator, prop->left);
+    njs_generator_next(generator, njs_generate, prop->left);
+
+    ret = njs_generator_after(vm, generator,
+                              njs_queue_first(&generator->stack), node,
+                              njs_generate_method_call_arguments, NULL, 0);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
 
     /* Method name. */
 
-    ret = njs_generator(vm, generator, prop->right);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), prop->right,
+                               njs_generate, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_method_call_arguments(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t                  ret;
+    njs_jump_off_t             method_offset;
+    njs_parser_node_t          *prop;
+    njs_vmcode_method_frame_t  *method;
+
+    prop = node->left;
 
     njs_generate_code(generator, njs_vmcode_method_frame_t, method,
                       NJS_VMCODE_METHOD_FRAME, 3, prop);
@@ -3148,21 +4023,41 @@ njs_generate_method_call(njs_vm_t *vm, njs_generator_t *generator,
     method->ctor = node->ctor;
     method->object = prop->left->index;
     method->method = prop->right->index;
+    method->nargs = 0;
+
+    njs_generator_next(generator, njs_generate,
+                       (node->right != NULL ? node->right->left : node->right));
+
+    ret = njs_generator_after(vm, generator,
+                              njs_queue_first(&generator->stack), node,
+                              njs_generate_method_call_end, NULL, 0);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
 
-    nargs = njs_generate_move_arguments(vm, generator, node);
-    if (njs_slow_path(nargs < 0)) {
-        return nargs;
+    if (node->right == NULL) {
+        return NJS_OK;
     }
 
-    method = njs_code_ptr(generator, njs_vmcode_method_frame_t, method_offset);
-    method->nargs = nargs;
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node->right,
+                               njs_generate_move_arguments,
+                               &method_offset, sizeof(njs_jump_off_t));
+}
+
+
+static njs_int_t
+njs_generate_method_call_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t  ret;
 
     ret = njs_generate_call(vm, generator, node);
     if (njs_fast_path(ret != NJS_OK)) {
         return ret;
     }
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, generator->context);
 }
 
 
@@ -3192,28 +4087,35 @@ static njs_int_t
 njs_generate_move_arguments(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t              ret;
-    njs_uint_t             nargs;
-    njs_parser_node_t      *arg;
-    njs_vmcode_move_arg_t  *move_arg;
+    njs_jump_off_t               func_offset;
+    njs_vmcode_move_arg_t        *move_arg;
+    njs_vmcode_function_frame_t  *func;
 
-    nargs = 0;
+    if (node == NULL) {
+        return njs_generator_stack_pop(vm, generator, generator->context);
+    }
 
-    for (arg = node->right; arg != NULL; arg = arg->right) {
-        ret = njs_generator(vm, generator, arg->left);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
+    njs_generate_code(generator, njs_vmcode_move_arg_t, move_arg,
+                      NJS_VMCODE_MOVE_ARG, 0, node);
+    move_arg->src = node->left->index;
+
+    func_offset = *((njs_jump_off_t *) generator->context);
+    func = njs_code_ptr(generator, njs_vmcode_function_frame_t, func_offset);
 
-        njs_generate_code(generator, njs_vmcode_move_arg_t, move_arg,
-                          NJS_VMCODE_MOVE_ARG, 0, node);
-        move_arg->src = arg->left->index;
-        move_arg->dst = nargs;
+    move_arg->dst = (njs_uint_t) func->nargs;
 
-        nargs++;
+    func->nargs++;
+
+    if (node->right == NULL) {
+        return njs_generator_stack_pop(vm, generator, generator->context);
     }
 
-    return nargs;
+    njs_generator_next(generator, njs_generate, node->right->left);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node->right,
+                               njs_generate_move_arguments,
+                               generator->context, 0);
 }
 
 
@@ -3243,25 +4145,16 @@ static njs_int_t
 njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t                    ret;
-    njs_str_t                    try_cont_label, try_exit_label,
-                                 catch_cont_label, catch_exit_label;
-    njs_index_t                  exception_index, exit_index, catch_index;
-    njs_jump_off_t               try_offset, try_end_offset, catch_offset,
-                                 catch_end_offset;
-    njs_variable_t               *var;
-    const njs_str_t              *dest_label;
-    njs_vmcode_catch_t           *catch;
-    njs_vmcode_finally_t         *finally;
-    njs_vmcode_try_end_t         *try_end, *catch_end;
-    njs_generator_patch_t        *patch;
-    njs_generator_block_t        *block, *try_block, *catch_block;
-    njs_vmcode_try_start_t       *try_start;
-    njs_vmcode_try_trampoline_t  *try_break, *try_continue;
+    njs_int_t                ret;
+    njs_index_t              exception_index, exit_index;
+    njs_vmcode_try_start_t   *try_start;
+    njs_generator_try_ctx_t  ctx;
+
+    njs_memzero(&ctx, sizeof(njs_generator_try_ctx_t));
 
     njs_generate_code(generator, njs_vmcode_try_start_t, try_start,
                       NJS_VMCODE_TRY_START, 2, node);
-    try_offset = njs_code_offset(generator, try_start);
+    ctx.try_offset = njs_code_offset(generator, try_start);
 
     exception_index = njs_generate_temp_index_get(vm, generator, node);
     if (njs_slow_path(exception_index == NJS_INDEX_ERROR)) {
@@ -3288,23 +4181,49 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
         return ret;
     }
 
-    try_block = generator->block;
-    try_block->index = exit_index;
+    ctx.try_block = generator->block;
+    ctx.try_block->index = exit_index;
+    ctx.exception_index = exception_index;
 
-    ret = njs_generator(vm, generator, node->left);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
+    ctx.catch_cont_label = undef_label;
+    ctx.catch_exit_label = undef_label;
+    ctx.try_cont_label = undef_label;
+    ctx.try_exit_label = undef_label;
+
+    njs_generator_next(generator, njs_generate, node->left);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_try_left,
+                               &ctx, sizeof(njs_generator_try_ctx_t));
+}
 
-    try_exit_label = undef_label;
-    try_cont_label = undef_label;
+
+static njs_int_t
+njs_generate_try_left(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t                    ret;
+    njs_index_t                  exit_index, catch_index;
+    njs_jump_off_t               try_end_offset;
+    njs_variable_t               *var;
+    njs_vmcode_catch_t           *catch;
+    njs_vmcode_try_end_t         *try_end;
+    njs_generator_block_t        *try_block;
+    njs_generator_try_ctx_t      *ctx;
+    njs_vmcode_try_trampoline_t  *try_break, *try_continue;
+
+    ctx = generator->context;
+
+    try_block = ctx->try_block;
+    exit_index = try_block->index;
 
     njs_generate_code(generator, njs_vmcode_try_end_t, try_end,
                       NJS_VMCODE_TRY_END, 0, NULL);
     try_end_offset = njs_code_offset(generator, try_end);
 
     if (try_block->exit != NULL) {
-        try_exit_label = try_block->exit->label;
+        ctx->try_exit_label = try_block->exit->label;
 
         njs_generate_patch_block(vm, generator, try_block->exit);
 
@@ -3319,7 +4238,7 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
     }
 
     if (try_block->continuation != NULL) {
-        try_cont_label = try_block->continuation->label;
+        ctx->try_cont_label = try_block->continuation->label;
 
         njs_generate_patch_block(vm, generator, try_block->continuation);
 
@@ -3336,14 +4255,12 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
 
     generator->block = try_block->next;
 
-    njs_code_set_jump_offset(generator, njs_vmcode_try_start_t, try_offset);
-    try_offset = try_end_offset;
+    njs_code_set_jump_offset(generator, njs_vmcode_try_start_t,
+                             ctx->try_offset);
+    ctx->try_offset = try_end_offset;
 
     node = node->right;
 
-    catch_exit_label = undef_label;
-    catch_cont_label = undef_label;
-
     if (node->token_type == NJS_TOKEN_CATCH) {
         /* A "try/catch" case. */
 
@@ -3356,210 +4273,292 @@ njs_generate_try_statement(njs_vm_t *vm, njs_generator_t *generator,
 
         njs_generate_code_catch(generator, catch, catch_index, node);
 
-        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_try_catch, ctx, 0);
+    }
+
+    if (node->left != NULL) {
+        /* A try/catch/finally case. */
+
+        var = njs_variable_reference(vm, node->left->left);
+        if (njs_slow_path(var == NULL)) {
+            return NJS_ERROR;
+        }
+
+        catch_index = node->left->left->index;
+
+        njs_generate_code_catch(generator, catch, catch_index, node);
+        ctx->catch_offset = njs_code_offset(generator, catch);
+
+        ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_TRY,
+                                       &no_label);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
 
-        njs_code_set_jump_offset(generator, njs_vmcode_try_end_t, try_offset);
+        ctx->catch_block = generator->block;
+        ctx->catch_block->index = exit_index;
+
+        njs_generator_next(generator, njs_generate, node->left->right);
+
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), node,
+                                   njs_generate_try_finally, ctx, 0);
+    }
+
+    /* A try/finally case. */
+
+    njs_generate_code_catch(generator, catch, ctx->exception_index, NULL);
+
+    ctx->catch_block = NULL;
+
+    njs_code_set_jump_offset(generator, njs_vmcode_try_end_t,
+                             ctx->try_offset);
+
+    njs_generator_next(generator, njs_generate, node->right);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_try_end, ctx, 0);
+}
+
+
+static njs_int_t
+njs_generate_try_catch(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t                ret;
+    njs_index_t              exit_index;
+    njs_vmcode_finally_t     *finally;
+    njs_generator_patch_t    *patch;
+    njs_generator_block_t    *block, *try_block;
+    njs_generator_try_ctx_t  *ctx;
+
+    ctx = generator->context;
+
+    try_block = ctx->try_block;
+    exit_index = try_block->index;
+
+    njs_code_set_jump_offset(generator, njs_vmcode_try_end_t,
+                             ctx->try_offset);
+
+    if (try_block->continuation != NULL || try_block->exit != NULL) {
+        njs_generate_code_finally(generator, finally, ctx->exception_index,
+                                  exit_index, NULL);
+
+        if (try_block->continuation != NULL) {
+            /*
+             * block != NULL is checked
+             * by njs_generate_continue_statement()
+             */
+            block = njs_generate_find_block(generator->block,
+                                            NJS_GENERATOR_LOOP,
+                                            &ctx->try_cont_label);
 
-        if (try_block->continuation != NULL || try_block->exit != NULL) {
-            njs_generate_code_finally(generator, finally, exception_index,
-                                      exit_index, NULL);
+            patch = njs_generate_make_continuation_patch(vm, block,
+                                                         &ctx->try_cont_label,
+                        njs_code_offset(generator, finally)
+                         + offsetof(njs_vmcode_finally_t, continue_offset));
+            if (njs_slow_path(patch == NULL)) {
+                return NJS_ERROR;
+            }
+        }
 
-            if (try_block->continuation != NULL) {
-                /*
-                 * block != NULL is checked
-                 * by njs_generate_continue_statement()
-                 */
-                block = njs_generate_find_block(generator->block,
-                                                NJS_GENERATOR_LOOP,
-                                                &try_cont_label);
+        if (try_block->exit != NULL) {
+            block = njs_generate_find_block(generator->block,
+                                            NJS_GENERATOR_ALL,
+                                            &ctx->try_exit_label);
 
-                patch = njs_generate_make_continuation_patch(vm, block,
-                                                             &try_cont_label,
+            if (block != NULL) {
+                patch = njs_generate_make_exit_patch(vm, block,
+                                                     &ctx->try_exit_label,
                             njs_code_offset(generator, finally)
-                             + offsetof(njs_vmcode_finally_t, continue_offset));
+                            + offsetof(njs_vmcode_finally_t, break_offset));
                 if (njs_slow_path(patch == NULL)) {
                     return NJS_ERROR;
                 }
             }
-
-            if (try_block->exit != NULL) {
-                block = njs_generate_find_block(generator->block,
-                                                NJS_GENERATOR_ALL,
-                                                &try_exit_label);
-
-                if (block != NULL) {
-                    patch = njs_generate_make_exit_patch(vm, block,
-                                                         &try_exit_label,
-                                njs_code_offset(generator, finally)
-                                + offsetof(njs_vmcode_finally_t, break_offset));
-                    if (njs_slow_path(patch == NULL)) {
-                        return NJS_ERROR;
-                    }
-                }
-            }
         }
+    }
 
-        /* TODO: release exception variable index. */
+    /* TODO: release exception variable index. */
 
-    } else {
-        if (node->left != NULL) {
-            /* A try/catch/finally case. */
+    ret = njs_generate_index_release(vm, generator, ctx->exception_index);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
 
-            var = njs_variable_reference(vm, node->left->left);
-            if (njs_slow_path(var == NULL)) {
-                return NJS_ERROR;
-            }
+    return njs_generator_stack_pop(vm, generator, ctx);
+}
 
-            catch_index = node->left->left->index;
 
-            njs_generate_code_catch(generator, catch, catch_index, node);
-            catch_offset = njs_code_offset(generator, catch);
+static njs_int_t
+njs_generate_try_finally(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_index_t                  exit_index;
+    njs_jump_off_t               catch_end_offset;
+    njs_vmcode_catch_t           *catch;
+    njs_vmcode_try_end_t         *catch_end;
+    njs_generator_block_t        *try_block, *catch_block;
+    njs_generator_try_ctx_t      *ctx;
+    njs_vmcode_try_trampoline_t  *try_break, *try_continue;
 
-            ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_TRY,
-                                           &no_label);
-            if (njs_slow_path(ret != NJS_OK)) {
-                return ret;
-            }
+    ctx = generator->context;
 
-            catch_block = generator->block;
-            catch_block->index = exit_index;
+    try_block = ctx->try_block;
+    exit_index = try_block->index;
+    catch_block = ctx->catch_block;
 
-            ret = njs_generator(vm, generator, node->left->right);
-            if (njs_slow_path(ret != NJS_OK)) {
-                return ret;
-            }
+    njs_generate_code(generator, njs_vmcode_try_end_t, catch_end,
+                      NJS_VMCODE_TRY_END, 0, node->left->right);
+    catch_end_offset = njs_code_offset(generator, catch_end);
 
-            njs_generate_code(generator, njs_vmcode_try_end_t, catch_end,
-                              NJS_VMCODE_TRY_END, 0, node->left->right);
-            catch_end_offset = njs_code_offset(generator, catch_end);
+    if (catch_block->exit != NULL) {
+        ctx->catch_exit_label = catch_block->exit->label;
 
-            if (catch_block->exit != NULL) {
-                catch_exit_label = catch_block->exit->label;
+        njs_generate_patch_block(vm, generator, catch_block->exit);
 
-                njs_generate_patch_block(vm, generator, catch_block->exit);
+        njs_generate_code(generator, njs_vmcode_try_trampoline_t,
+                          try_break, NJS_VMCODE_TRY_BREAK, 1, NULL);
 
-                njs_generate_code(generator, njs_vmcode_try_trampoline_t,
-                                  try_break, NJS_VMCODE_TRY_BREAK, 1, NULL);
+        try_break->exit_value = exit_index;
 
-                try_break->exit_value = exit_index;
+        try_break->offset = -sizeof(njs_vmcode_try_end_t);
 
-                try_break->offset = -sizeof(njs_vmcode_try_end_t);
+    } else {
+        try_break = NULL;
+    }
 
-            } else {
-                try_break = NULL;
-            }
+    if (catch_block->continuation != NULL) {
+        ctx->catch_cont_label = catch_block->continuation->label;
 
-            if (catch_block->continuation != NULL) {
-                catch_cont_label = catch_block->continuation->label;
+        njs_generate_patch_block(vm, generator,
+                                 catch_block->continuation);
 
-                njs_generate_patch_block(vm, generator,
-                                         catch_block->continuation);
+        njs_generate_code(generator, njs_vmcode_try_trampoline_t,
+                          try_continue, NJS_VMCODE_TRY_CONTINUE, 1,
+                          NULL);
 
-                njs_generate_code(generator, njs_vmcode_try_trampoline_t,
-                                  try_continue, NJS_VMCODE_TRY_CONTINUE, 1,
-                                  NULL);
+        try_continue->exit_value = exit_index;
 
-                try_continue->exit_value = exit_index;
+        try_continue->offset = -sizeof(njs_vmcode_try_end_t);
 
-                try_continue->offset = -sizeof(njs_vmcode_try_end_t);
+        if (try_break != NULL) {
+            try_continue->offset -= sizeof(njs_vmcode_try_trampoline_t);
+        }
+    }
 
-                if (try_break != NULL) {
-                    try_continue->offset -= sizeof(njs_vmcode_try_trampoline_t);
-                }
-            }
+    generator->block = catch_block->next;
+
+    njs_code_set_jump_offset(generator, njs_vmcode_catch_t,
+                             ctx->catch_offset);
 
-            generator->block = catch_block->next;
+    /* TODO: release exception variable index. */
 
-            njs_code_set_jump_offset(generator, njs_vmcode_catch_t,
-                                     catch_offset);
+    njs_generate_code_catch(generator, catch, ctx->exception_index, NULL);
 
-            /* TODO: release exception variable index. */
+    njs_code_set_jump_offset(generator, njs_vmcode_try_end_t,
+                             catch_end_offset);
 
-            njs_generate_code_catch(generator, catch, exception_index, NULL);
+    njs_code_set_jump_offset(generator, njs_vmcode_try_end_t,
+                             ctx->try_offset);
 
-            njs_code_set_jump_offset(generator, njs_vmcode_try_end_t,
-                                     catch_end_offset);
+    njs_generator_next(generator, njs_generate, node->right);
 
-        } else {
-            /* A try/finally case. */
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_try_end, ctx, 0);
+}
 
-            njs_generate_code_catch(generator, catch, exception_index, NULL);
 
-            catch_block = NULL;
-        }
+static njs_int_t
+njs_generate_try_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t                ret;
+    njs_index_t              exit_index;
+    const njs_str_t          *dest_label;
+    njs_vmcode_finally_t     *finally;
+    njs_generator_patch_t    *patch;
+    njs_generator_block_t    *block, *try_block, *catch_block;
+    njs_generator_try_ctx_t  *ctx;
 
-        njs_code_set_jump_offset(generator, njs_vmcode_try_end_t, try_offset);
+    ctx = generator->context;
 
-        ret = njs_generator(vm, generator, node->right);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
+    try_block = ctx->try_block;
+    exit_index = try_block->index;
+    catch_block = ctx->catch_block;
+
+    njs_generate_code_finally(generator, finally, ctx->exception_index,
+                              exit_index, node);
+
+    if (try_block->continuation != NULL
+        || (catch_block && catch_block->continuation != NULL))
+    {
+        dest_label = njs_generate_jump_destination(vm, generator->block,
+                                                   "try continue",
+                                                   NJS_GENERATOR_LOOP,
+                                                   &ctx->try_cont_label,
+                                                   &ctx->catch_cont_label);
+        if (njs_slow_path(dest_label == NULL)) {
+            return NJS_ERROR;
         }
 
-        njs_generate_code_finally(generator, finally, exception_index,
-                                  exit_index, node);
+        /*
+         * block != NULL is checked
+         * by njs_generate_continue_statement()
+         */
+        block = njs_generate_find_block(generator->block,
+                                        NJS_GENERATOR_LOOP, dest_label);
 
-        if (try_block->continuation != NULL
-            || (catch_block && catch_block->continuation != NULL))
-        {
-            dest_label = njs_generate_jump_destination(vm, generator->block,
-                                                       "try continue",
-                                                       NJS_GENERATOR_LOOP,
-                                                       &try_cont_label,
-                                                       &catch_cont_label);
-            if (njs_slow_path(dest_label == NULL)) {
-                return NJS_ERROR;
-            }
+        patch = njs_generate_make_continuation_patch(vm, block, dest_label,
+                         njs_code_offset(generator, finally)
+                         + offsetof(njs_vmcode_finally_t, continue_offset));
+        if (njs_slow_path(patch == NULL)) {
+            return NJS_ERROR;
+        }
+    }
 
-            /*
-             * block != NULL is checked
-             * by njs_generate_continue_statement()
-             */
-            block = njs_generate_find_block(generator->block,
-                                            NJS_GENERATOR_LOOP, dest_label);
+    if (try_block->exit != NULL
+        || (catch_block != NULL && catch_block->exit != NULL))
+    {
+        dest_label = njs_generate_jump_destination(vm, generator->block,
+                                                   "try break/return",
+                                                   NJS_GENERATOR_ALL
+                                                   | NJS_GENERATOR_TRY,
+                                                   &ctx->try_exit_label,
+                                                   &ctx->catch_exit_label);
+        if (njs_slow_path(dest_label == NULL)) {
+            return NJS_ERROR;
+        }
 
-            patch = njs_generate_make_continuation_patch(vm, block, dest_label,
-                             njs_code_offset(generator, finally)
-                             + offsetof(njs_vmcode_finally_t, continue_offset));
+        /*
+         * block can be NULL for "return" instruction in
+         * outermost try-catch block.
+         */
+        block = njs_generate_find_block(generator->block,
+                                        NJS_GENERATOR_ALL
+                                        | NJS_GENERATOR_TRY, dest_label);
+        if (block != NULL) {
+            patch = njs_generate_make_exit_patch(vm, block, dest_label,
+                            njs_code_offset(generator, finally)
+                            + offsetof(njs_vmcode_finally_t, break_offset));
             if (njs_slow_path(patch == NULL)) {
                 return NJS_ERROR;
             }
         }
+    }
 
-        if (try_block->exit != NULL
-            || (catch_block != NULL && catch_block->exit != NULL))
-        {
-            dest_label = njs_generate_jump_destination(vm, generator->block,
-                                                       "try break/return",
-                                                       NJS_GENERATOR_ALL
-                                                       | NJS_GENERATOR_TRY,
-                                                       &try_exit_label,
-                                                       &catch_exit_label);
-            if (njs_slow_path(dest_label == NULL)) {
-                return NJS_ERROR;
-            }
-
-            /*
-             * block can be NULL for "return" instruction in
-             * outermost try-catch block.
-             */
-            block = njs_generate_find_block(generator->block,
-                                            NJS_GENERATOR_ALL
-                                            | NJS_GENERATOR_TRY, dest_label);
-            if (block != NULL) {
-                patch = njs_generate_make_exit_patch(vm, block, dest_label,
-                                njs_code_offset(generator, finally)
-                                + offsetof(njs_vmcode_finally_t, break_offset));
-                if (njs_slow_path(patch == NULL)) {
-                    return NJS_ERROR;
-                }
-            }
-        }
+    ret = njs_generate_index_release(vm, generator, ctx->exception_index);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
     }
 
-    return njs_generate_index_release(vm, generator, exception_index);
+    return njs_generator_stack_pop(vm, generator, ctx);
 }
 
 
@@ -3567,20 +4566,26 @@ static njs_int_t
 njs_generate_throw_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t           ret;
-    njs_vmcode_throw_t  *throw;
+    njs_generator_next(generator, njs_generate, node->right);
 
-    ret = njs_generator(vm, generator, node->right);
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_throw_end, NULL, 0);
+}
 
-    if (njs_fast_path(ret == NJS_OK)) {
-        njs_generate_code(generator, njs_vmcode_throw_t, throw,
-                          NJS_VMCODE_THROW, 1, node);
+static njs_int_t
+njs_generate_throw_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_vmcode_throw_t  *throw;
 
-        node->index = node->right->index;
-        throw->retval = node->index;
-    }
+    njs_generate_code(generator, njs_vmcode_throw_t, throw,
+                      NJS_VMCODE_THROW, 1, node);
 
-    return ret;
+    node->index = node->right->index;
+    throw->retval = node->index;
+
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -3588,12 +4593,8 @@ static njs_int_t
 njs_generate_import_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t                 ret;
-    njs_index_t               index;
-    njs_module_t              *module;
-    njs_variable_t            *var;
-    njs_parser_node_t         *lvalue, *expr;
-    njs_vmcode_object_copy_t  *copy;
+    njs_variable_t     *var;
+    njs_parser_node_t  *lvalue, *expr;
 
     lvalue = node->left;
     expr = node->right;
@@ -3603,23 +4604,36 @@ njs_generate_import_statement(njs_vm_t *vm, njs_generator_t *generator,
         return NJS_ERROR;
     }
 
-    index = lvalue->index;
-
     if (expr->left != NULL) {
-        ret = njs_generator(vm, generator, expr->left);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return ret;
-        }
+        njs_generator_next(generator, njs_generate, expr->left);
+
+        return njs_generator_after(vm, generator,
+                                   njs_queue_first(&generator->stack), node,
+                                   njs_generate_import_statement_end, NULL, 0);
     }
 
+    return njs_generate_import_statement_end(vm, generator, node);
+}
+
+
+static njs_int_t
+njs_generate_import_statement_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_module_t              *module;
+    njs_parser_node_t         *expr;
+    njs_vmcode_object_copy_t  *copy;
+
+    expr = node->right;
+
     module = (njs_module_t *) expr->index;
 
     njs_generate_code(generator, njs_vmcode_object_copy_t, copy,
                       NJS_VMCODE_OBJECT_COPY, 2, node);
-    copy->retval = index;
+    copy->retval = node->left->index;
     copy->object = module->index;
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
 }
 
 
@@ -3627,23 +4641,140 @@ static njs_int_t
 njs_generate_export_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_int_t            ret;
+    njs_generator_next(generator, njs_generate, node->right);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_export_statement_end, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_export_statement_end(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
     njs_parser_node_t    *obj;
     njs_vmcode_return_t  *code;
 
     obj = node->right;
 
-    ret = njs_generator(vm, generator, obj);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
-
     njs_generate_code(generator, njs_vmcode_return_t, code,
                       NJS_VMCODE_RETURN, 1, NULL);
     code->retval = obj->index;
     node->index = obj->index;
 
-    return NJS_OK;
+    return njs_generator_stack_pop(vm, generator, NULL);
+}
+
+
+static njs_int_t
+njs_generate_wo_dest(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_parser_scope_t  *scope;
+
+    scope = njs_function_scope(node->scope);
+
+    scope->dest_disable = 1;
+
+    njs_generator_next(generator, njs_generate, node);
+
+    return njs_generator_after(vm, generator,
+                               njs_queue_first(&generator->stack), node,
+                               njs_generate_wo_dest_after, NULL, 0);
+}
+
+
+static njs_int_t
+njs_generate_wo_dest_after(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_parser_scope_t  *scope;
+
+    scope = njs_function_scope(node->scope);
+
+    scope->dest_disable = 0;
+
+    return njs_generator_stack_pop(vm, generator, NULL);
+}
+
+
+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)
+{
+    njs_int_t                ret;
+    njs_index_t              index;
+    njs_value_t              property;
+    njs_vmcode_prop_get_t    *prop_get;
+    const njs_lexer_entry_t  *lex_entry;
+
+    index = njs_generate_temp_index_get(vm, generator, node);
+    if (njs_slow_path(index == NJS_INDEX_ERROR)) {
+        return NJS_ERROR;
+    }
+
+    njs_generate_code(generator, njs_vmcode_prop_get_t, prop_get,
+                 exception ? NJS_VMCODE_GLOBAL_GET: NJS_VMCODE_PROPERTY_GET,
+                 3, node);
+
+    prop_get->value = index;
+
+    prop_get->object = njs_scope_global_this_index();
+    if (njs_slow_path(prop_get->object == NJS_INDEX_ERROR)) {
+        return NJS_ERROR;
+    }
+
+    lex_entry = njs_lexer_entry(node->u.reference.unique_id);
+    if (njs_slow_path(lex_entry == NULL)) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_string_set(vm, &property, lex_entry->name.start,
+                         lex_entry->name.length);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    prop_get->property = njs_scope_global_index(vm, &property,
+                                                generator->runtime);
+    if (njs_slow_path(prop_get->property == NJS_INDEX_ERROR)) {
+        return NJS_ERROR;
+    }
+
+    node->index = index;
+
+    if (!exception) {
+        return NJS_OK;
+    }
+
+    return njs_generate_reference_error(vm, generator, node);
+}
+
+
+static njs_int_t
+njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_vmcode_error_t       *ref_err;
+    const njs_lexer_entry_t  *lex_entry;
+
+    if (njs_slow_path(!node->u.reference.not_defined)) {
+        njs_internal_error(vm, "variable is not defined but not_defined "
+                               "is not set");
+        return NJS_ERROR;
+    }
+
+    njs_generate_code(generator, njs_vmcode_error_t, ref_err, NJS_VMCODE_ERROR,
+                      0, NULL);
+
+    ref_err->type = NJS_OBJ_TYPE_REF_ERROR;
+    lex_entry = njs_lexer_entry(node->u.reference.unique_id);
+    if (njs_slow_path(lex_entry == NULL)) {
+        return NJS_ERROR;
+    }
+
+    return njs_name_copy(vm, &ref_err->u.name, &lex_entry->name);
 }
 
 
@@ -3752,6 +4883,22 @@ njs_generate_children_indexes_release(njs_vm_t *vm, njs_generator_t *generator,
 }
 
 
+static njs_int_t
+njs_generate_children_indexes_release_pop(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node)
+{
+    njs_int_t  ret;
+
+    ret = njs_generate_node_index_release(vm, generator, node->left);
+
+    if (njs_fast_path(ret == NJS_OK)) {
+        return njs_generate_node_index_release_pop(vm, generator, node->right);
+    }
+
+    return ret;
+}
+
+
 static njs_int_t
 njs_generate_node_index_release(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
@@ -3763,6 +4910,22 @@ njs_generate_node_index_release(njs_vm_t *vm, njs_generator_t *generator,
     return NJS_OK;
 }
 
+static njs_int_t
+njs_generate_node_index_release_pop(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node)
+{
+    njs_int_t  ret;
+
+    if (node != NULL && node->temporary) {
+        ret = njs_generate_index_release(vm, generator, node->index);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return ret;
+        }
+    }
+
+    return njs_generator_stack_pop(vm, generator, NULL);
+}
+
 
 static njs_int_t
 njs_generate_index_release(njs_vm_t *vm, njs_generator_t *generator,
@@ -3792,82 +4955,3 @@ njs_generate_index_release(njs_vm_t *vm, njs_generator_t *generator,
 
     return NJS_ERROR;
 }
-
-
-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)
-{
-    njs_int_t                ret;
-    njs_index_t              index;
-    njs_value_t              property;
-    njs_vmcode_prop_get_t    *prop_get;
-    const njs_lexer_entry_t  *lex_entry;
-
-    index = njs_generate_temp_index_get(vm, generator, node);
-    if (njs_slow_path(index == NJS_INDEX_ERROR)) {
-        return NJS_ERROR;
-    }
-
-    njs_generate_code(generator, njs_vmcode_prop_get_t, prop_get,
-                 exception ? NJS_VMCODE_GLOBAL_GET: NJS_VMCODE_PROPERTY_GET,
-                 3, node);
-
-    prop_get->value = index;
-
-    prop_get->object = njs_scope_global_this_index();
-    if (njs_slow_path(prop_get->object == NJS_INDEX_ERROR)) {
-        return NJS_ERROR;
-    }
-
-    lex_entry = njs_lexer_entry(node->u.reference.unique_id);
-    if (njs_slow_path(lex_entry == NULL)) {
-        return NJS_ERROR;
-    }
-
-    ret = njs_string_set(vm, &property, lex_entry->name.start,
-                         lex_entry->name.length);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return NJS_ERROR;
-    }
-
-    prop_get->property = njs_scope_global_index(vm, &property,
-                                                generator->runtime);
-    if (njs_slow_path(prop_get->property == NJS_INDEX_ERROR)) {
-        return NJS_ERROR;
-    }
-
-    node->index = index;
-
-    if (!exception) {
-        return NJS_OK;
-    }
-
-    return njs_generate_reference_error(vm, generator, node);
-}
-
-
-static njs_int_t
-njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator,
-    njs_parser_node_t *node)
-{
-    njs_vmcode_error_t       *ref_err;
-    const njs_lexer_entry_t  *lex_entry;
-
-    if (njs_slow_path(!node->u.reference.not_defined)) {
-        njs_internal_error(vm, "variable is not defined but not_defined "
-                               "is not set");
-        return NJS_ERROR;
-    }
-
-    njs_generate_code(generator, njs_vmcode_error_t, ref_err, NJS_VMCODE_ERROR,
-                      0, NULL);
-
-    ref_err->type = NJS_OBJ_TYPE_REF_ERROR;
-    lex_entry = njs_lexer_entry(node->u.reference.unique_id);
-    if (njs_slow_path(lex_entry == NULL)) {
-        return NJS_ERROR;
-    }
-
-    return njs_name_copy(vm, &ref_err->u.name, &lex_entry->name);
-}
index 74d7a5cafb968da5c1ba8065ff980492bacdec50..e9ed37f3ab5c34a1c534527d36246d0648628287 100644 (file)
 
 typedef struct njs_generator_block_s   njs_generator_block_t;
 
+
+typedef njs_int_t (*njs_generator_state_func_t)(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
+
+
 struct njs_generator_s {
+    njs_generator_state_func_t      state;
+    njs_queue_t                     stack;
+    njs_parser_node_t               *node;
+    void                            *context;
+
     njs_value_t                     *local_scope;
 
     njs_generator_block_t           *block;
index 4f783b8f9a8607f8541b8ab65d9775487bfba275..b623ab61bbdbc2439b74c77d205124536a3ffea8 100644 (file)
@@ -12957,41 +12957,48 @@ static njs_unit_test_t  njs_test[] =
       njs_str("true") },
 
 #if NJS_HAVE_LARGE_STACK
-    { njs_str("new Function(\"(\".repeat(2**13));"),
+    { njs_str("new Function('('.repeat(2**13));"),
       njs_str("SyntaxError: Unexpected token \"}\" in runtime:1") },
 
-    { njs_str("new Function(\"{\".repeat(2**13));"),
+    { njs_str("new Function('{'.repeat(2**13));"),
       njs_str("SyntaxError: Unexpected token \")\" in runtime:1") },
 
-    { njs_str("new Function(\"[\".repeat(2**13));"),
+    { njs_str("new Function('['.repeat(2**13));"),
       njs_str("SyntaxError: Unexpected token \"}\" in runtime:1") },
 
-    { njs_str("new Function(\"`\".repeat(2**13));"),
-      njs_str("RangeError: Maximum call stack size exceeded") },
+    { njs_str("new Function('`'.repeat(2**13));"),
+      njs_str("[object Function]") },
 
-    { njs_str("new Function(\"{[\".repeat(2**13));"),
+    { njs_str("new Function('{['.repeat(2**13));"),
       njs_str("SyntaxError: Unexpected token \"}\" in runtime:1") },
 
-    { njs_str("new Function(\"{;\".repeat(2**13));"),
+    { njs_str("new Function('{;'.repeat(2**13));"),
       njs_str("SyntaxError: Unexpected token \")\" in runtime:1") },
 
-    { njs_str("new Function(\"1;\".repeat(2**13));"),
-      njs_str("RangeError: Maximum call stack size exceeded") },
+    { njs_str("(new Function('1;'.repeat(2**13) + 'return 2'))()"),
+      njs_str("2") },
 
-    { njs_str("new Function(\"~\".repeat(2**13));"),
-      njs_str("SyntaxError: Unexpected token \"}\" in runtime:1") },
+    { njs_str("(new Function('return' + '~'.repeat(2**13) + '3'))()"),
+      njs_str("3") },
 
-    { njs_str("new Function(\"new \".repeat(2**13));"),
-      njs_str("SyntaxError: Unexpected token \"}\" in runtime:1") },
+    { njs_str("(new Function('return' + '~'.repeat(2**13+1) + '3'))()"),
+      njs_str("-4") },
 
-    { njs_str("new Function(\"typeof \".repeat(2**13));"),
+    { njs_str("new Function('new '.repeat(2**13));"),
       njs_str("SyntaxError: Unexpected token \"}\" in runtime:1") },
 
-    { njs_str("new Function(\"1\" + \"** 1\".repeat(2**13));"),
-      njs_str("RangeError: Maximum call stack size exceeded") },
+    { njs_str("(new Function('return ' + 'typeof '.repeat(2**13) + 'x'))()"),
+      njs_str("string") },
 
-    { njs_str("new Function(\"var a; a\" + \"= a\".repeat(2**13));"),
-      njs_str("RangeError: Maximum call stack size exceeded") },
+    { njs_str("(new Function('return 5' + '** 1'.repeat(2**13)))()"),
+      njs_str("5") },
+
+    { njs_str("(new Function('var a = 7; return a' + '= a'.repeat(2**13)))()"),
+      njs_str("7") },
+
+    { njs_str("var a = (new Function('return [' + '1,'.repeat(2**13) + ']'))();"
+              "a.push(5); [a[2**13 - 1], a[2**13]]"),
+      njs_str("1,5") },
 #endif
 
     { njs_str("var f = new Function('return 1;'); f();"),