[njs] Added njs_vm_external_constructor().

Dmitry Volyntsev xeioex at nginx.com
Mon Jul 3 20:34:11 UTC 2023


details:   https://hg.nginx.org/njs/rev/167f75576f49
branches:  
changeset: 2175:167f75576f49
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Mon Jul 03 12:49:00 2023 -0700
description:
Added njs_vm_external_constructor().

The new API allows to add new constructor/prototype pairs.

diffstat:

 external/njs_crypto_module.c       |    1 +
 external/njs_fs_module.c           |    1 +
 external/njs_query_string_module.c |    1 +
 external/njs_shell.c               |    1 +
 external/njs_webcrypto_module.c    |    1 +
 external/njs_xml_module.c          |    1 +
 external/njs_zlib_module.c         |    1 +
 nginx/ngx_http_js_module.c         |    1 +
 nginx/ngx_js.c                     |    1 +
 nginx/ngx_js_fetch.c               |    1 +
 nginx/ngx_stream_js_module.c       |    1 +
 src/njs.h                          |   18 ++-
 src/njs_array.c                    |    2 +-
 src/njs_array_buffer.c             |    2 +-
 src/njs_async.c                    |    2 +-
 src/njs_buffer.c                   |   13 +-
 src/njs_builtin.c                  |  127 ++++----------------
 src/njs_date.c                     |    2 +-
 src/njs_error.c                    |   16 +-
 src/njs_extern.c                   |   71 +++++++++++
 src/njs_function.c                 |   10 +-
 src/njs_json.c                     |    2 +-
 src/njs_object.c                   |   16 +-
 src/njs_parser.c                   |    6 +-
 src/njs_promise.c                  |   12 +-
 src/njs_regexp.c                   |    8 +-
 src/njs_typed_array.c              |    6 +-
 src/njs_value.c                    |    2 +-
 src/njs_value.h                    |    5 +-
 src/njs_vm.c                       |  224 ++++++++++++++++++++++++++++++++++--
 src/njs_vm.h                       |   34 ++--
 src/njs_vmcode.c                   |    2 +-
 src/test/njs_externals_test.c      |  113 ++++++++++++++++++-
 src/test/njs_unit_test.c           |   44 +++++++-
 34 files changed, 561 insertions(+), 187 deletions(-)

diffs (truncated from 1548 to 1000 lines):

diff -r 3386684745b7 -r 167f75576f49 external/njs_crypto_module.c
--- a/external/njs_crypto_module.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/external/njs_crypto_module.c	Mon Jul 03 12:49:00 2023 -0700
@@ -287,6 +287,7 @@ static njs_int_t    njs_crypto_hmac_prot
 
 njs_module_t  njs_crypto_module = {
     .name = njs_str("crypto"),
+    .preinit = NULL,
     .init = njs_crypto_init,
 };
 
diff -r 3386684745b7 -r 167f75576f49 external/njs_fs_module.c
--- a/external/njs_fs_module.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/external/njs_fs_module.c	Mon Jul 03 12:49:00 2023 -0700
@@ -1407,6 +1407,7 @@ static njs_int_t    njs_fs_bytes_written
 
 njs_module_t  njs_fs_module = {
     .name = njs_str("fs"),
+    .preinit = NULL,
     .init = njs_fs_init,
 };
 
diff -r 3386684745b7 -r 167f75576f49 external/njs_query_string_module.c
--- a/external/njs_query_string_module.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/external/njs_query_string_module.c	Mon Jul 03 12:49:00 2023 -0700
@@ -105,6 +105,7 @@ static njs_external_t  njs_ext_query_str
 
 njs_module_t  njs_query_string_module = {
     .name = njs_str("querystring"),
+    .preinit = NULL,
     .init = njs_query_string_init,
 };
 
