[njs] Refactoring of user modules importing.

Dmitry Volyntsev xeioex at nginx.com
Mon Feb 21 15:06:05 UTC 2022


details:   https://hg.nginx.org/njs/rev/77c398f26d7e
branches:  
changeset: 1828:77c398f26d7e
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Mon Feb 21 14:49:38 2022 +0000
description:
Refactoring of user modules importing.

Previously, user modules were compiled as as anonymous functions in a
global scope.  This is incorrect, because modules should be compiled
in their own scope.

In addition, this patch introduces HostResolveImportedModule support.
When vm->options.ops->module_loader is provided, a module lookup
and compilation is delegated to this callback.

This closes #443 issue on Github.

diffstat:

 external/njs_crypto_module.c               |    2 +-
 external/njs_fs_module.c                   |    2 +-
 external/njs_query_string_module.c         |    2 +-
 nginx/ngx_http_js_module.c                 |   20 +-
 nginx/ngx_stream_js_module.c               |   19 +-
 src/njs.h                                  |    6 +
 src/njs_buffer.c                           |    2 +-
 src/njs_builtin.c                          |    4 +-
 src/njs_disassembler.c                     |   22 +-
 src/njs_function.c                         |    2 +-
 src/njs_generator.c                        |   87 +---
 src/njs_generator.h                        |    5 +-
 src/njs_module.c                           |  481 +++++++---------------------
 src/njs_module.h                           |   13 +-
 src/njs_parser.c                           |  238 ++++---------
 src/njs_parser.h                           |   31 +-
 src/njs_shell.c                            |   21 +-
 src/njs_variable.c                         |    2 +-
 src/njs_vm.c                               |   84 ++++-
 src/njs_vm.h                               |    1 +
 src/njs_vmcode.c                           |   68 ++++
 src/njs_vmcode.h                           |    8 +
 test/js/import_cyclic.t.js                 |   11 +
 test/js/import_expression.t.js             |    1 +
 test/js/import_global_ref.t.js             |   13 +
 test/js/import_global_ref_var.t.js         |   10 +
 test/js/import_order.t.js                  |   18 +
 test/js/import_recursive.t.js              |    6 +-
 test/js/import_recursive_early_access.t.js |    9 +
 test/js/import_recursive_relative.t.js     |    9 +
 test/js/import_sinking_export_default.t.js |   10 +
 test/js/module/cyclic_a.js                 |    2 +
 test/js/module/cyclic_b.js                 |    2 +
 test/js/module/export_global_a.js          |    5 +
 test/js/module/http.js                     |    7 +
 test/js/module/jwt.js                      |    7 +
 test/js/module/lib1.js                     |    5 +
 test/js/module/order.js                    |    7 +
 test/js/module/order2.js                   |    7 +
 test/js/module/recursive.js                |    2 +
 test/js/module/recursive_early_access.js   |    5 +
 test/js/module/recursive_relative.js       |    2 +
 test/js/module/sinking_export_default.js   |    5 +
 43 files changed, 598 insertions(+), 665 deletions(-)

diffs (truncated from 2098 to 1000 lines):

diff -r 7a08ed3e9cb8 -r 77c398f26d7e external/njs_crypto_module.c
--- a/external/njs_crypto_module.c	Tue Feb 15 13:17:52 2022 +0000
+++ b/external/njs_crypto_module.c	Mon Feb 21 14:49:38 2022 +0000
@@ -646,7 +646,7 @@ njs_crypto_init(njs_vm_t *vm)
         return NJS_ERROR;
     }
 
-    module = njs_module_add(vm, &njs_str_value("crypto"), 1);
+    module = njs_module_add(vm, &njs_str_value("crypto"));
     if (njs_slow_path(module == NULL)) {
         return NJS_ERROR;
     }
diff -r 7a08ed3e9cb8 -r 77c398f26d7e external/njs_fs_module.c
--- a/external/njs_fs_module.c	Tue Feb 15 13:17:52 2022 +0000
+++ b/external/njs_fs_module.c	Mon Feb 21 14:49:38 2022 +0000
@@ -3090,7 +3090,7 @@ njs_fs_init(njs_vm_t *vm)
         return NJS_ERROR;
     }
 
-    module = njs_module_add(vm, &njs_str_value("fs"), 1);
+    module = njs_module_add(vm, &njs_str_value("fs"));
     if (njs_slow_path(module == NULL)) {
         return NJS_ERROR;
     }
diff -r 7a08ed3e9cb8 -r 77c398f26d7e external/njs_query_string_module.c
--- a/external/njs_query_string_module.c	Tue Feb 15 13:17:52 2022 +0000
+++ b/external/njs_query_string_module.c	Mon Feb 21 14:49:38 2022 +0000
@@ -967,7 +967,7 @@ njs_query_string_init(njs_vm_t *vm)
         return NJS_ERROR;
     }
 
-    module = njs_module_add(vm, &njs_str_value("querystring"), 1);
+    module = njs_module_add(vm, &njs_str_value("querystring"));
     if (njs_slow_path(module == NULL)) {
         return NJS_ERROR;
     }
