From: Dmitry Volyntsev Date: Thu, 3 Sep 2026 15:53:03 +0000 (-0700) Subject: Parser: release temporary compilation memory X-Git-Tag: 1.0.2~64 X-Git-Url: https://git.kaiwu.me/%7B@url%7D?a=commitdiff_plain;h=1186361b4b8f638323067a7aa9932bf4c52e2e53;p=njs.git Parser: release temporary compilation memory Create a pool for each parser invocation and allocate parser nodes, array-item storage, continuations, preread tokens, and active labels from it. Destroy the pool after generation and on parser or generator failures. Keep atoms, lambdas, regexp patterns, scopes, variables, bytecode, and runtime constants in the VM pool. Clear persistent scope AST roots before releasing the temporary pool. --- diff --git a/src/njs_function.c b/src/njs_function.c index b6a8a467..fafbd1aa 100644 --- a/src/njs_function.c +++ b/src/njs_function.c @@ -989,6 +989,11 @@ njs_function_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_function_lambda_t *lambda; const njs_token_type_t *type; + njs_memzero(&chain, sizeof(njs_chb_t)); + str.length = 0; + str.start = NULL; + parser.mem_pool = NULL; + static const njs_token_type_t safe_ast[] = { NJS_TOKEN_END, NJS_TOKEN_FUNCTION_EXPRESSION, @@ -1023,7 +1028,7 @@ njs_function_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, for (i = 1; i < nargs - 1; i++) { ret = njs_value_to_chain(vm, &chain, njs_argument(args, i)); if (njs_slow_path(ret < NJS_OK)) { - return ret; + goto done; } if (i != (nargs - 2)) { @@ -1036,7 +1041,7 @@ njs_function_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, if (nargs > 1) { ret = njs_value_to_chain(vm, &chain, njs_argument(args, nargs - 1)); if (njs_slow_path(ret < NJS_OK)) { - return ret; + goto done; } } @@ -1045,7 +1050,8 @@ njs_function_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, ret = njs_chb_join(&chain, &str); if (njs_slow_path(ret != NJS_OK)) { njs_memory_error(vm); - return NJS_ERROR; + ret = NJS_ERROR; + goto done; } file = njs_str_value("runtime"); @@ -1053,12 +1059,12 @@ njs_function_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, ret = njs_parser_init(vm, &parser, NULL, &file, str.start, str.start + str.length); if (njs_slow_path(ret != NJS_OK)) { - return ret; + goto done; } ret = njs_parser(vm, &parser); if (njs_slow_path(ret != NJS_OK)) { - return ret; + goto done; } if (!vm->options.unsafe) { @@ -1092,7 +1098,8 @@ njs_function_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, ret = njs_generator_init(&generator, &file, 0, 1); if (njs_slow_path(ret != NJS_OK)) { njs_internal_error(vm, "njs_generator_init() failed"); - return NJS_ERROR; + ret = NJS_ERROR; + goto done; } code = njs_generate_scope(vm, &generator, parser.scope, @@ -1102,24 +1109,25 @@ njs_function_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_internal_error(vm, "njs_generate_scope() failed"); } - return NJS_ERROR; + ret = NJS_ERROR; + goto done; } - njs_chb_destroy(&chain); - if ((code->end - code->start) != (sizeof(njs_vmcode_function_t) + sizeof(njs_vmcode_return_t)) || ((njs_vmcode_generic_t *) code->start)->code != NJS_VMCODE_FUNCTION) { njs_syntax_error(vm, "single function literal required"); - return NJS_ERROR; + ret = NJS_ERROR; + goto done; } lambda = ((njs_vmcode_function_t *) code->start)->lambda; function = njs_function_alloc(vm, lambda, (njs_bool_t) async); if (njs_slow_path(function == NULL)) { - return NJS_ERROR; + ret = NJS_ERROR; + goto done; } function->global = 1; @@ -1130,17 +1138,32 @@ njs_function_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, ret = njs_function_name_set(vm, function, &name, NULL); if (njs_slow_path(ret == NJS_ERROR)) { - return ret; + goto done; } njs_set_function(retval, function); - return NJS_OK; + ret = NJS_OK; + goto done; fail: njs_type_error(vm, "function constructor is disabled in \"safe\" mode"); - return NJS_ERROR; + ret = NJS_ERROR; + +done: + + if (parser.mem_pool != NULL) { + njs_parser_destroy(&parser); + } + + njs_chb_destroy(&chain); + + if (str.start != NULL) { + njs_mp_free(vm->mem_pool, str.start); + } + + return ret; } diff --git a/src/njs_generator.c b/src/njs_generator.c index 09cc657d..6d034d84 100644 --- a/src/njs_generator.c +++ b/src/njs_generator.c @@ -5044,6 +5044,7 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator, code->name = *name; generator->code_size = generator->code_end - generator->code_start; + scope->top = NULL; return code; } diff --git a/src/njs_lexer.c b/src/njs_lexer.c index b0448a51..db49197d 100644 --- a/src/njs_lexer.c +++ b/src/njs_lexer.c @@ -293,14 +293,15 @@ static const njs_lexer_multi_t njs_assignment_token[] = { njs_int_t -njs_lexer_init(njs_vm_t *vm, njs_lexer_t *lexer, njs_str_t *file, - u_char *start, u_char *end) +njs_lexer_init(njs_vm_t *vm, njs_mp_t *mem_pool, njs_lexer_t *lexer, + njs_str_t *file, u_char *start, u_char *end) { lexer->file = *file; lexer->start = start; lexer->end = end; lexer->line = 1; lexer->vm = vm; + lexer->mem_pool = mem_pool; njs_queue_init(&lexer->preread); @@ -314,7 +315,7 @@ njs_lexer_next_token(njs_lexer_t *lexer) njs_int_t ret; njs_lexer_token_t *token; - token = njs_mp_zalloc(lexer->vm->mem_pool, sizeof(njs_lexer_token_t)); + token = njs_mp_zalloc(lexer->mem_pool, sizeof(njs_lexer_token_t)); if (njs_slow_path(token == NULL)) { return NULL; } @@ -429,7 +430,7 @@ njs_lexer_consume_token(njs_lexer_t *lexer, unsigned length) njs_queue_remove(lnk); - njs_mp_free(lexer->vm->mem_pool, token); + njs_mp_free(lexer->mem_pool, token); } } diff --git a/src/njs_lexer.h b/src/njs_lexer.h index a0b37b4b..c816e570 100644 --- a/src/njs_lexer.h +++ b/src/njs_lexer.h @@ -263,14 +263,15 @@ typedef struct { njs_str_t file; njs_vm_t *vm; + njs_mp_t *mem_pool; u_char *start; u_char *end; } njs_lexer_t; -njs_int_t njs_lexer_init(njs_vm_t *vm, njs_lexer_t *lexer, njs_str_t *file, - u_char *start, u_char *end); +njs_int_t njs_lexer_init(njs_vm_t *vm, njs_mp_t *mem_pool, + njs_lexer_t *lexer, njs_str_t *file, u_char *start, u_char *end); njs_lexer_token_t *njs_lexer_token(njs_lexer_t *lexer, njs_bool_t with_end_line); diff --git a/src/njs_parser.c b/src/njs_parser.c index efc1d290..02c38f0d 100644 --- a/src/njs_parser.c +++ b/src/njs_parser.c @@ -542,18 +542,47 @@ njs_int_t njs_parser_init(njs_vm_t *vm, njs_parser_t *parser, njs_parser_scope_t *scope, njs_str_t *file, u_char *start, u_char *end) { + njs_int_t ret; njs_lexer_t *lexer; njs_memzero(parser, sizeof(njs_parser_t)); parser->scope = scope; + parser->mem_pool = njs_mp_fast_create(2 * njs_pagesize(), 128, 512, 16); + if (njs_slow_path(parser->mem_pool == NULL)) { + njs_memory_error(vm); + return NJS_ERROR; + } + lexer = &parser->lexer0; parser->lexer = lexer; njs_rbtree_init(&parser->labels, njs_parser_scope_rbtree_compare); - return njs_lexer_init(vm, lexer, file, start, end); + ret = njs_lexer_init(vm, parser->mem_pool, lexer, file, start, end); + if (njs_slow_path(ret != NJS_OK)) { + njs_mp_destroy(parser->mem_pool); + parser->mem_pool = NULL; + } + + return ret; +} + + +void +njs_parser_destroy(njs_parser_t *parser) +{ + njs_parser_scope_t *scope; + + for (scope = parser->scope; scope != NULL; scope = scope->parent) { + scope->top = NULL; + } + + if (parser->mem_pool != NULL) { + njs_mp_destroy(parser->mem_pool); + parser->mem_pool = NULL; + } } @@ -8387,7 +8416,7 @@ njs_parser_array_item(njs_parser_t *parser, njs_parser_node_t *array, items = array->u.array.items; if (items == NULL) { - items = njs_arr_create(parser->vm->mem_pool, 4, + items = njs_arr_create(parser->mem_pool, 4, sizeof(njs_parser_array_item_t)); if (njs_slow_path(items == NULL)) { return NJS_ERROR; diff --git a/src/njs_parser.h b/src/njs_parser.h index 3498d48e..e5bb3c82 100644 --- a/src/njs_parser.h +++ b/src/njs_parser.h @@ -90,6 +90,7 @@ struct njs_parser_s { njs_lexer_t lexer0; njs_lexer_t *lexer; njs_vm_t *vm; + njs_mp_t *mem_pool; njs_parser_node_t *node; njs_parser_node_t *target; njs_parser_scope_t *scope; @@ -144,6 +145,7 @@ intptr_t njs_parser_scope_rbtree_compare(njs_rbtree_node_t *node1, njs_rbtree_node_t *node2); njs_int_t njs_parser_init(njs_vm_t *vm, njs_parser_t *parser, njs_parser_scope_t *scope, njs_str_t *file, u_char *start, u_char *end); +void njs_parser_destroy(njs_parser_t *parser); njs_int_t njs_parser(njs_vm_t *vm, njs_parser_t *parser); njs_bool_t njs_variable_closure_test(njs_parser_scope_t *root, @@ -205,7 +207,7 @@ njs_parser_node_new(njs_parser_t *parser, njs_token_type_t type) { njs_parser_node_t *node; - node = njs_mp_zalloc(parser->vm->mem_pool, sizeof(njs_parser_node_t)); + node = njs_mp_zalloc(parser->mem_pool, sizeof(njs_parser_node_t)); if (njs_fast_path(node != NULL)) { node->token_type = type; @@ -219,7 +221,7 @@ njs_parser_node_new(njs_parser_t *parser, njs_token_type_t type) njs_inline void njs_parser_node_free(njs_parser_t *parser, njs_parser_node_t *node) { - njs_mp_free(parser->vm->mem_pool, node); + njs_mp_free(parser->mem_pool, node); } @@ -332,7 +334,7 @@ njs_parser_stack_pop(njs_parser_t *parser) parser->allow_in = entry->allow_in; parser->var_type = entry->var_type; - njs_mp_free(parser->vm->mem_pool, entry); + njs_mp_free(parser->mem_pool, entry); return NJS_OK; } @@ -367,8 +369,7 @@ _njs_parser_after(njs_parser_t *parser, njs_queue_link_t *link, void *node, { njs_parser_stack_entry_t *entry; - entry = njs_mp_alloc(parser->vm->mem_pool, - sizeof(njs_parser_stack_entry_t)); + entry = njs_mp_alloc(parser->mem_pool, sizeof(njs_parser_stack_entry_t)); if (njs_slow_path(entry == NULL)) { return NJS_ERROR; } diff --git a/src/njs_variable.c b/src/njs_variable.c index 47ee5009..176438fb 100644 --- a/src/njs_variable.c +++ b/src/njs_variable.c @@ -306,7 +306,7 @@ njs_label_add(njs_parser_t *parser, uintptr_t atom_id) { njs_parser_label_t *label; - label = njs_mp_alloc(parser->vm->mem_pool, sizeof(njs_parser_label_t)); + label = njs_mp_alloc(parser->mem_pool, sizeof(njs_parser_label_t)); if (njs_slow_path(label == NULL)) { njs_memory_error(parser->vm); return NJS_ERROR; @@ -335,7 +335,7 @@ njs_label_remove(njs_parser_t *parser, uintptr_t atom_id) } njs_rbtree_delete(&parser->labels, (njs_rbtree_part_t *) node); - njs_mp_free(parser->vm->mem_pool, node); + njs_mp_free(parser->mem_pool, node); return NJS_OK; } diff --git a/src/njs_vm.c b/src/njs_vm.c index ba2fca55..4ddc2fd0 100644 --- a/src/njs_vm.c +++ b/src/njs_vm.c @@ -233,6 +233,7 @@ njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end) ret = njs_parser(vm, &parser); if (njs_slow_path(ret != NJS_OK)) { + njs_parser_destroy(&parser); return NJS_ERROR; } @@ -240,10 +241,12 @@ njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end) NJS_CHB_MP_INIT(&chain, njs_vm_memory_pool(vm)); ret = njs_parser_serialize_ast(parser.node, &chain); if (njs_slow_path(ret == NJS_ERROR)) { + njs_parser_destroy(&parser); return ret; } if (njs_slow_path(njs_chb_join(&chain, &ast) != NJS_OK)) { + njs_parser_destroy(&parser); return NJS_ERROR; } @@ -259,6 +262,7 @@ njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end) ret = njs_generator_init(&generator, &vm->options.file, 0, 0); if (njs_slow_path(ret != NJS_OK)) { njs_internal_error(vm, "njs_generator_init() failed"); + njs_parser_destroy(&parser); return NJS_ERROR; } @@ -268,9 +272,12 @@ njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end) njs_internal_error(vm, "njs_generate_scope() failed"); } + njs_parser_destroy(&parser); return NJS_ERROR; } + njs_parser_destroy(&parser); + if (scope->items > global_items) { global = vm->levels[NJS_LEVEL_GLOBAL]; @@ -342,6 +349,7 @@ njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start, ret = njs_parser(vm, &parser); if (njs_slow_path(ret != NJS_OK)) { + njs_parser_destroy(&parser); return NULL; } @@ -350,6 +358,7 @@ njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start, ret = njs_generator_init(&generator, &module->name, 0, 0); if (njs_slow_path(ret != NJS_OK)) { njs_internal_error(vm, "njs_generator_init() failed"); + njs_parser_destroy(&parser); return NULL; } @@ -357,12 +366,14 @@ njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start, if (njs_slow_path(code == NULL)) { njs_internal_error(vm, "njs_generate_scope() failed"); + njs_parser_destroy(&parser); return NULL; } lambda = njs_mp_zalloc(vm->mem_pool, sizeof(njs_function_lambda_t)); if (njs_fast_path(lambda == NULL)) { njs_memory_error(vm); + njs_parser_destroy(&parser); return NULL; } @@ -373,6 +384,8 @@ njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start, module->function.u.lambda = lambda; + njs_parser_destroy(&parser); + return module; }