diff -r 3386684745b7 -r 167f75576f49 external/njs_shell.c
--- a/external/njs_shell.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/external/njs_shell.c	Mon Jul 03 12:49:00 2023 -0700
@@ -254,6 +254,7 @@ static njs_vm_ops_t njs_console_ops = {
 
 njs_module_t  njs_console_module = {
     .name = njs_str("console"),
+    .preinit = NULL,
     .init = njs_externals_init,
 };
 
diff -r 3386684745b7 -r 167f75576f49 external/njs_webcrypto_module.c
--- a/external/njs_webcrypto_module.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/external/njs_webcrypto_module.c	Mon Jul 03 12:49:00 2023 -0700
@@ -659,6 +659,7 @@ static njs_external_t  njs_ext_webcrypto
 
 njs_module_t  njs_webcrypto_module = {
     .name = njs_str("webcrypto"),
+    .preinit = NULL,
     .init = njs_webcrypto_init,
 };
 
diff -r 3386684745b7 -r 167f75576f49 external/njs_xml_module.c
--- a/external/njs_xml_module.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/external/njs_xml_module.c	Mon Jul 03 12:49:00 2023 -0700
@@ -402,6 +402,7 @@ static njs_external_t  njs_ext_xml_attr[
 
 njs_module_t  njs_xml_module = {
     .name = njs_str("xml"),
+    .preinit = NULL,
     .init = njs_xml_init,
 };
 
diff -r 3386684745b7 -r 167f75576f49 external/njs_zlib_module.c
--- a/external/njs_zlib_module.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/external/njs_zlib_module.c	Mon Jul 03 12:49:00 2023 -0700
@@ -176,6 +176,7 @@ static njs_external_t  njs_ext_zlib[] = 
 
 njs_module_t  njs_zlib_module = {
     .name = njs_str("zlib"),
+    .preinit = NULL,
     .init = njs_zlib_init,
 };
 
diff -r 3386684745b7 -r 167f75576f49 nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/nginx/ngx_http_js_module.c	Mon Jul 03 12:49:00 2023 -0700
@@ -786,6 +786,7 @@ static njs_vm_meta_t ngx_http_js_metas =
 
 njs_module_t  ngx_js_http_module = {
     .name = njs_str("http"),
+    .preinit = NULL,
     .init = ngx_js_http_init,
 };
 
diff -r 3386684745b7 -r 167f75576f49 nginx/ngx_js.c
--- a/nginx/ngx_js.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/nginx/ngx_js.c	Mon Jul 03 12:49:00 2023 -0700
@@ -165,6 +165,7 @@ static njs_external_t  ngx_js_ext_core[]
 
 njs_module_t  ngx_js_ngx_module = {
     .name = njs_str("ngx"),
+    .preinit = NULL,
     .init = ngx_js_core_init,
 };
 
diff -r 3386684745b7 -r 167f75576f49 nginx/ngx_js_fetch.c
--- a/nginx/ngx_js_fetch.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/nginx/ngx_js_fetch.c	Mon Jul 03 12:49:00 2023 -0700
@@ -656,6 +656,7 @@ static njs_int_t    ngx_http_js_fetch_he
 
 njs_module_t  ngx_js_fetch_module = {
     .name = njs_str("fetch"),
+    .preinit = NULL,
     .init = ngx_js_fetch_init,
 };
 
diff -r 3386684745b7 -r 167f75576f49 nginx/ngx_stream_js_module.c
--- a/nginx/ngx_stream_js_module.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/nginx/ngx_stream_js_module.c	Mon Jul 03 12:49:00 2023 -0700
@@ -568,6 +568,7 @@ static njs_int_t    ngx_stream_js_sessio
 
 njs_module_t  ngx_js_stream_module = {
     .name = njs_str("stream"),
+    .preinit = NULL,
     .init = ngx_js_stream_init,
 };
 
diff -r 3386684745b7 -r 167f75576f49 src/njs.h
--- a/src/njs.h	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs.h	Mon Jul 03 12:49:00 2023 -0700
@@ -257,6 +257,7 @@ typedef njs_int_t (*njs_addon_init_pt)(n
 
 typedef struct {
     njs_str_t                       name;
+    njs_addon_init_pt               preinit;
     njs_addon_init_pt               init;
 } njs_module_t;
 
@@ -403,6 +404,10 @@ NJS_EXPORT njs_int_t njs_vm_add_path(njs
 
 NJS_EXPORT njs_int_t njs_vm_external_prototype(njs_vm_t *vm,
     const njs_external_t *definition, njs_uint_t n);
+NJS_EXPORT njs_int_t njs_vm_external_constructor(njs_vm_t *vm,
+    const njs_str_t *name, njs_function_native_t native,
+    const njs_external_t *ctor_props, njs_uint_t ctor_nprops,
+    const njs_external_t *proto_props, njs_uint_t proto_nprops);
 NJS_EXPORT njs_int_t njs_vm_external_create(njs_vm_t *vm, njs_value_t *value,
     njs_int_t proto_id, njs_external_ptr_t external, njs_bool_t shared);
 NJS_EXPORT njs_external_ptr_t njs_vm_external(njs_vm_t *vm,
@@ -417,6 +422,15 @@ NJS_EXPORT njs_int_t njs_value_property_
 NJS_EXPORT uintptr_t njs_vm_meta(njs_vm_t *vm, njs_uint_t index);
 NJS_EXPORT njs_vm_opt_t *njs_vm_options(njs_vm_t *vm);
 
+NJS_EXPORT njs_int_t njs_error_constructor(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t type, njs_value_t *retval);
+NJS_EXPORT njs_int_t njs_object_prototype_create_constructor(njs_vm_t *vm,
+    njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+    njs_value_t *retval);
+NJS_EXPORT njs_int_t njs_object_prototype_create(njs_vm_t *vm,
+    njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+    njs_value_t *retval);
+
 NJS_EXPORT njs_function_t *njs_vm_function_alloc(njs_vm_t *vm,
     njs_function_native_t native, njs_bool_t shared, njs_bool_t ctor);
 
@@ -433,7 +447,9 @@ NJS_EXPORT njs_function_t *njs_vm_functi
 NJS_EXPORT njs_bool_t njs_vm_constructor(njs_vm_t *vm);
 
 NJS_EXPORT void njs_vm_throw(njs_vm_t *vm, const njs_value_t *value);
-NJS_EXPORT void njs_vm_error2(njs_vm_t *vm, unsigned type, const char *fmt,
+NJS_EXPORT void njs_vm_error2(njs_vm_t *vm, unsigned error_type,
+    const char *fmt, ...);
+NJS_EXPORT void njs_vm_error3(njs_vm_t *vm, unsigned type, const char *fmt,
     ...);
 NJS_EXPORT void njs_vm_exception_get(njs_vm_t *vm, njs_value_t *retval);
 NJS_EXPORT njs_mp_t *njs_vm_memory_pool(njs_vm_t *vm);
diff -r 3386684745b7 -r 167f75576f49 src/njs_array.c
--- a/src/njs_array.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_array.c	Mon Jul 03 12:49:00 2023 -0700
@@ -83,7 +83,7 @@ njs_array_alloc(njs_vm_t *vm, njs_bool_t
     array->start = array->data;
     njs_lvlhsh_init(&array->object.hash);
     array->object.shared_hash = vm->shared->array_instance_hash;
-    array->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_ARRAY].object;
+    array->object.__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_ARRAY);
     array->object.slots = NULL;
     array->object.type = NJS_ARRAY;
     array->object.shared = 0;
diff -r 3386684745b7 -r 167f75576f49 src/njs_array_buffer.c
--- a/src/njs_array_buffer.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_array_buffer.c	Mon Jul 03 12:49:00 2023 -0700
@@ -33,7 +33,7 @@ njs_array_buffer_alloc(njs_vm_t *vm, uin
         goto memory_error;
     }
 
-    proto = &vm->prototypes[NJS_OBJ_TYPE_ARRAY_BUFFER].object;
+    proto = njs_vm_proto(vm, NJS_OBJ_TYPE_ARRAY_BUFFER);
 
     njs_lvlhsh_init(&array->object.hash);
     njs_lvlhsh_init(&array->object.shared_hash);
diff -r 3386684745b7 -r 167f75576f49 src/njs_async.c
--- a/src/njs_async.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_async.c	Mon Jul 03 12:49:00 2023 -0700
@@ -18,7 +18,7 @@ njs_async_function_frame_invoke(njs_vm_t
     njs_value_t               ctor;
     njs_promise_capability_t  *capability;
 
-    njs_set_function(&ctor, &vm->constructors[NJS_OBJ_TYPE_PROMISE]);
+    njs_set_function(&ctor, &njs_vm_ctor(vm, NJS_OBJ_TYPE_PROMISE));
 
     capability = njs_promise_new_capability(vm, &ctor);
     if (njs_slow_path(capability == NULL)) {
diff -r 3386684745b7 -r 167f75576f49 src/njs_buffer.c
--- a/src/njs_buffer.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_buffer.c	Mon Jul 03 12:49:00 2023 -0700
@@ -126,6 +126,7 @@ static njs_external_t  njs_ext_buffer[] 
 
 njs_module_t  njs_buffer_module = {
     .name = njs_str("buffer"),
+    .preinit = NULL,
     .init = njs_buffer_init,
 };
 
@@ -147,7 +148,7 @@ njs_buffer_set(njs_vm_t *vm, njs_value_t
 
     buffer = (njs_array_buffer_t *) &array[1];
 
-    proto = &vm->prototypes[NJS_OBJ_TYPE_ARRAY_BUFFER].object;
+    proto = njs_vm_proto(vm, NJS_OBJ_TYPE_ARRAY_BUFFER);
 
     njs_lvlhsh_init(&buffer->object.hash);
     njs_lvlhsh_init(&buffer->object.shared_hash);
@@ -161,7 +162,7 @@ njs_buffer_set(njs_vm_t *vm, njs_value_t
     buffer->u.data = (void *) start;
     buffer->size = size;
 
-    proto = &vm->prototypes[NJS_OBJ_TYPE_BUFFER].object;
+    proto = njs_vm_proto(vm, NJS_OBJ_TYPE_BUFFER);
 
     array->type = NJS_OBJ_TYPE_UINT8_ARRAY;
     njs_lvlhsh_init(&array->object.hash);
@@ -197,7 +198,7 @@ njs_buffer_alloc(njs_vm_t *vm, size_t si
         return NULL;
     }
 
-    array->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_BUFFER].object;
+    array->object.__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_BUFFER);
 
     return array;
 }
@@ -462,7 +463,7 @@ njs_buffer_from_array_buffer(njs_vm_t *v
         return NJS_ERROR;
     }
 
-    buffer->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_BUFFER].object;
+    buffer->object.__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_BUFFER);
 
     buffer->offset = off;
     buffer->byte_length = len;
@@ -943,7 +944,7 @@ njs_buffer_is_buffer(njs_vm_t *vm, njs_v
     array = njs_buffer_slot_internal(vm, njs_arg(args, nargs, 1));
 
     if (njs_fast_path(array != NULL && array->object.__proto__
-                      == &vm->prototypes[NJS_OBJ_TYPE_BUFFER].object))
+                      == njs_vm_proto(vm, NJS_OBJ_TYPE_BUFFER)))
     {
         is = 1;
     }
@@ -2184,7 +2185,7 @@ njs_buffer_prototype_slice(njs_vm_t *vm,
     }
 
     array = njs_typed_array(retval);
-    array->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_BUFFER].object;
+    array->object.__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_BUFFER);
 
     return NJS_OK;
 }
