[njs] Moving child function declaration instantiation to bytecode.
noreply at nginx.com
noreply at nginx.com
Tue Jun 17 00:37:02 UTC 2025
details: https://github.com/nginx/njs/commit/60e28d7bde0f83adf825976fbabf9f73ccae698c
branches: master
commit: 60e28d7bde0f83adf825976fbabf9f73ccae698c
user: Dmitry Volyntsev <xeioex at 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;
More information about the nginx-devel
mailing list