diff -r 7a08ed3e9cb8 -r 77c398f26d7e nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c	Tue Feb 15 13:17:52 2022 +0000
+++ b/nginx/ngx_http_js_module.c	Mon Feb 21 14:49:38 2022 +0000
@@ -704,7 +704,8 @@ static njs_external_t  ngx_http_js_ext_r
 
 static njs_vm_ops_t ngx_http_js_ops = {
     ngx_http_js_set_timer,
-    ngx_http_js_clear_timer
+    ngx_http_js_clear_timer,
+    NULL,
 };
 
 
@@ -3490,8 +3491,12 @@ ngx_http_js_init_main_conf(ngx_conf_t *c
 
     import = jmcf->imports->elts;
     for (i = 0; i < jmcf->imports->nelts; i++) {
-        size += sizeof("import  from '';\n") - 1 + import[i].name.len
-                + import[i].path.len;
+
+        /* import <name> from '<path>'; globalThis.<name> = <name>; */
+
+        size += sizeof("import  from '';") - 1 + import[i].name.len * 3
+                + import[i].path.len
+                + sizeof(" globalThis. = ;\n") - 1;
     }
 
     start = ngx_pnalloc(cf->pool, size);
@@ -3502,11 +3507,18 @@ ngx_http_js_init_main_conf(ngx_conf_t *c
     p = start;
     import = jmcf->imports->elts;
     for (i = 0; i < jmcf->imports->nelts; i++) {
+
+        /* import <name> from '<path>'; globalThis.<name> = <name>; */
+
         p = ngx_cpymem(p, "import ", sizeof("import ") - 1);
         p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
         p = ngx_cpymem(p, " from '", sizeof(" from '") - 1);
         p = ngx_cpymem(p, import[i].path.data, import[i].path.len);
-        p = ngx_cpymem(p, "';\n", sizeof("';\n") - 1);
+        p = ngx_cpymem(p, "'; globalThis.", sizeof("'; globalThis.") - 1);
+        p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
+        p = ngx_cpymem(p, " = ", sizeof(" = ") - 1);
+        p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
+        p = ngx_cpymem(p, ";\n", sizeof(";\n") - 1);
     }
 
     njs_vm_opt_init(&options);
diff -r 7a08ed3e9cb8 -r 77c398f26d7e nginx/ngx_stream_js_module.c
--- a/nginx/ngx_stream_js_module.c	Tue Feb 15 13:17:52 2022 +0000
+++ b/nginx/ngx_stream_js_module.c	Mon Feb 21 14:49:38 2022 +0000
@@ -456,7 +456,8 @@ static njs_external_t  ngx_stream_js_ext
 
 static njs_vm_ops_t ngx_stream_js_ops = {
     ngx_stream_js_set_timer,
-    ngx_stream_js_clear_timer
+    ngx_stream_js_clear_timer,
+    NULL,
 };
 
 
@@ -1512,8 +1513,11 @@ ngx_stream_js_init_main_conf(ngx_conf_t 
 
     import = jmcf->imports->elts;
     for (i = 0; i < jmcf->imports->nelts; i++) {
-        size += sizeof("import  from '';\n") - 1 + import[i].name.len
-                + import[i].path.len;
+        /* import <name> from '<path>'; globalThis.<name> = <name>; */
+
+        size += sizeof("import  from '';") - 1 + import[i].name.len * 3
+                + import[i].path.len
+                + sizeof(" globalThis. = ;\n") - 1;
     }
 
     start = ngx_pnalloc(cf->pool, size);
@@ -1524,11 +1528,18 @@ ngx_stream_js_init_main_conf(ngx_conf_t 
     p = start;
     import = jmcf->imports->elts;
     for (i = 0; i < jmcf->imports->nelts; i++) {
+
+        /* import <name> from '<path>'; globalThis.<name> = <name>; */
+
         p = ngx_cpymem(p, "import ", sizeof("import ") - 1);
         p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
         p = ngx_cpymem(p, " from '", sizeof(" from '") - 1);
         p = ngx_cpymem(p, import[i].path.data, import[i].path.len);
-        p = ngx_cpymem(p, "';\n", sizeof("';\n") - 1);
+        p = ngx_cpymem(p, "'; globalThis.", sizeof("'; globalThis.") - 1);
+        p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
+        p = ngx_cpymem(p, " = ", sizeof(" = ") - 1);
+        p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
+        p = ngx_cpymem(p, ";\n", sizeof(";\n") - 1);
     }
 
     njs_vm_opt_init(&options);
diff -r 7a08ed3e9cb8 -r 77c398f26d7e src/njs.h
--- a/src/njs.h	Tue Feb 15 13:17:52 2022 +0000
+++ b/src/njs.h	Mon Feb 21 14:49:38 2022 +0000
@@ -28,6 +28,7 @@
 
 typedef uintptr_t                   njs_index_t;
 typedef struct njs_vm_s             njs_vm_t;
+typedef struct njs_mod_s            njs_mod_t;
 typedef union  njs_value_s          njs_value_t;
 typedef struct njs_function_s       njs_function_t;
 typedef struct njs_vm_shared_s      njs_vm_shared_t;
@@ -183,11 +184,14 @@ typedef njs_host_event_t (*njs_set_timer
     uint64_t delay, njs_vm_event_t vm_event);
 typedef void (*njs_event_destructor_t)(njs_external_ptr_t external,
     njs_host_event_t event);
+typedef njs_mod_t *(*njs_module_loader_t)(njs_vm_t *vm,
+    njs_external_ptr_t external, njs_str_t *name);
 
 
 typedef struct {
     njs_set_timer_t                 set_timer;
     njs_event_destructor_t          clear_timer;
+    njs_module_loader_t             module_loader;
 } njs_vm_ops_t;
 
 
@@ -254,6 +258,8 @@ NJS_EXPORT njs_vm_t *njs_vm_create(njs_v
 NJS_EXPORT void njs_vm_destroy(njs_vm_t *vm);
 
 NJS_EXPORT njs_int_t njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end);
+NJS_EXPORT njs_mod_t *njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name,
+    u_char **start, u_char *end);
 NJS_EXPORT njs_vm_t *njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external);
 
 NJS_EXPORT njs_vm_event_t njs_vm_add_event(njs_vm_t *vm,
diff -r 7a08ed3e9cb8 -r 77c398f26d7e src/njs_buffer.c
--- a/src/njs_buffer.c	Tue Feb 15 13:17:52 2022 +0000
+++ b/src/njs_buffer.c	Mon Feb 21 14:49:38 2022 +0000
@@ -3015,7 +3015,7 @@ njs_buffer_init(njs_vm_t *vm)
         return NJS_ERROR;
     }
 
-    module = njs_module_add(vm, &njs_str_value("buffer"), 1);
+    module = njs_module_add(vm, &njs_str_value("buffer"));
     if (njs_slow_path(module == NULL)) {
         return NJS_ERROR;
     }
diff -r 7a08ed3e9cb8 -r 77c398f26d7e src/njs_builtin.c
--- a/src/njs_builtin.c	Tue Feb 15 13:17:52 2022 +0000
+++ b/src/njs_builtin.c	Mon Feb 21 14:49:38 2022 +0000
@@ -761,7 +761,9 @@ njs_builtin_match_native_function(njs_vm
             break;
         }
 
-        if (njs_is_object(&module->value)) {
+        if (njs_is_object(&module->value)
+            && !njs_object(&module->value)->shared)
+        {
             ctx.match = module->name;
 
             ret = njs_object_traverse(vm, njs_object(&module->value), &ctx,
diff -r 7a08ed3e9cb8 -r 77c398f26d7e src/njs_disassembler.c
--- a/src/njs_disassembler.c	Tue Feb 15 13:17:52 2022 +0000
+++ b/src/njs_disassembler.c	Mon Feb 21 14:49:38 2022 +0000
@@ -172,15 +172,6 @@ njs_disassembler(njs_vm_t *vm)
     n = vm->codes->items;
 
     while (n != 0) {
-        if (code->start == vm->start) {
-            break;
-        }
-
-        code++;
-        n--;
-    }
-
-    while (n != 0) {
         njs_printf("%V:%V\n", &code->file, &code->name);
         njs_disassemble(code);
         code++;
@@ -207,6 +198,7 @@ njs_disassemble(njs_vm_code_t *code)
     njs_vmcode_3addr_t           *code3;
     njs_vmcode_array_t           *array;
     njs_vmcode_catch_t           *catch;
+    njs_vmcode_import_t          *import;
     njs_vmcode_finally_t         *finally;
     njs_vmcode_try_end_t         *try_end;
     njs_vmcode_move_arg_t        *move_arg;
@@ -398,6 +390,18 @@ njs_disassemble(njs_vm_code_t *code)
             continue;
         }
 
+        if (operation == NJS_VMCODE_IMPORT) {
+            import = (njs_vmcode_import_t *) p;
+
+            njs_printf("%5uD | %05uz IMPORT            %04Xz %V\n",
+                       line, p - start, (size_t) import->retval,
+                       &import->module->name);
+
+            p += sizeof(njs_vmcode_import_t);
+
+            continue;
+        }
+
         if (operation == NJS_VMCODE_TRY_START) {
             try_start = (njs_vmcode_try_start_t *) p;
 
diff -r 7a08ed3e9cb8 -r 77c398f26d7e src/njs_function.c
--- a/src/njs_function.c	Tue Feb 15 13:17:52 2022 +0000
+++ b/src/njs_function.c	Mon Feb 21 14:49:38 2022 +0000
@@ -1209,7 +1209,7 @@ njs_function_constructor(njs_vm_t *vm, n
         }
     }
 
-    ret = njs_generator_init(&generator, 0, 1);
+    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;
diff -r 7a08ed3e9cb8 -r 77c398f26d7e src/njs_generator.c
--- a/src/njs_generator.c	Tue Feb 15 13:17:52 2022 +0000
+++ b/src/njs_generator.c	Mon Feb 21 14:49:38 2022 +0000
@@ -319,8 +319,6 @@ static njs_int_t njs_generate_throw_end(
     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,
@@ -424,8 +422,8 @@ static njs_int_t njs_generate_index_rele
         njs_code_offset_diff(generator, patch->jump_offset)
 
 
-#define njs_generate_syntax_error(vm, node, fmt, ...)                         \
-    njs_parser_node_error(vm, node, NJS_OBJ_TYPE_SYNTAX_ERROR, fmt,           \
+#define njs_generate_syntax_error(vm, node, file, fmt, ...)                   \
+    njs_parser_node_error(vm, NJS_OBJ_TYPE_SYNTAX_ERROR, node, file, fmt,     \
                           ##__VA_ARGS__)
 
 
@@ -436,13 +434,14 @@ static const njs_str_t  undef_label  = {
 
 
 njs_int_t
-njs_generator_init(njs_generator_t *generator, njs_int_t depth,
-    njs_bool_t runtime)
+njs_generator_init(njs_generator_t *generator, njs_str_t *file,
+    njs_int_t depth, njs_bool_t runtime)
 {
     njs_memzero(generator, sizeof(njs_generator_t));
 
     njs_queue_init(&generator->stack);
 
+    generator->file = *file;
     generator->depth = depth;
     generator->runtime = runtime;
 
@@ -2312,7 +2311,8 @@ njs_generate_continue_statement(njs_vm_t
 
 syntax_error:
 
-    njs_generate_syntax_error(vm, node, "Illegal continue statement");
+    njs_generate_syntax_error(vm, node, &generator->file,
+                              "Illegal continue statement");
 
     return NJS_ERROR;
 }
@@ -2357,7 +2357,8 @@ njs_generate_break_statement(njs_vm_t *v
 
 syntax_error:
 
-    njs_generate_syntax_error(vm, node, "Illegal break statement");
+    njs_generate_syntax_error(vm, node, &generator->file,
+                              "Illegal break statement");
 
     return NJS_ERROR;
 }
@@ -3102,17 +3103,13 @@ njs_generate_function(njs_vm_t *vm, njs_
     njs_parser_node_t *node)
 {
     njs_int_t              ret;
-    njs_bool_t             module;
-    const njs_str_t        *name;
     njs_function_lambda_t  *lambda;
     njs_vmcode_function_t  *function;
 
     lambda = node->u.value.data.u.lambda;
-    module = node->right->scope->module;
-
-    name = module ? &njs_entry_module : &njs_entry_anonymous;
-
-    ret = njs_generate_function_scope(vm, generator, lambda, node, name);
+
+    ret = njs_generate_function_scope(vm, generator, lambda, node,
+                                      &njs_entry_anonymous);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
@@ -3641,13 +3638,11 @@ njs_generate_function_scope(njs_vm_t *vm
     njs_function_lambda_t *lambda, njs_parser_node_t *node,
     const njs_str_t *name)
 {
-    njs_int_t          ret;
-    njs_arr_t          *arr;
-    njs_bool_t         module;
-    njs_uint_t         depth;
-    njs_vm_code_t      *code;
-    njs_generator_t    generator;
-    njs_parser_node_t  *file_node;
+    njs_int_t        ret;
+    njs_arr_t        *arr;
+    njs_uint_t       depth;
+    njs_vm_code_t    *code;
+    njs_generator_t  generator;
 
     depth = prev->depth;
 
@@ -3656,7 +3651,7 @@ njs_generate_function_scope(njs_vm_t *vm
         return NJS_ERROR;
     }
 
-    ret = njs_generator_init(&generator, depth, prev->runtime);
+    ret = njs_generator_init(&generator, &prev->file, depth, prev->runtime);
     if (njs_slow_path(ret != NJS_OK)) {
         njs_internal_error(vm, "njs_generator_init() failed");
         return NJS_ERROR;
@@ -3673,11 +3668,6 @@ njs_generate_function_scope(njs_vm_t *vm
         return NJS_ERROR;
     }
 
-    module = node->right->scope->module;
-    file_node = module ? node->right : node;
-
-    code->file = file_node->scope->file;
-
     lambda->start = generator.code_start;
     lambda->closures = generator.closures->start;
     lambda->nclosures = generator.closures->items;
@@ -3774,7 +3764,7 @@ njs_generate_scope(njs_vm_t *vm, njs_gen
     code = njs_arr_item(vm->codes, index);
     code->start = generator->code_start;
     code->end = generator->code_end;
-    code->file = scope->file;
+    code->file = generator->file;
     code->name = *name;
 
     generator->code_size = generator->code_end - generator->code_start;
@@ -4620,45 +4610,22 @@ static njs_int_t
 njs_generate_import_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_variable_t     *var;
-    njs_parser_node_t  *lvalue, *expr;
+    njs_variable_t       *var;
+    njs_parser_node_t    *lvalue;
+    njs_vmcode_import_t  *import;
 
     lvalue = node->left;
-    expr = node->right;
 
     var = njs_variable_reference(vm, lvalue);
     if (njs_slow_path(var == NULL)) {
         return NJS_ERROR;
     }
 
-    if (expr->left != NULL) {
-        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_mod_t                 *module;
-    njs_parser_node_t         *expr;
-    njs_vmcode_object_copy_t  *copy;
-
-    expr = node->right;
-
-    module = (njs_mod_t *) expr->index;
-
-    njs_generate_code(generator, njs_vmcode_object_copy_t, copy,
-                      NJS_VMCODE_OBJECT_COPY, 2, node);
-    copy->retval = node->left->index;
-    copy->object = module->index;
+    njs_generate_code(generator, njs_vmcode_import_t, import,
+                      NJS_VMCODE_IMPORT, 1, node);
+
+    import->module = node->u.module;
+    import->retval = lvalue->index;
 
     return njs_generator_stack_pop(vm, generator, NULL);
 }
diff -r 7a08ed3e9cb8 -r 77c398f26d7e src/njs_generator.h
--- a/src/njs_generator.h	Tue Feb 15 13:17:52 2022 +0000
+++ b/src/njs_generator.h	Mon Feb 21 14:49:38 2022 +0000
@@ -27,6 +27,7 @@ struct njs_generator_s {
     njs_arr_t                       *index_cache;
     njs_arr_t                       *closures;
 
+    njs_str_t                       file;
     njs_arr_t                       *lines;
 
     size_t                          code_size;
@@ -40,8 +41,8 @@ struct njs_generator_s {
 };
 
 
-njs_int_t njs_generator_init(njs_generator_t *generator, njs_int_t depth,
-    njs_bool_t runtime);
+njs_int_t njs_generator_init(njs_generator_t *generator, njs_str_t *file,
+    njs_int_t depth, njs_bool_t runtime);
 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);
 uint32_t njs_lookup_line(njs_vm_code_t *code, uint32_t offset);
diff -r 7a08ed3e9cb8 -r 77c398f26d7e src/njs_module.c
--- a/src/njs_module.c	Tue Feb 15 13:17:52 2022 +0000
+++ b/src/njs_module.c	Mon Feb 21 14:49:38 2022 +0000
@@ -12,286 +12,60 @@ typedef struct {
     int                 fd;
     njs_str_t           name;
     njs_str_t           file;
+    char                path[NJS_MAX_PATH + 1];
 } njs_module_info_t;
 
 
-typedef struct {
-    njs_str_t           text;
-    njs_module_info_t   info;
-    njs_lexer_t         *prev;
-    njs_lexer_t         lexer;
-} njs_module_temp_t;
-
-
-static njs_int_t njs_parser_module_lambda_after(njs_parser_t *parser,
-    njs_lexer_token_t *token, njs_queue_link_t *current);
-static njs_int_t njs_parser_module_after(njs_parser_t *parser,
-    njs_lexer_token_t *token, njs_queue_link_t *current);
-
 static njs_int_t njs_module_lookup(njs_vm_t *vm, const njs_str_t *cwd,
     njs_module_info_t *info);
-static njs_int_t njs_module_relative_path(njs_vm_t *vm,
-    const njs_str_t *dir, njs_module_info_t *info);
-static njs_int_t njs_module_absolute_path(njs_vm_t *vm,
+static njs_int_t njs_module_path(njs_vm_t *vm, const njs_str_t *dir,
     njs_module_info_t *info);
-static njs_bool_t njs_module_realpath_equal(const njs_str_t *path1,
-    const njs_str_t *path2);
 static njs_int_t njs_module_read(njs_vm_t *vm, int fd, njs_str_t *body);
-static njs_mod_t *njs_module_find(njs_vm_t *vm, njs_str_t *name,
-    njs_bool_t local);
-static njs_int_t njs_module_insert(njs_parser_t *parser, njs_mod_t *module);
-
-
-njs_int_t
-njs_module_load(njs_vm_t *vm)
-{
-    njs_int_t     ret;
-    njs_mod_t     **item, *module;
-    njs_uint_t    i;
-    njs_value_t   *value;
-    njs_object_t  *object;
-
-    if (vm->modules == NULL) {
-        return NJS_OK;
-    }
-
-    item = vm->modules->start;
-
-    for (i = 0; i < vm->modules->items; i++) {
-        module = *item;
-
-        if (module->function.native) {
-            value = njs_scope_valid_value(vm, module->index);
-            njs_value_assign(value, &module->value);
-
-            object = njs_object_value_copy(vm, value);
-            if (njs_slow_path(object == NULL)) {
-                return NJS_ERROR;
-            }
-
-        } else {
-            ret = njs_vm_invoke(vm, &module->function, NULL, 0,
-                                njs_scope_valid_value(vm, module->index));
-            if (ret == NJS_ERROR) {
-                return ret;
-            }
-        }
-
-        item++;
-    }
-
-    return NJS_OK;
-}
+static njs_mod_t *njs_default_module_loader(njs_vm_t *vm,
+    njs_external_ptr_t external, njs_str_t *name);
 
 
-void
-njs_module_reset(njs_vm_t *vm)
-{
-    njs_mod_t           **item, *module;
-    njs_uint_t          i;
-    njs_lvlhsh_query_t  lhq;
-
-    if (vm->modules == NULL) {
-        return;
-    }
-
-    item = vm->modules->start;
-
-    for (i = 0; i < vm->modules->items; i++) {
-        module = *item;
-
-        if (!module->function.native) {
-            lhq.key = module->name;
-            lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length);
-            lhq.proto = &njs_modules_hash_proto;
-            lhq.pool = vm->mem_pool;
-
-            (void) njs_lvlhsh_delete(&vm->modules_hash, &lhq);
-        }
-
-        item++;
-    }
-
-    njs_arr_reset(vm->modules);
-}
-
-
-njs_int_t
-njs_parser_module(njs_parser_t *parser, njs_lexer_token_t *token,
-    njs_queue_link_t *current)
+njs_mod_t *
+njs_parser_module(njs_parser_t *parser, njs_str_t *name)
 {
-    njs_int_t          ret;
-    njs_str_t          name, text;
-    njs_mod_t          *module;
-    njs_module_temp_t  *temp;
-    njs_module_info_t  info;
-
-    name = token->text;
-
-    parser->node = NULL;
-
-    module = njs_module_find(parser->vm, &name, 1);
-    if (module != NULL && module->function.native) {
-        njs_lexer_consume_token(parser->lexer, 1);
-
-        parser->target = (njs_parser_node_t *) module;
+    njs_mod_t            *module;
+    njs_vm_t             *vm;
+    njs_external_ptr_t   external;
+    njs_module_loader_t  loader;
 
-        return njs_parser_module_after(parser, token, current);
-    }
-
-    njs_memzero(&text, sizeof(njs_str_t));
-
-    if (parser->vm->options.sandbox || name.length == 0) {
-        njs_parser_syntax_error(parser, "Cannot find module \"%V\"", &name);
-        goto fail;
-    }
+    vm = parser->vm;
 
-    /* Non-native module. */
-
-    njs_memzero(&info, sizeof(njs_module_info_t));
-
-    info.name = name;
-
-    ret = njs_module_lookup(parser->vm, &parser->scope->cwd, &info);
-    if (njs_slow_path(ret != NJS_OK)) {
-        njs_parser_syntax_error(parser, "Cannot find module \"%V\"", &name);
-        goto fail;
+    if (name->length == 0) {
+        njs_parser_syntax_error(parser, "Cannot find module \"%V\"", name);
+        return NULL;
     }
 
-    module = njs_module_find(parser->vm, &info.file, 1);
+    module = njs_module_find(vm, name, 1);
     if (module != NULL) {
-        (void) close(info.fd);
-        njs_lexer_consume_token(parser->lexer, 1);
-
-        parser->target = (njs_parser_node_t *) module;
-
-        return njs_parser_module_after(parser, token, current);
-    }
-
-    ret = njs_module_read(parser->vm, info.fd, &text);
-
-    (void) close(info.fd);
-
-    if (njs_slow_path(ret != NJS_OK)) {
-        njs_internal_error(parser->vm, "while reading \"%V\" module",
-                           &info.file);
-        goto fail;
-    }
-
-    if (njs_module_realpath_equal(&parser->lexer->file, &info.file)) {
-        njs_parser_syntax_error(parser, "Cannot import itself \"%V\"",
-                                &info.file);
-        goto fail;
+        goto done;
     }
 
-    temp = njs_mp_alloc(parser->vm->mem_pool, sizeof(njs_module_temp_t));
-    if (njs_slow_path(temp == NULL)) {
-        return NJS_ERROR;
-    }
-
-    ret = njs_lexer_init(parser->vm, &temp->lexer, &info.file, text.start,
-                         text.start + text.length, 0);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return NJS_ERROR;
-    }
-
-    njs_lexer_consume_token(parser->lexer, 1);
+    external = parser;
+    loader = njs_default_module_loader;
 
-    temp->prev = parser->lexer;
-    temp->info = info;
-    temp->text = text;
-
-    parser->lexer = &temp->lexer;
-
-    njs_parser_next(parser, njs_parser_module_lambda);
-
-    return njs_parser_after(parser, current, temp, 0,
-                            njs_parser_module_lambda_after);
-
-fail:
-
-    if (text.start != NULL) {
-        njs_mp_free(parser->vm->mem_pool, text.start);
+    if (vm->options.ops != NULL && vm->options.ops->module_loader != NULL) {
+        loader = vm->options.ops->module_loader;
+        external = vm->external;
     }
 
-    return NJS_ERROR;
-}
-
-
-static njs_int_t
-njs_parser_module_lambda_after(njs_parser_t *parser, njs_lexer_token_t *token,
-    njs_queue_link_t *current)
-{
-    njs_mod_t          *module;
-    njs_module_temp_t  *temp;
-
-    temp = (njs_module_temp_t *) parser->target;
-
-    if (parser->ret != NJS_OK) {
-        njs_mp_free(parser->vm->mem_pool, temp->text.start);
-        njs_mp_free(parser->vm->mem_pool, temp);
-
-        if (token->type == NJS_TOKEN_END) {
-            return njs_parser_stack_pop(parser);
-        }
-
-        return njs_parser_failed(parser);
-    }
-
-    module = njs_module_add(parser->vm, &temp->info.file, 0);
-    if (njs_slow_path(module == NULL)) {
-        parser->lexer = temp->prev;
-
-        if (temp->text.start != NULL) {
-            njs_mp_free(parser->vm->mem_pool, temp->text.start);
-        }
-
-        return njs_parser_failed(parser);
+    module = loader(vm, external, name);
+    if (module == NULL) {
+        njs_parser_syntax_error(parser, "Cannot find module \"%V\"", name);
+        return NULL;
     }
 
-    module->function.args_offset = 1;
-    module->function.u.lambda = parser->node->u.value.data.u.lambda;
-
-    njs_mp_free(parser->vm->mem_pool, temp->text.start);
-
-    parser->lexer = temp->prev;
-    parser->target = (njs_parser_node_t *) module;
-
-    njs_mp_free(parser->vm->mem_pool, temp);
-
-    return njs_parser_module_after(parser, token, current);
-}
+done:
 
-
-static njs_int_t
-njs_parser_module_after(njs_parser_t *parser, njs_lexer_token_t *token,
-    njs_queue_link_t *current)
-{
-    njs_int_t          ret;
-    njs_mod_t          *module;
-    njs_parser_node_t  *node;
-
-    node = njs_parser_node_new(parser, 0);
-    if (njs_slow_path(node == NULL)) {
-       return NJS_ERROR;
+    if (module->index == 0) {
+        module->index = vm->shared->module_items++;
     }
 
-    node->left = parser->node;
-
-    module = (njs_mod_t *) parser->target;
-
-    if (module->index == 0) {
-        ret = njs_module_insert(parser, module);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return NJS_ERROR;
-        }
-    }
-
-    node->index = (njs_index_t) module;
-
-    parser->node = node;
-
-    return njs_parser_stack_pop(parser);
+    return module;
 }
 
 
@@ -303,10 +77,10 @@ njs_module_lookup(njs_vm_t *vm, const nj
     njs_uint_t  i;
 
     if (info->name.start[0] == '/') {
-        return njs_module_absolute_path(vm, info);
+        return njs_module_path(vm, NULL, info);
     }
 
-    ret = njs_module_relative_path(vm, cwd, info);
+    ret = njs_module_path(vm, cwd, info);
 
     if (ret != NJS_DECLINED) {
         return ret;
@@ -319,7 +93,7 @@ njs_module_lookup(njs_vm_t *vm, const nj
     path = vm->paths->start;
 
     for (i = 0; i < vm->paths->items; i++) {
-        ret = njs_module_relative_path(vm, path, info);
+        ret = njs_module_path(vm, path, info);
 
         if (ret != NJS_DECLINED) {
             return ret;
@@ -333,74 +107,60 @@ njs_module_lookup(njs_vm_t *vm, const nj
 
 
 static njs_int_t
-njs_module_absolute_path(njs_vm_t *vm, njs_module_info_t *info)
+njs_module_path(njs_vm_t *vm, const njs_str_t *dir, njs_module_info_t *info)
 {
-    njs_str_t  file;
+    char        *p;
+    size_t      length;
+    njs_bool_t  trail;
+    char        src[NJS_MAX_PATH + 1];
+
+    trail = 0;
+    length = info->name.length;
+
+    if (dir != NULL) {
+        length = dir->length;
 
-    file.length = info->name.length;
-    file.start = njs_mp_alloc(vm->mem_pool, file.length + 1);
-    if (njs_slow_path(file.start == NULL)) {
+        if (length == 0) {
+            return NJS_DECLINED;
+        }
+
+        trail = (dir->start[dir->length - 1] != '/');
+
+        if (trail) {
+            length++;
+        }
+    }
+
+    if (njs_slow_path(length > NJS_MAX_PATH)) {
         return NJS_ERROR;
     }
 
-    memcpy(file.start, info->name.start, file.length);
-    file.start[file.length] = '\0';
+    p = &src[0];
+
+    if (dir != NULL) {
+        p = (char *) njs_cpymem(p, dir->start, dir->length);
 
-    info->fd = open((char *) file.start, O_RDONLY);
-    if (info->fd < 0) {
-        njs_mp_free(vm->mem_pool, file.start);
+        if (trail) {
+            *p++ = '/';
+        }
+    }
+
+    p = (char *) njs_cpymem(p, info->name.start, info->name.length);
+    *p = '\0';
+
+    p = realpath(&src[0], &info->path[0]);
+    if (p == NULL) {
         return NJS_DECLINED;
     }
 
-    info->file = file;
-
-    return NJS_OK;
-}
-
-
-static njs_int_t
-njs_module_relative_path(njs_vm_t *vm, const njs_str_t *dir,
-    njs_module_info_t *info)
-{
-    u_char      *p;
-    njs_str_t   file;
-    njs_bool_t  trail;
-
-    file.length = dir->length;
-
-    if (file.length == 0) {
+    info->fd = open(&info->path[0], O_RDONLY);
+    if (info->fd < 0) {
         return NJS_DECLINED;
     }
 
-    trail = (dir->start[dir->length - 1] != '/');
 
-    if (trail) {
-        file.length++;
-    }
-
-    file.length += info->name.length;
-
-    file.start = njs_mp_alloc(vm->mem_pool, file.length + 1);
-    if (njs_slow_path(file.start == NULL)) {
-        return NJS_ERROR;
-    }
-
-    p = njs_cpymem(file.start, dir->start, dir->length);
-
-    if (trail) {
-        *p++ = '/';
-    }
-
-    p = njs_cpymem(p, info->name.start, info->name.length);
-    *p = '\0';
-
-    info->fd = open((char *) file.start, O_RDONLY);
-    if (info->fd < 0) {
-        njs_mp_free(vm->mem_pool, file.start);
-        return NJS_DECLINED;
-    }
-
-    info->file = file;
+    info->file.start = (u_char *) &info->path[0];
+    info->file.length = njs_strlen(info->file.start);
 
     return NJS_OK;
 }
@@ -412,6 +172,8 @@ njs_module_read(njs_vm_t *vm, int fd, nj
     ssize_t      n;
     struct stat  sb;
 
+    text->start = NULL;
+
     if (fstat(fd, &sb) == -1) {
         goto fail;
     }
@@ -445,18 +207,6 @@ fail:
 }
 
 
-static njs_bool_t
-njs_module_realpath_equal(const njs_str_t *path1, const njs_str_t *path2)
-{
-    char  rpath1[MAXPATHLEN], rpath2[MAXPATHLEN];
-
-    realpath((char *) path1->start, rpath1);
-    realpath((char *) path2->start, rpath2);
-
-    return (strcmp(rpath1, rpath2) == 0);
-}
-
-
 static njs_int_t
 njs_module_hash_test(njs_lvlhsh_query_t *lhq, void *data)
 {
@@ -482,7 +232,7 @@ const njs_lvlhsh_proto_t  njs_modules_ha
 };
 
 
-static njs_mod_t *
+njs_mod_t *
 njs_module_find(njs_vm_t *vm, njs_str_t *name, njs_bool_t shared)
 {
     njs_int_t           ret;
@@ -533,11 +283,10 @@ njs_module_find(njs_vm_t *vm, njs_str_t 
 
 
 njs_mod_t *
-njs_module_add(njs_vm_t *vm, njs_str_t *name, njs_bool_t shared)
+njs_module_add(njs_vm_t *vm, njs_str_t *name)
 {
     njs_int_t           ret;
     njs_mod_t           *module;
-    njs_lvlhsh_t        *hash;
     njs_lvlhsh_query_t  lhq;
 
     module = njs_mp_zalloc(vm->mem_pool, sizeof(njs_mod_t));
@@ -559,9 +308,7 @@ njs_module_add(njs_vm_t *vm, njs_str_t *
     lhq.pool = vm->mem_pool;
     lhq.proto = &njs_modules_hash_proto;
 
-    hash = shared ? &vm->shared->modules_hash : &vm->modules_hash;
-
-    ret = njs_lvlhsh_insert(hash, &lhq);
+    ret = njs_lvlhsh_insert(&vm->shared->modules_hash, &lhq);
     if (njs_fast_path(ret == NJS_OK)) {
         return module;
     }
@@ -575,38 +322,6 @@ njs_module_add(njs_vm_t *vm, njs_str_t *
 }
 
 
-static njs_int_t
-njs_module_insert(njs_parser_t *parser, njs_mod_t *module)
-{
-    njs_vm_t            *vm;
-    njs_mod_t           **value;
-    njs_parser_scope_t  *scope;
-
-    scope = njs_parser_global_scope(parser);
-    vm = parser->vm;
-
-    module->index = njs_scope_index(scope->type, scope->items, NJS_LEVEL_LOCAL,
-                                    NJS_VARIABLE_VAR);
-    scope->items++;
-
-    if (vm->modules == NULL) {
-        vm->modules = njs_arr_create(vm->mem_pool, 4, sizeof(njs_mod_t *));
-        if (njs_slow_path(vm->modules == NULL)) {
-            return NJS_ERROR;
-        }
-    }
-
-    value = njs_arr_add(vm->modules);



More information about the nginx-devel mailing list