diff -r 3386684745b7 -r 167f75576f49 src/njs_builtin.c
--- a/src/njs_builtin.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_builtin.c	Mon Jul 03 12:49:00 2023 -0700
@@ -115,7 +115,7 @@ njs_object_hash_init(njs_vm_t *vm, njs_l
 njs_int_t
 njs_builtin_objects_create(njs_vm_t *vm)
 {
-    njs_int_t                  ret;
+    njs_int_t                  ret, index;
     njs_uint_t                 i;
     njs_object_t               *object, *string_object;
     njs_function_t             *constructor;
@@ -129,6 +129,8 @@ njs_builtin_objects_create(njs_vm_t *vm)
         return NJS_ERROR;
     }
 
+    vm->shared = shared;
+
     njs_lvlhsh_init(&shared->keywords_hash);
     njs_lvlhsh_init(&shared->values_hash);
 
@@ -204,34 +206,42 @@ njs_builtin_objects_create(njs_vm_t *vm)
         return NJS_ERROR;
     }
 
-    prototype = shared->prototypes;
+    for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_MAX; i++) {
+        index = njs_vm_ctor_push(vm);
+        if (njs_slow_path(index < 0)) {
+            return NJS_ERROR;
+        }
 
-    for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_MAX; i++) {
-        prototype[i] = njs_object_type_init[i]->prototype_value;
+        njs_assert_msg((njs_uint_t) index == i,
+                       "ctor index should match object type");
 
-        ret = njs_object_hash_init(vm, &prototype[i].object.shared_hash,
+        prototype = njs_shared_prototype(shared, i);
+        *prototype = njs_object_type_init[i]->prototype_value;
+
+        ret = njs_object_hash_init(vm, &prototype->object.shared_hash,
                                    njs_object_type_init[i]->prototype_props);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
 
-        prototype[i].object.extensible = 1;
+        prototype->object.extensible = 1;
     }
 
-    shared->prototypes[NJS_OBJ_TYPE_REGEXP].regexp.pattern =
-                                              shared->empty_regexp_pattern;
-
-    constructor = shared->constructors;
+    prototype = njs_shared_prototype(shared, NJS_OBJ_TYPE_REGEXP);
+    prototype->regexp.pattern = shared->empty_regexp_pattern;
 
     for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_MAX; i++) {
+        constructor = njs_shared_ctor(shared, i);
+
         if (njs_object_type_init[i]->constructor_props == NULL) {
+            njs_memzero(constructor, sizeof(njs_function_t));
             continue;
         }
 
-        constructor[i] = njs_object_type_init[i]->constructor;
-        constructor[i].object.shared = 0;
+        *constructor = njs_object_type_init[i]->constructor;
+        constructor->object.shared = 0;
 
-        ret = njs_object_hash_init(vm, &constructor[i].object.shared_hash,
+        ret = njs_object_hash_init(vm, &constructor->object.shared_hash,
                                    njs_object_type_init[i]->constructor_props);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
@@ -259,91 +269,6 @@ njs_builtin_objects_create(njs_vm_t *vm)
 
     njs_lvlhsh_init(&shared->modules_hash);
 
-    vm->shared = shared;
-
-    return NJS_OK;
-}
-
-
-njs_int_t
-njs_builtin_objects_clone(njs_vm_t *vm, njs_value_t *global)
-{
-    size_t        size;
-    njs_uint_t    i;
-    njs_object_t  *object_prototype, *function_prototype,
-                  *typed_array_prototype, *error_prototype, *async_prototype,
-                  *typed_array_ctor, *error_ctor;
-
-    /*
-     * Copy both prototypes and constructors arrays by one memcpy()
-     * because they are stored together.
-     */
-    size = (sizeof(njs_object_prototype_t) + sizeof(njs_function_t))
-           * NJS_OBJ_TYPE_MAX;
-
-    memcpy(vm->prototypes, vm->shared->prototypes, size);
-
-    object_prototype = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object;
-
-    for (i = NJS_OBJ_TYPE_ARRAY; i < NJS_OBJ_TYPE_NORMAL_MAX; i++) {
-        vm->prototypes[i].object.__proto__ = object_prototype;
-    }
-
-    typed_array_prototype = &vm->prototypes[NJS_OBJ_TYPE_TYPED_ARRAY].object;
-
-    for (i = NJS_OBJ_TYPE_TYPED_ARRAY_MIN;
-         i < NJS_OBJ_TYPE_TYPED_ARRAY_MAX;
-         i++)
-    {
-        vm->prototypes[i].object.__proto__ = typed_array_prototype;
-    }
-
-    vm->prototypes[NJS_OBJ_TYPE_ARRAY_ITERATOR].object.__proto__ =
-                              &vm->prototypes[NJS_OBJ_TYPE_ITERATOR].object;
-
-    vm->prototypes[NJS_OBJ_TYPE_BUFFER].object.__proto__ =
-                              &vm->prototypes[NJS_OBJ_TYPE_UINT8_ARRAY].object;
-
-    error_prototype = &vm->prototypes[NJS_OBJ_TYPE_ERROR].object;
-    error_prototype->__proto__ = object_prototype;
-
-    for (i = NJS_OBJ_TYPE_EVAL_ERROR; i < NJS_OBJ_TYPE_MAX; i++) {
-        vm->prototypes[i].object.__proto__ = error_prototype;
-    }
-
-    function_prototype = &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object;
-
-    async_prototype = &vm->prototypes[NJS_OBJ_TYPE_ASYNC_FUNCTION].object;
-    async_prototype->__proto__ = function_prototype;
-
-    for (i = NJS_OBJ_TYPE_OBJECT; i < NJS_OBJ_TYPE_NORMAL_MAX; i++) {
-        vm->constructors[i].object.__proto__ = function_prototype;
-    }
-
-    typed_array_ctor = &vm->constructors[NJS_OBJ_TYPE_TYPED_ARRAY].object;
-
-    for (i = NJS_OBJ_TYPE_TYPED_ARRAY_MIN;
-         i < NJS_OBJ_TYPE_TYPED_ARRAY_MAX;
-         i++)
-    {
-        vm->constructors[i].object.__proto__ = typed_array_ctor;
-    }
-
-    error_ctor = &vm->constructors[NJS_OBJ_TYPE_ERROR].object;
-    error_ctor->__proto__ = function_prototype;
-
-    for (i = NJS_OBJ_TYPE_EVAL_ERROR; i < NJS_OBJ_TYPE_MAX; i++) {
-        vm->constructors[i].object.__proto__ = error_ctor;
-    }
-
-    vm->global_object.__proto__ = object_prototype;
-
-    njs_set_undefined(global);
-    njs_set_object(global, &vm->global_object);
-
-    vm->string_object = vm->shared->string_object;
-    vm->string_object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_STRING].object;
-
     return NJS_OK;
 }
 
