details: https://github.com/nginx/njs/commit/60e28d7bde0f83adf825976fbabf9f73ccae698c branches: master commit: 60e28d7bde0f83adf825976fbabf9f73ccae698c user: Dmitry Volyntsev <xei...@nginx.com> date: Mon, 9 Jun 2025 18:38:15 -0700 description: Moving child function declaration instantiation to bytecode.
Children functions need to be hoisted and instantiated at the beginning of a function call. Previously, it was done as a part of C code that implements JS function call. Now, each child function is instantiated by FUNCTION instruction at a function prelude. This makes global and function code similar, which in turn allows to get rid of FUNCTION COPY instruction which was only needed for global code. --- src/njs_disassembler.c | 3 -- src/njs_function.c | 24 -------------- src/njs_function.h | 3 -- src/njs_generator.c | 88 +++++++++++++++++++++++++++++++------------------- src/njs_parser.h | 3 +- src/njs_variable.c | 3 +- src/njs_vm.c | 5 --- src/njs_vmcode.c | 47 +++------------------------ src/njs_vmcode.h | 8 ----- 9 files changed, 63 insertions(+), 121 deletions(-) diff --git a/src/njs_disassembler.c b/src/njs_disassembler.c index c7927bf5..72ea63b9 100644 --- a/src/njs_disassembler.c +++ b/src/njs_disassembler.c @@ -30,9 +30,6 @@ static njs_code_name_t code_names[] = { { NJS_VMCODE_TEMPLATE_LITERAL, sizeof(njs_vmcode_template_literal_t), njs_str("TEMPLATE LITERAL") }, - { NJS_VMCODE_FUNCTION_COPY, sizeof(njs_vmcode_function_copy_t), - njs_str("FUNCTION COPY ") }, - { NJS_VMCODE_PROPERTY_GET, sizeof(njs_vmcode_prop_get_t), njs_str("PROP GET ") }, { NJS_VMCODE_PROPERTY_ATOM_GET, sizeof(njs_vmcode_prop_get_t), diff --git a/src/njs_function.c b/src/njs_function.c index 1db0d7ab..06948177 100644 --- a/src/njs_function.c +++ b/src/njs_function.c @@ -523,7 +523,6 @@ njs_function_lambda_call(njs_vm_t *vm, njs_value_t *retval, void *promise_cap) njs_value_t *args, **local, *value; njs_value_t **cur_local, **cur_closures; njs_function_t *function; - njs_declaration_t *declr; njs_function_lambda_t *lambda; frame = (njs_frame_t *) vm->top_frame; @@ -582,29 +581,6 @@ njs_function_lambda_call(njs_vm_t *vm, njs_value_t *retval, void *promise_cap) vm->active_frame = frame; - /* Closures */ - - n = lambda->ndeclarations; - - while (n != 0) { - n--; - - declr = &lambda->declarations[n]; - value = njs_scope_value(vm, declr->index); - - *value = *declr->value; - - function = njs_function_value_copy(vm, value); - if (njs_slow_path(function == NULL)) { - return NJS_ERROR; - } - - ret = njs_function_capture_closure(vm, function, function->u.lambda); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } - } - ret = njs_vmcode_interpreter(vm, lambda->start, retval, promise_cap, NULL); /* Restore current level. */ diff --git a/src/njs_function.h b/src/njs_function.h index 6516ff78..5aa98dd3 100644 --- a/src/njs_function.h +++ b/src/njs_function.h @@ -13,9 +13,6 @@ struct njs_function_lambda_s { uint32_t nclosures; uint32_t nlocal; - njs_declaration_t *declarations; - uint32_t ndeclarations; - njs_index_t self; uint32_t nargs; diff --git a/src/njs_generator.c b/src/njs_generator.c index e8c61c0a..bb443017 100644 --- a/src/njs_generator.c +++ b/src/njs_generator.c @@ -890,11 +890,10 @@ 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; - njs_vmcode_function_copy_t *copy; + njs_int_t ret; + njs_variable_t *var; + njs_parser_scope_t *scope; + njs_vmcode_variable_t *variable; var = njs_variable_reference(vm, node); if (njs_slow_path(var == NULL)) { @@ -906,13 +905,6 @@ njs_generate_name(njs_vm_t *vm, njs_generator_t *generator, return njs_generator_stack_pop(vm, generator, NULL); } - if (var->function && var->type == NJS_VARIABLE_FUNCTION) { - njs_generate_code(generator, njs_vmcode_function_copy_t, copy, - NJS_VMCODE_FUNCTION_COPY, node); - copy->function = &var->value; - copy->retval = node->index; - } - if (var->init) { return njs_generator_stack_pop(vm, generator, NULL); } @@ -935,10 +927,9 @@ static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node, njs_reference_type_t type, njs_variable_t **retvar) { - njs_variable_t *var; - njs_parser_scope_t *scope; - njs_vmcode_variable_t *variable; - njs_vmcode_function_copy_t *copy; + njs_variable_t *var; + njs_parser_scope_t *scope; + njs_vmcode_variable_t *variable; var = njs_variable_reference(vm, node); @@ -958,13 +949,6 @@ njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator, } } - if (var->function && var->type == NJS_VARIABLE_FUNCTION) { - njs_generate_code(generator, njs_vmcode_function_copy_t, copy, - NJS_VMCODE_FUNCTION_COPY, node); - copy->function = &var->value; - copy->retval = node->index; - } - if (var->init) { return NJS_OK; } @@ -4293,7 +4277,6 @@ njs_generate_function_scope(njs_vm_t *vm, njs_generator_t *prev, const njs_str_t *name) { njs_int_t ret; - njs_arr_t *arr; njs_uint_t depth; njs_vm_code_t *code; njs_generator_t generator; @@ -4327,10 +4310,6 @@ njs_generate_function_scope(njs_vm_t *vm, njs_generator_t *prev, lambda->nclosures = generator.closures->items; lambda->nlocal = node->scope->items; - arr = node->scope->declarations; - lambda->declarations = (arr != NULL) ? arr->start : NULL; - lambda->ndeclarations = (arr != NULL) ? arr->items : 0; - return NJS_OK; } @@ -4339,11 +4318,15 @@ njs_vm_code_t * njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator, njs_parser_scope_t *scope, const njs_str_t *name) { - u_char *p; - int64_t nargs; - njs_int_t ret; - njs_uint_t index; - njs_vm_code_t *code; + u_char *p, *code_start; + size_t code_size, prelude; + int64_t nargs; + njs_int_t ret; + njs_arr_t *arr; + njs_uint_t index, n; + njs_vm_code_t *code; + njs_declaration_t *declr; + njs_vmcode_function_t *fun; generator->code_size = 128; @@ -4414,6 +4397,45 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator, } while (generator->state != NULL); + arr = scope->declarations; + scope->declarations = NULL; + + if (arr != NULL && arr->items > 0) { + declr = arr->start; + prelude = sizeof(njs_vmcode_function_t) * arr->items; + code_size = generator->code_end - generator->code_start; + + for (n = 0; n < arr->items; n++) { + fun = (njs_vmcode_function_t *) njs_generate_reserve(vm, + generator, sizeof(njs_vmcode_function_t)); + if (njs_slow_path(fun == NULL)) { + njs_memory_error(vm); + return NULL; + } + + generator->code_end += sizeof(njs_vmcode_function_t); + fun->code = NJS_VMCODE_FUNCTION; + + fun->lambda = declr[n].lambda; + fun->async = declr[n].async; + fun->retval = declr[n].index; + } + + code_start = njs_mp_alloc(vm->mem_pool, code_size + prelude); + if (njs_slow_path(code_start == NULL)) { + njs_memory_error(vm); + return NULL; + } + + memcpy(code_start, &generator->code_start[code_size], prelude); + memcpy(&code_start[prelude], generator->code_start, code_size); + + njs_mp_free(vm->mem_pool, generator->code_start); + + generator->code_start = code_start; + generator->code_end = code_start + code_size + prelude; + } + code = njs_arr_item(vm->codes, index); code->start = generator->code_start; code->end = generator->code_end; diff --git a/src/njs_parser.h b/src/njs_parser.h index 2f7cff79..ebe5e686 100644 --- a/src/njs_parser.h +++ b/src/njs_parser.h @@ -109,8 +109,9 @@ typedef struct { typedef struct { - njs_value_t *value; + njs_function_lambda_t *lambda; njs_index_t index; + njs_bool_t async; } njs_declaration_t; diff --git a/src/njs_variable.c b/src/njs_variable.c index 40924ccf..bdf0d959 100644 --- a/src/njs_variable.c +++ b/src/njs_variable.c @@ -79,7 +79,8 @@ njs_variable_function_add(njs_parser_t *parser, njs_parser_scope_t *scope, var->index = njs_scope_index(root->type, root->items, NJS_LEVEL_LOCAL, type); - declr->value = &var->value; + declr->lambda = lambda; + declr->async = !ctor; declr->index = var->index; root->items++; diff --git a/src/njs_vm.c b/src/njs_vm.c index 008f9d04..18a1c8e6 100644 --- a/src/njs_vm.c +++ b/src/njs_vm.c @@ -310,7 +310,6 @@ njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start, u_char *end) { njs_int_t ret; - njs_arr_t *arr; njs_mod_t *module; njs_parser_t parser; njs_vm_code_t *code; @@ -366,10 +365,6 @@ njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start, lambda->start = generator.code_start; lambda->nlocal = scope->items; - arr = scope->declarations; - lambda->declarations = (arr != NULL) ? arr->start : NULL; - lambda->ndeclarations = (arr != NULL) ? arr->items : 0; - module->function.u.lambda = lambda; return module; diff --git a/src/njs_vmcode.c b/src/njs_vmcode.c index c0e8333d..c7adf63f 100644 --- a/src/njs_vmcode.c +++ b/src/njs_vmcode.c @@ -16,15 +16,12 @@ struct njs_property_next_s { static njs_jump_off_t njs_vmcode_object(njs_vm_t *vm, njs_value_t *retval); static njs_jump_off_t njs_vmcode_array(njs_vm_t *vm, u_char *pc, njs_value_t *retval); -static njs_jump_off_t njs_vmcode_function(njs_vm_t *vm, u_char *pc, - njs_value_t *retval); +static njs_jump_off_t njs_vmcode_function(njs_vm_t *vm, u_char *pc); static njs_jump_off_t njs_vmcode_arguments(njs_vm_t *vm, u_char *pc); static njs_jump_off_t njs_vmcode_regexp(njs_vm_t *vm, u_char *pc, njs_value_t *retval); static njs_jump_off_t njs_vmcode_template_literal(njs_vm_t *vm, njs_value_t *retval); -static njs_jump_off_t njs_vmcode_function_copy(njs_vm_t *vm, njs_value_t *value, - njs_index_t retval); static njs_jump_off_t njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *value, njs_value_t *key, njs_value_t *retval); @@ -113,7 +110,6 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_char *pc, njs_value_t *rval, njs_vmcode_equal_jump_t *equal; njs_vmcode_try_return_t *try_return; njs_vmcode_method_frame_t *method_frame; - njs_vmcode_function_copy_t *fcopy; njs_vmcode_prop_accessor_t *accessor; njs_vmcode_try_trampoline_t *try_trampoline; njs_vmcode_function_frame_t *function_frame; @@ -157,7 +153,6 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_char *pc, njs_value_t *rval, NJS_GOTO_ROW(NJS_VMCODE_IF_EQUAL_JUMP), NJS_GOTO_ROW(NJS_VMCODE_PROPERTY_INIT), NJS_GOTO_ROW(NJS_VMCODE_RETURN), - NJS_GOTO_ROW(NJS_VMCODE_FUNCTION_COPY), NJS_GOTO_ROW(NJS_VMCODE_FUNCTION_FRAME), NJS_GOTO_ROW(NJS_VMCODE_METHOD_FRAME), NJS_GOTO_ROW(NJS_VMCODE_FUNCTION_CALL), @@ -1155,9 +1150,7 @@ NEXT_LBL; CASE (NJS_VMCODE_FUNCTION): njs_vmcode_debug_opcode(); - njs_vmcode_operand(vm, vmcode->operand1, retval); - - ret = njs_vmcode_function(vm, pc, retval); + ret = njs_vmcode_function(vm, pc); if (njs_slow_path(ret < 0 && ret >= NJS_PREEMPT)) { goto error; } @@ -1422,17 +1415,6 @@ NEXT_LBL; return NJS_OK; - CASE (NJS_VMCODE_FUNCTION_COPY): - njs_vmcode_debug_opcode(); - - fcopy = (njs_vmcode_function_copy_t *) pc; - ret = njs_vmcode_function_copy(vm, fcopy->function, fcopy->retval); - if (njs_slow_path(ret == NJS_ERROR)) { - goto error; - } - - BREAK; - CASE (NJS_VMCODE_FUNCTION_FRAME): njs_vmcode_debug_opcode(); @@ -1928,7 +1910,7 @@ njs_vmcode_array(njs_vm_t *vm, u_char *pc, njs_value_t *retval) static njs_jump_off_t -njs_vmcode_function(njs_vm_t *vm, u_char *pc, njs_value_t *retval) +njs_vmcode_function(njs_vm_t *vm, u_char *pc) { njs_function_t *function; njs_vmcode_function_t *code; @@ -1948,7 +1930,7 @@ njs_vmcode_function(njs_vm_t *vm, u_char *pc, njs_value_t *retval) function->args_count = lambda->nargs - lambda->rest_parameters; - njs_set_function(retval, function); + njs_set_function(njs_scope_value(vm, code->retval), function); return sizeof(njs_vmcode_function_t); } @@ -2032,27 +2014,6 @@ njs_vmcode_template_literal(njs_vm_t *vm, njs_value_t *retval) } -static njs_jump_off_t -njs_vmcode_function_copy(njs_vm_t *vm, njs_value_t *value, njs_index_t retidx) -{ - njs_value_t *retval; - njs_function_t *function; - - retval = njs_scope_value(vm, retidx); - - if (!njs_is_valid(retval)) { - *retval = *value; - - function = njs_function_value_copy(vm, retval); - if (njs_slow_path(function == NULL)) { - return NJS_ERROR; - } - } - - return sizeof(njs_vmcode_function_copy_t); -} - - static njs_jump_off_t njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *value, njs_value_t *key, njs_value_t *init) diff --git a/src/njs_vmcode.h b/src/njs_vmcode.h index 83507f63..5170f29f 100644 --- a/src/njs_vmcode.h +++ b/src/njs_vmcode.h @@ -38,7 +38,6 @@ enum { NJS_VMCODE_IF_EQUAL_JUMP, NJS_VMCODE_PROPERTY_INIT, NJS_VMCODE_RETURN, - NJS_VMCODE_FUNCTION_COPY, NJS_VMCODE_FUNCTION_FRAME, NJS_VMCODE_METHOD_FRAME, NJS_VMCODE_FUNCTION_CALL, @@ -381,13 +380,6 @@ typedef struct { } njs_vmcode_error_t; -typedef struct { - njs_vmcode_t code; - njs_value_t *function; - njs_index_t retval; -} njs_vmcode_function_copy_t; - - typedef struct { njs_vmcode_t code; njs_index_t retval; _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel