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

Reply via email to