@@ -838,7 +763,7 @@ njs_builtin_match_native_function(njs_vm
     /* Constructor from built-in modules (not-mapped to global object). */
 
     for (i = NJS_OBJ_TYPE_HIDDEN_MIN; i < NJS_OBJ_TYPE_HIDDEN_MAX; i++) {
-        njs_set_object(&value, &vm->constructors[i].object);
+        njs_set_object(&value, &njs_vm_ctor(vm, i).object);
 
         ret = njs_value_property(vm, &value, njs_value_arg(&njs_string_name),
                                  &tag);
@@ -847,7 +772,7 @@ njs_builtin_match_native_function(njs_vm
             njs_string_get(&tag, &ctx.match);
         }
 
-        ret = njs_object_traverse(vm, &vm->constructors[i].object, &ctx,
+        ret = njs_object_traverse(vm, njs_object(&value), &ctx,
                                   njs_builtin_traverse);
 
         if (ret == NJS_DONE) {
@@ -1253,7 +1178,7 @@ njs_top_level_constructor(njs_vm_t *vm, 
             return NJS_DECLINED;
         }
 
-        ctor = &vm->constructors[njs_prop_magic16(self)];
+        ctor = &njs_vm_ctor(vm, njs_prop_magic16(self));
 
         njs_set_function(retval, ctor);
     }
diff -r 3386684745b7 -r 167f75576f49 src/njs_date.c
--- a/src/njs_date.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_date.c	Mon Jul 03 12:49:00 2023 -0700
@@ -364,7 +364,7 @@ njs_date_alloc(njs_vm_t *vm, double time
     date->object.extensible = 1;
     date->object.error_data = 0;
     date->object.fast_array = 0;
-    date->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_DATE].object;
+    date->object.__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_DATE);
     date->object.slots = NULL;
 
     date->time = time;
diff -r 3386684745b7 -r 167f75576f49 src/njs_error.c
--- a/src/njs_error.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_error.c	Mon Jul 03 12:49:00 2023 -0700
@@ -76,7 +76,7 @@ njs_throw_error(njs_vm_t *vm, njs_object
     va_list  args;
 
     va_start(args, fmt);
-    njs_throw_error_va(vm, &vm->prototypes[type].object, fmt, args);
+    njs_throw_error_va(vm, njs_vm_proto(vm, type), fmt, args);
     va_end(args);
 }
 
@@ -96,7 +96,7 @@ njs_error_fmt_new(njs_vm_t *vm, njs_valu
         va_end(args);
     }
 
-    njs_error_new(vm, dst, &vm->prototypes[type].object, buf, p - buf);
+    njs_error_new(vm, dst, njs_vm_proto(vm, type), buf, p - buf);
 }
 
 
@@ -298,7 +298,7 @@ memory_error:
 }
 
 
