From 3e7d070acc6b7c3d17862048ad754a9f16a1738a Mon Sep 17 00:00:00 2001 From: Alexander Borisov Date: Thu, 15 Jul 2021 20:32:40 +0300 Subject: [PATCH] Removed recursion from code generator. --- src/njs_generator.c | 2832 ++++++++++++++++++++++++++------------ src/njs_generator.h | 10 + src/test/njs_unit_test.c | 43 +- 3 files changed, 1993 insertions(+), 892 deletions(-) diff --git a/src/njs_generator.c b/src/njs_generator.c index 0a021db6..1bfdbb6e 100644 --- a/src/njs_generator.c +++ b/src/njs_generator.c @@ -12,6 +12,15 @@ typedef struct njs_generator_patch_s njs_generator_patch_t; +typedef enum { + NJS_GENERATOR_LOOP = 1, + NJS_GENERATOR_SWITCH = 2, + NJS_GENERATOR_BLOCK = 4, + NJS_GENERATOR_TRY = 8, +#define NJS_GENERATOR_ALL (NJS_GENERATOR_LOOP | NJS_GENERATOR_SWITCH) +} njs_generator_block_type_t; + + struct njs_generator_patch_s { /* * The jump_offset field points to jump offset field which contains a small @@ -26,15 +35,6 @@ struct njs_generator_patch_s { }; -typedef enum { - NJS_GENERATOR_LOOP = 1, - NJS_GENERATOR_SWITCH = 2, - NJS_GENERATOR_BLOCK = 4, - NJS_GENERATOR_TRY = 8, -#define NJS_GENERATOR_ALL (NJS_GENERATOR_LOOP | NJS_GENERATOR_SWITCH) -} njs_generator_block_type_t; - - struct njs_generator_block_s { njs_generator_block_type_t type; /* 4 bits */ njs_str_t label; @@ -54,12 +54,50 @@ struct njs_generator_block_s { }; -static njs_int_t njs_generator(njs_vm_t *vm, njs_generator_t *generator, - njs_parser_node_t *node); +typedef struct { + njs_generator_state_func_t state; + njs_queue_link_t link; + njs_parser_node_t *node; + void *context; +} njs_generator_stack_entry_t; + + +typedef struct { + njs_generator_patch_t *patch; + njs_generator_patch_t **last; + njs_vmcode_jump_t *jump; + njs_jump_off_t jump_offset; + njs_index_t index; +} njs_generator_switch_ctx_t; + + +typedef struct { + njs_jump_off_t jump_offset; + njs_jump_off_t loop_offset; + njs_vmcode_jump_t *jump; + njs_variable_t *var; + njs_index_t index; +} njs_generator_loop_ctx_t; + + +typedef struct { + njs_index_t exception_index; + njs_jump_off_t try_offset; + njs_jump_off_t catch_offset; + njs_generator_block_t *try_block; + njs_generator_block_t *catch_block; + njs_str_t try_cont_label; + njs_str_t try_exit_label; + njs_str_t catch_cont_label; + njs_str_t catch_exit_label; +} njs_generator_try_ctx_t; + + static u_char *njs_generate_reserve(njs_vm_t *vm, njs_generator_t *generator, size_t size); static njs_int_t njs_generate_code_map(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node, u_char *code); + static njs_int_t njs_generate_name(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator, @@ -67,26 +105,72 @@ static njs_int_t njs_generate_variable(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); -} diff --git a/src/njs_generator.h b/src/njs_generator.h index 74d7a5ca..e9ed37f3 100644 --- a/src/njs_generator.h +++ b/src/njs_generator.h @@ -10,7 +10,17 @@ 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; diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 4f783b8f..b623ab61 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -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();"), -- 2.47.3