-static njs_int_t
+njs_int_t
 njs_error_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t type, njs_value_t *retval)
 {
@@ -339,7 +339,7 @@ njs_error_constructor(njs_vm_t *vm, njs_
         }
     }
 
-    error = njs_error_alloc(vm, &vm->prototypes[type].object, NULL,
+    error = njs_error_alloc(vm, njs_vm_proto(vm, type), NULL,
                             njs_is_defined(value) ? value : NULL,
                             njs_is_defined(&list) ? &list : NULL);
     if (njs_slow_path(error == NULL)) {
@@ -499,15 +499,13 @@ const njs_object_init_t  njs_aggregate_e
 void
 njs_memory_error_set(njs_vm_t *vm, njs_value_t *value)
 {
-    njs_object_t            *object;
-    njs_object_prototype_t  *prototypes;
+    njs_object_t  *object;
 
-    prototypes = vm->prototypes;
     object = &vm->memory_error_object;
 
     njs_lvlhsh_init(&object->hash);
     njs_lvlhsh_init(&object->shared_hash);
-    object->__proto__ = &prototypes[NJS_OBJ_TYPE_INTERNAL_ERROR].object;
+    object->__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_INTERNAL_ERROR);
     object->slots = NULL;
     object->type = NJS_OBJECT;
     object->shared = 1;
@@ -555,7 +553,7 @@ njs_memory_error_prototype_create(njs_vm
 
     function = njs_function(value);
     proto = njs_property_prototype_create(vm, &function->object.hash,
-                                          &vm->prototypes[index].object);
+                                          njs_vm_proto(vm, index));
     if (proto == NULL) {
         proto = &njs_value_undefined;
     }
diff -r 3386684745b7 -r 167f75576f49 src/njs_extern.c
--- a/src/njs_extern.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_extern.c	Mon Jul 03 12:49:00 2023 -0700
@@ -315,6 +315,77 @@ njs_vm_external_prototype(njs_vm_t *vm, 
 }
 
 
+static njs_int_t
+njs_vm_external_constructor_handler(njs_vm_t *vm, njs_object_prop_t *prop,
+    njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
+{
+    njs_set_function(retval, &njs_vm_ctor(vm, njs_prop_magic32(prop)));
+
+    return NJS_OK;
+}
+
+
+njs_int_t
+njs_vm_external_constructor(njs_vm_t *vm, const njs_str_t *name,
+    njs_function_native_t native, const njs_external_t *ctor_props,
+    njs_uint_t ctor_nprops, const njs_external_t *proto_props,
+    njs_uint_t proto_nprops)
+{
+    njs_int_t               ret, index, proto_id;
+    njs_arr_t               **pprotos;
+    njs_function_t          *constructor;
+    njs_exotic_slots_t      *slots;
+    njs_object_prototype_t  *prototype;
+
+    index = njs_vm_ctor_push(vm);
+    if (njs_slow_path(index < 0)) {
+        njs_internal_error(vm, "njs_vm_ctor_push() failed");
+        return -1;
+    }
+
+    proto_id = njs_vm_external_prototype(vm, proto_props, proto_nprops);
+    if (njs_slow_path(proto_id < 0)) {
+        njs_internal_error(vm, "njs_vm_external_prototype(proto_props) failed");
+        return -1;
+    }
+
+    prototype = njs_shared_prototype(vm->shared, index);
+    njs_memzero(prototype, sizeof(njs_object_prototype_t));
+    prototype->object.type = NJS_OBJECT;
+    prototype->object.extensible = 1;
+
+    pprotos = njs_arr_item(vm->protos, proto_id);
+    slots = (*pprotos)->start;
+    prototype->object.shared_hash = slots->external_shared_hash;
+
+    proto_id = njs_vm_external_prototype(vm, ctor_props, ctor_nprops);
+    if (njs_slow_path(proto_id < 0)) {
+        njs_internal_error(vm, "njs_vm_external_prototype(ctor_props) failed");
+        return -1;
+    }
+
+    constructor = njs_shared_ctor(vm->shared, index);
+    njs_memzero(constructor, sizeof(njs_function_t));
+    constructor->object.type = NJS_FUNCTION;
+    constructor->u.native = native;
+    constructor->magic8 = index;
+    constructor->native = 1;
+    constructor->ctor = 1;
+
+    pprotos = njs_arr_item(vm->protos, proto_id);
+    slots = (*pprotos)->start;
+    constructor->object.shared_hash = slots->external_shared_hash;
+
+    ret = njs_vm_bind_handler(vm, name, njs_vm_external_constructor_handler, 0,
+                              index, 1);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    return index;
+}
+
+
 njs_int_t
 njs_vm_external_create(njs_vm_t *vm, njs_value_t *value, njs_int_t proto_id,
     njs_external_ptr_t external, njs_bool_t shared)
diff -r 3386684745b7 -r 167f75576f49 src/njs_function.c
--- a/src/njs_function.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_function.c	Mon Jul 03 12:49:00 2023 -0700
@@ -46,10 +46,10 @@ njs_function_alloc(njs_vm_t *vm, njs_fun
     }
 
     if (async) {
-        proto = &vm->prototypes[NJS_OBJ_TYPE_ASYNC_FUNCTION].object;
+        proto = njs_vm_proto(vm, NJS_OBJ_TYPE_ASYNC_FUNCTION);
 
     } else {
-        proto = &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object;
+        proto = njs_vm_proto(vm, NJS_OBJ_TYPE_FUNCTION);
     }
 
     function->object.__proto__ = proto;
@@ -84,7 +84,7 @@ njs_vm_function_alloc(njs_vm_t *vm, njs_
     function->object.shared = shared;
     function->u.native = native;
     function->object.shared_hash = vm->shared->function_instance_hash;
-    function->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object;
+    function->object.__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_FUNCTION);
     function->object.type = NJS_FUNCTION;
 
     return function;
@@ -212,7 +212,7 @@ njs_function_copy(njs_vm_t *vm, njs_func
 
     type = njs_function_object_type(vm, function);
 
-    copy->object.__proto__ = &vm->prototypes[type].object;
+    copy->object.__proto__ = njs_vm_proto(vm, type);
     copy->object.shared = 0;
 
     if (copy->ctor) {
@@ -1370,7 +1370,7 @@ njs_function_prototype_bind(njs_vm_t *vm
     /* Bound functions have no "prototype" property. */
     function->object.shared_hash = vm->shared->arrow_instance_hash;
 
-    function->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object;
+    function->object.__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_FUNCTION);
     function->object.shared = 0;
 
     function->context = njs_function(&args[0]);
diff -r 3386684745b7 -r 167f75576f49 src/njs_json.c
--- a/src/njs_json.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_json.c	Mon Jul 03 12:49:00 2023 -0700
@@ -1979,7 +1979,7 @@ njs_vm_value_dump(njs_vm_t *vm, njs_str_
 
     if (njs_slow_path(vm->top_frame == NULL)) {
         /* An exception was thrown during compilation. */
-        njs_vm_init(vm);
+        njs_vm_runtime_init(vm);
     }
 
     if (njs_is_valid(&vm->exception)) {
diff -r 3386684745b7 -r 167f75576f49 src/njs_object.c
--- a/src/njs_object.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_object.c	Mon Jul 03 12:49:00 2023 -0700
@@ -45,7 +45,7 @@ njs_object_alloc(njs_vm_t *vm)
     if (njs_fast_path(object != NULL)) {
         njs_lvlhsh_init(&object->hash);
         njs_lvlhsh_init(&object->shared_hash);
-        object->__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object;
+        object->__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_OBJECT);
         object->slots = NULL;
         object->type = NJS_OBJECT;
         object->shared = 0;
@@ -80,7 +80,7 @@ njs_object_value_copy(njs_vm_t *vm, njs_
 
     if (njs_fast_path(object != NULL)) {
         memcpy(object, njs_object(value), size);
-        object->__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object;
+        object->__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_OBJECT);
         object->shared = 0;
         value->data.u.object = object;
         return object;
@@ -119,7 +119,7 @@ njs_object_value_alloc(njs_vm_t *vm, njs
     ov->object.error_data = 0;
     ov->object.fast_array = 0;
 
-    ov->object.__proto__ = &vm->prototypes[prototype_index].object;
+    ov->object.__proto__ = njs_vm_proto(vm, prototype_index);
     ov->object.slots = NULL;
 
     if (value != NULL) {
@@ -1501,7 +1501,7 @@ njs_object_get_prototype_of(njs_vm_t *vm
         index = njs_primitive_prototype_index(value->type);
 
         if (njs_is_symbol(value)) {
-            njs_set_object(retval, &vm->prototypes[index].object);
+            njs_set_object(retval, njs_vm_proto(vm, index));
 
         } else {
             njs_set_object_value(retval,
@@ -1843,7 +1843,7 @@ njs_primitive_prototype_get_proto(njs_vm
 
     } else {
         index = njs_primitive_prototype_index(value->type);
-        proto = &vm->prototypes[index].object;
+        proto = njs_vm_proto(vm, index);
     }
 
     if (proto != NULL) {
@@ -1875,7 +1875,7 @@ njs_object_prototype_create(njs_vm_t *vm
     function = njs_function(value);
     index = function - vm->constructors;
 
-    if (index >= 0 && index < NJS_OBJ_TYPE_MAX) {
+    if (index >= 0 && (size_t) index < vm->constructors_size) {
         proto = njs_property_prototype_create(vm, &function->object.hash,
                                               &vm->prototypes[index].object);
     }
@@ -2111,7 +2111,7 @@ njs_object_prototype_create_constructor(
             prototype = (njs_object_prototype_t *) object;
             index = prototype - vm->prototypes;
 
-            if (index >= 0 && index < NJS_OBJ_TYPE_MAX) {
+            if (index >= 0 && (size_t) index < vm->constructors_size) {
                 goto found;
             }
 
@@ -2128,7 +2128,7 @@ njs_object_prototype_create_constructor(
 
 found:
 
-    njs_set_function(&constructor, &vm->constructors[index]);
+    njs_set_function(&constructor, &njs_vm_ctor(vm, index));
     setval = &constructor;
 
     cons = njs_property_constructor_set(vm, &prototype->object.hash, setval);
diff -r 3386684745b7 -r 167f75576f49 src/njs_parser.c
--- a/src/njs_parser.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_parser.c	Mon Jul 03 12:49:00 2023 -0700
@@ -9199,6 +9199,10 @@ njs_parser_error(njs_vm_t *vm, njs_objec
     static const njs_value_t  file_name = njs_string("fileName");
     static const njs_value_t  line_number = njs_string("lineNumber");
 
+    if (njs_slow_path(vm->top_frame == NULL)) {
+        njs_vm_runtime_init(vm);
+    }
+
     p = msg;
     end = msg + NJS_MAX_ERROR_STR;
 
@@ -9217,7 +9221,7 @@ njs_parser_error(njs_vm_t *vm, njs_objec
         p = njs_sprintf(p, end, " in %uD", line);
     }
 
-    njs_error_new(vm, &error, &vm->prototypes[type].object, msg, p - msg);
+    njs_error_new(vm, &error, njs_vm_proto(vm, type), msg, p - msg);
 
     njs_set_number(&value, line);
     njs_value_property_set(vm, &error, njs_value_arg(&line_number), &value);
diff -r 3386684745b7 -r 167f75576f49 src/njs_promise.c
--- a/src/njs_promise.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_promise.c	Mon Jul 03 12:49:00 2023 -0700
@@ -131,7 +131,7 @@ njs_promise_alloc(njs_vm_t *vm)
     promise->object.extensible = 1;
     promise->object.error_data = 0;
     promise->object.fast_array = 0;
-    promise->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_PROMISE].object;
+    promise->object.__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_PROMISE);
     promise->object.slots = NULL;
 
     data = (njs_promise_data_t *) ((uint8_t *) promise + sizeof(njs_promise_t));
@@ -265,7 +265,7 @@ njs_promise_create_function(njs_vm_t *vm
         context = NULL;
     }
 
-    function->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object;
+    function->object.__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_FUNCTION);
     function->object.shared_hash = vm->shared->arrow_instance_hash;
     function->object.type = NJS_FUNCTION;
     function->object.extensible = 1;
@@ -1352,8 +1352,8 @@ njs_promise_perform_all(njs_vm_t *vm, nj
 
         if (handler == njs_promise_perform_any_handler) {
             error = njs_error_alloc(vm,
-                           &vm->prototypes[NJS_OBJ_TYPE_AGGREGATE_ERROR].object,
-                           NULL, &string_any_rejected, &argument);
+                                njs_vm_proto(vm, NJS_OBJ_TYPE_AGGREGATE_ERROR),
+                                NULL, &string_any_rejected, &argument);
             if (njs_slow_path(error == NULL)) {
                 return NJS_ERROR;
             }
@@ -1730,8 +1730,8 @@ njs_promise_any_reject_element_functions
         njs_mp_free(vm->mem_pool, context->remaining_elements);
 
         error = njs_error_alloc(vm,
-                          &vm->prototypes[NJS_OBJ_TYPE_AGGREGATE_ERROR].object,
-                          NULL, &string_any_rejected, &arr_value);
+                                njs_vm_proto(vm, NJS_OBJ_TYPE_AGGREGATE_ERROR),
+                                NULL, &string_any_rejected, &arr_value);
         if (njs_slow_path(error == NULL)) {
             return NJS_ERROR;
         }
diff -r 3386684745b7 -r 167f75576f49 src/njs_regexp.c
--- a/src/njs_regexp.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_regexp.c	Mon Jul 03 12:49:00 2023 -0700
@@ -503,7 +503,7 @@ njs_regexp_alloc(njs_vm_t *vm, njs_regex
     if (njs_fast_path(regexp != NULL)) {
         njs_lvlhsh_init(&regexp->object.hash);
         regexp->object.shared_hash = vm->shared->regexp_instance_hash;
-        regexp->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_REGEXP].object;
+        regexp->object.__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_REGEXP);
         regexp->object.slots = NULL;
         regexp->object.type = NJS_REGEXP;
         regexp->object.shared = 0;
@@ -628,7 +628,7 @@ njs_regexp_prototype_flag(njs_vm_t *vm, 
     }
 
     if (njs_slow_path(!njs_is_regexp(this))) {
-        if (njs_object(this) == &vm->prototypes[NJS_OBJ_TYPE_REGEXP].object) {
+        if (njs_object(this) == njs_vm_proto(vm, NJS_OBJ_TYPE_REGEXP)) {
             njs_set_undefined(retval);
             return NJS_OK;
         }
@@ -679,7 +679,7 @@ njs_regexp_prototype_source(njs_vm_t *vm
     }
 
     if (njs_slow_path(!njs_is_regexp(this))) {
-        if (njs_object(this) == &vm->prototypes[NJS_OBJ_TYPE_REGEXP].object) {
+        if (njs_object(this) == njs_vm_proto(vm, NJS_OBJ_TYPE_REGEXP)) {
             njs_value_assign(retval, &njs_string_empty_regexp);
             return NJS_OK;
         }
@@ -1553,7 +1553,7 @@ njs_regexp_prototype_symbol_split(njs_vm
         return ret;
     }
 
-    njs_set_function(&constructor, &vm->constructors[NJS_OBJ_TYPE_REGEXP]);
+    njs_set_function(&constructor, &njs_vm_ctor(vm, NJS_OBJ_TYPE_REGEXP));
 
     ret = njs_value_species_constructor(vm, rx, &constructor, &constructor);
     if (njs_slow_path(ret != NJS_OK)) {
diff -r 3386684745b7 -r 167f75576f49 src/njs_typed_array.c
--- a/src/njs_typed_array.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_typed_array.c	Mon Jul 03 12:49:00 2023 -0700
@@ -180,7 +180,7 @@ njs_typed_array_alloc(njs_vm_t *vm, njs_
 
     njs_lvlhsh_init(&array->object.hash);
     njs_lvlhsh_init(&array->object.shared_hash);
-    array->object.__proto__ = &vm->prototypes[type].object;
+    array->object.__proto__ = njs_vm_proto(vm, type);
     array->object.type = NJS_TYPED_ARRAY;
     array->object.extensible = 1;
     array->object.fast_array = 1;
@@ -264,7 +264,7 @@ njs_typed_array_species_create(njs_vm_t 
 
     array = njs_typed_array(exemplar);
 
-    njs_set_function(&constructor, &vm->constructors[array->type]);
+    njs_set_function(&constructor, &njs_vm_ctor(vm, array->type));
 
     ret = njs_value_species_constructor(vm, exemplar, &constructor,
                                         &constructor);
@@ -2413,7 +2413,7 @@ njs_data_view_constructor(njs_vm_t *vm, 
 
     njs_lvlhsh_init(&view->object.hash);
     njs_lvlhsh_init(&view->object.shared_hash);
-    view->object.__proto__ = &vm->prototypes[view->type].object;
+    view->object.__proto__ = njs_vm_proto(vm, view->type);
     view->object.type = NJS_DATA_VIEW;
     view->object.extensible = 1;
 
diff -r 3386684745b7 -r 167f75576f49 src/njs_value.c
--- a/src/njs_value.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_value.c	Mon Jul 03 12:49:00 2023 -0700
@@ -638,7 +638,7 @@ njs_property_query(njs_vm_t *vm, njs_pro
     case NJS_NUMBER:
     case NJS_SYMBOL:
         index = njs_primitive_prototype_index(value->type);
-        obj = &vm->prototypes[index].object;
+        obj = njs_vm_proto(vm, index);
         break;
 
     case NJS_STRING:
diff -r 3386684745b7 -r 167f75576f49 src/njs_value.h
--- a/src/njs_value.h	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_value.h	Mon Jul 03 12:49:00 2023 -0700
@@ -625,9 +625,8 @@ typedef struct {
     ((value)->type >= NJS_OBJECT)
 
 
-#define njs_has_prototype(vm, value, proto)                                   \
-    (((njs_object_prototype_t *)                                              \
-        njs_object(value)->__proto__ - (vm)->prototypes) == proto)
+#define njs_has_prototype(vm, value, proto_id)                                \
+    (njs_object(value)->__proto__ == njs_vm_proto(vm, proto_id))
 
 
 #define njs_is_object_value(value)                                            \
diff -r 3386684745b7 -r 167f75576f49 src/njs_vm.c
--- a/src/njs_vm.c	Fri Jun 30 21:02:44 2023 -0700
+++ b/src/njs_vm.c	Mon Jul 03 12:49:00 2023 -0700
@@ -9,6 +9,7 @@
 
 
 static njs_int_t njs_vm_handle_events(njs_vm_t *vm);
+static njs_int_t njs_vm_protos_init(njs_vm_t *vm, njs_value_t *global);
 
 
 const njs_str_t  njs_entry_empty =          njs_str("");
@@ -78,13 +79,47 @@ njs_vm_create(njs_vm_opt_t *options)
     vm->trace.data = vm;
 
     if (options->init) {
-        ret = njs_vm_init(vm);
+        ret = njs_vm_runtime_init(vm);
         if (njs_slow_path(ret != NJS_OK)) {
             return NULL;
         }
     }
 
     for (i = 0; njs_modules[i] != NULL; i++) {
+        if (njs_modules[i]->preinit == NULL) {
+            continue;
+        }
+
+        ret = njs_modules[i]->preinit(vm);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return NULL;
+        }
+    }
+
+    if (options->addons != NULL) {
+        addons = options->addons;
+        for (i = 0; addons[i] != NULL; i++) {
+            if (addons[i]->preinit == NULL) {
+                continue;
+            }
+
+            ret = addons[i]->preinit(vm);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return NULL;
+            }
+        }
+    }
+
+    ret = njs_vm_protos_init(vm, &vm->global_value);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NULL;
+    }
+
+    for (i = 0; njs_modules[i] != NULL; i++) {
+        if (njs_modules[i]->init == NULL) {
+            continue;
+        }
+
         ret = njs_modules[i]->init(vm);
         if (njs_slow_path(ret != NJS_OK)) {
             return NULL;
@@ -94,6 +129,10 @@ njs_vm_create(njs_vm_opt_t *options)
     if (options->addons != NULL) {
         addons = options->addons;
         for (i = 0; addons[i] != NULL; i++) {
+            if (addons[i]->init == NULL) {
+                continue;
+            }
+
             ret = addons[i]->init(vm);
             if (njs_slow_path(ret != NJS_OK)) {
                 return NULL;
@@ -111,6 +150,51 @@ njs_vm_create(njs_vm_opt_t *options)
 }
 
 
+njs_int_t
+njs_vm_ctor_push(njs_vm_t *vm)
+{
+    njs_function_t          *ctor;
+    njs_vm_shared_t         *shared;
+    njs_object_prototype_t  *prototype;
+
+    shared = vm->shared;


More information about the nginx-devel mailing list