[njs] Moving out HostPromiseRejectionTracker from njs core.

Dmitry Volyntsev xeioex at nginx.com
Sat Jan 20 02:16:49 UTC 2024


details:   https://hg.nginx.org/njs/rev/8aad26845b18
branches:  
changeset: 2269:8aad26845b18
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Thu Jan 18 18:03:35 2024 -0800
description:
Moving out HostPromiseRejectionTracker from njs core.

HostPromiseRejectionTracker should be implemented by host
environment according to ECMAScript specs.

The following method was removed: njs_vm_unhandled_rejection().
The following method was introduced: njs_vm_set_rejection_tracker().

diffstat:

 external/njs_shell.c         |  103 +++++++++++++++++++++++++++++++++++++++++-
 nginx/ngx_http_js_module.c   |    1 -
 nginx/ngx_js.c               |  101 +++++++++++++++++++++++++++++++++++++++--
 nginx/ngx_js.h               |    2 +
 nginx/ngx_stream_js_module.c |    1 -
 src/njs.h                    |   15 ++---
 src/njs_promise.c            |   74 ++++--------------------------
 src/njs_value.c              |    7 ++
 src/njs_vm.c                 |   40 +++------------
 src/njs_vm.h                 |    4 +-
 10 files changed, 230 insertions(+), 118 deletions(-)

diffs (651 lines):

diff -r da8b044e1c61 -r 8aad26845b18 external/njs_shell.c
--- a/external/njs_shell.c	Thu Jan 18 18:03:24 2024 -0800
+++ b/external/njs_shell.c	Thu Jan 18 18:03:35 2024 -0800
@@ -93,6 +93,12 @@ typedef struct {
 
 
 typedef struct {
+    void                    *promise;
+    njs_opaque_value_t      message;
+} njs_rejected_promise_t;
+
+
+typedef struct {
     njs_vm_t                *vm;
 
     uint32_t                event_id;
@@ -101,6 +107,8 @@ typedef struct {
 
     njs_queue_t             labels;
 
+    njs_arr_t               *rejected_promises;
+
     njs_bool_t              suppress_stdout;
 
     njs_completion_t        completion;
@@ -422,7 +430,7 @@ njs_options_parse(njs_opts_t *opts, int 
 
     opts->denormals = 1;
     opts->exit_code = EXIT_FAILURE;
-    opts->unhandled_rejection = NJS_VM_OPT_UNHANDLED_REJECTION_THROW;
+    opts->unhandled_rejection = 1;
 
     p = getenv("NJS_EXIT_CODE");
     if (p != NULL) {
@@ -528,7 +536,7 @@ njs_options_parse(njs_opts_t *opts, int 
             break;
 
         case 'r':
-            opts->unhandled_rejection = NJS_VM_OPT_UNHANDLED_REJECTION_IGNORE;
+            opts->unhandled_rejection = 0;
             break;
 
         case 's':
@@ -636,6 +644,8 @@ njs_console_init(njs_vm_t *vm, njs_conso
     njs_queue_init(&console->posted_events);
     njs_queue_init(&console->labels);
 
+    console->rejected_promises = NULL;
+
     console->completion.completions = njs_vm_completions(vm, NULL);
     if (console->completion.completions == NULL) {
         return NJS_ERROR;
@@ -749,6 +759,53 @@ njs_externals_init(njs_vm_t *vm)
 }
 
 
+static void
+njs_rejection_tracker(njs_vm_t *vm, njs_external_ptr_t external,
+    njs_bool_t is_handled, njs_value_t *promise, njs_value_t *reason)
+{
+    void                    *promise_obj;
+    uint32_t                i, length;
+    njs_console_t           *console;
+    njs_rejected_promise_t  *rejected_promise;
+
+    console = external;
+
+    if (is_handled && console->rejected_promises != NULL) {
+        rejected_promise = console->rejected_promises->start;
+        length = console->rejected_promises->items;
+
+        promise_obj = njs_value_ptr(promise);
+
+        for (i = 0; i < length; i++) {
+            if (rejected_promise[i].promise == promise_obj) {
+                njs_arr_remove(console->rejected_promises,
+                               &rejected_promise[i]);
+
+                break;
+            }
+        }
+
+        return;
+    }
+
+    if (console->rejected_promises == NULL) {
+        console->rejected_promises = njs_arr_create(njs_vm_memory_pool(vm), 4,
+                                                sizeof(njs_rejected_promise_t));
+        if (njs_slow_path(console->rejected_promises == NULL)) {
+            return;
+        }
+    }
+
+    rejected_promise = njs_arr_add(console->rejected_promises);
+    if (njs_slow_path(rejected_promise == NULL)) {
+        return;
+    }
+
+    rejected_promise->promise = njs_value_ptr(promise);
+    njs_value_assign(&rejected_promise->message, reason);
+}
+
+
 static njs_vm_t *
 njs_create_vm(njs_opts_t *opts)
 {
@@ -784,7 +841,6 @@ njs_create_vm(njs_opts_t *opts)
     vm_options.argv = opts->argv;
     vm_options.argc = opts->argc;
     vm_options.ast = opts->ast;
-    vm_options.unhandled_rejection = opts->unhandled_rejection;
 
     if (opts->stack_size != 0) {
         vm_options.max_stack_size = opts->stack_size;
@@ -796,6 +852,11 @@ njs_create_vm(njs_opts_t *opts)
         return NULL;
     }
 
+    if (opts->unhandled_rejection) {
+        njs_vm_set_rejection_tracker(vm, njs_rejection_tracker,
+                                     njs_vm_external_ptr(vm));
+    }
+
     for (i = 0; i < opts->n_paths; i++) {
         path.start = (u_char *) opts->paths[i];
         path.length = njs_strlen(opts->paths[i]);
@@ -914,6 +975,40 @@ njs_process_events(void *runtime)
 
 
 static njs_int_t
+njs_unhandled_rejection(void *runtime)
+{
+    njs_int_t               ret;
+    njs_str_t               message;
+    njs_console_t           *console;
+    njs_rejected_promise_t  *rejected_promise;
+
+    console = runtime;
+
+    if (console->rejected_promises == NULL
+        || console->rejected_promises->items == 0)
+    {
+        return 0;
+    }
+
+    rejected_promise = console->rejected_promises->start;
+
+    ret = njs_vm_value_to_string(console->vm, &message,
+                                 njs_value_arg(&rejected_promise->message));
+    if (njs_slow_path(ret != NJS_OK)) {
+        return -1;
+    }
+
+    njs_vm_error(console->vm, "unhandled promise rejection: %V",
+                 &message);
+
+    njs_arr_destroy(console->rejected_promises);
+    console->rejected_promises = NULL;
+
+    return 1;
+}
+
+
+static njs_int_t
 njs_read_file(njs_opts_t *opts, njs_str_t *content)
 {
     int          fd;
@@ -1112,7 +1207,7 @@ njs_process_script(njs_vm_t *vm, void *r
             }
         }
 
-        if (njs_vm_unhandled_rejection(vm)) {
+        if (njs_unhandled_rejection(runtime)) {
             njs_process_output(vm, NULL, NJS_ERROR);
 
             if (!njs_vm_options(vm)->interactive) {
diff -r da8b044e1c61 -r 8aad26845b18 nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c	Thu Jan 18 18:03:24 2024 -0800
+++ b/nginx/ngx_http_js_module.c	Thu Jan 18 18:03:35 2024 -0800
@@ -4505,7 +4505,6 @@ ngx_http_js_init_conf_vm(ngx_conf_t *cf,
     ngx_http_js_uptr[NGX_JS_MAIN_CONF_INDEX] = (uintptr_t) jmcf;
 
     options.backtrace = 1;
-    options.unhandled_rejection = NJS_VM_OPT_UNHANDLED_REJECTION_THROW;
     options.metas = &ngx_http_js_metas;
     options.addons = njs_http_js_addon_modules;
     options.argv = ngx_argv;
diff -r da8b044e1c61 -r 8aad26845b18 nginx/ngx_js.c
--- a/nginx/ngx_js.c	Thu Jan 18 18:03:24 2024 -0800
+++ b/nginx/ngx_js.c	Thu Jan 18 18:03:35 2024 -0800
@@ -12,17 +12,23 @@
 
 
 typedef struct {
-    ngx_queue_t       labels;
+    ngx_queue_t          labels;
 } ngx_js_console_t;
 
 
 typedef struct {
-    njs_str_t         name;
-    uint64_t          time;
-    ngx_queue_t       queue;
+    njs_str_t            name;
+    uint64_t             time;
+    ngx_queue_t          queue;
 } ngx_js_timelabel_t;
 
 
+typedef struct {
+    void                *promise;
+    njs_opaque_value_t   message;
+} ngx_js_rejected_promise_t;
+
+
 static njs_int_t ngx_js_ext_build(njs_vm_t *vm, njs_object_prop_t *prop,
     njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
 static njs_int_t ngx_js_ext_conf_file_path(njs_vm_t *vm,
@@ -49,6 +55,7 @@ static njs_int_t njs_set_immediate(njs_v
     njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
 static njs_int_t njs_clear_timeout(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
+static njs_int_t ngx_js_unhandled_rejection(ngx_js_ctx_t *ctx);
 static void ngx_js_cleanup_vm(void *data);
 
 static njs_int_t ngx_js_core_init(njs_vm_t *vm);
@@ -429,15 +436,15 @@ ngx_js_name_invoke(njs_vm_t *vm, ngx_str
         }
     }
 
-    if (njs_vm_unhandled_rejection(vm)) {
+    ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm));
+
+    if (ngx_js_unhandled_rejection(ctx)) {
         ngx_js_exception(vm, &exception);
 
         ngx_log_error(NGX_LOG_ERR, log, 0, "js exception: %V", &exception);
         return NGX_ERROR;
     }
 
-    ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm));
-
     return njs_rbtree_is_empty(&ctx->waiting_events) ? NGX_OK : NGX_AGAIN;
 }
 
@@ -1661,6 +1668,53 @@ ngx_js_merge_vm(ngx_conf_t *cf, ngx_js_l
 }
 
 
+static void
+ngx_js_rejection_tracker(njs_vm_t *vm, njs_external_ptr_t unused,
+    njs_bool_t is_handled, njs_value_t *promise, njs_value_t *reason)
+{
+    void                       *promise_obj;
+    uint32_t                    i, length;
+    ngx_js_ctx_t               *ctx;
+    ngx_js_rejected_promise_t  *rejected_promise;
+
+    ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm));
+
+    if (is_handled && ctx->rejected_promises != NULL) {
+        rejected_promise = ctx->rejected_promises->start;
+        length = ctx->rejected_promises->items;
+
+        promise_obj = njs_value_ptr(promise);
+
+        for (i = 0; i < length; i++) {
+            if (rejected_promise[i].promise == promise_obj) {
+                njs_arr_remove(ctx->rejected_promises,
+                               &rejected_promise[i]);
+
+                break;
+            }
+        }
+
+        return;
+    }
+
+    if (ctx->rejected_promises == NULL) {
+        ctx->rejected_promises = njs_arr_create(njs_vm_memory_pool(vm), 4,
+                                             sizeof(ngx_js_rejected_promise_t));
+        if (njs_slow_path(ctx->rejected_promises == NULL)) {
+            return;
+        }
+    }
+
+    rejected_promise = njs_arr_add(ctx->rejected_promises);
+    if (njs_slow_path(rejected_promise == NULL)) {
+        return;
+    }
+
+    rejected_promise->promise = njs_value_ptr(promise);
+    njs_value_assign(&rejected_promise->message, reason);
+}
+
+
 ngx_int_t
 ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_js_loc_conf_t *conf,
     njs_vm_opt_t *options)
@@ -1738,6 +1792,9 @@ ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_
     cln->handler = ngx_js_cleanup_vm;
     cln->data = conf;
 
+    njs_vm_set_rejection_tracker(conf->vm, ngx_js_rejection_tracker,
+                                 NULL);
+
     path.start = ngx_cycle->conf_prefix.data;
     path.length = ngx_cycle->conf_prefix.len;
 
@@ -1810,6 +1867,36 @@ ngx_js_init_conf_vm(ngx_conf_t *cf, ngx_
 }
 
 
+static njs_int_t
+ngx_js_unhandled_rejection(ngx_js_ctx_t *ctx)
+{
+    njs_int_t                   ret;
+    njs_str_t                   message;
+    ngx_js_rejected_promise_t  *rejected_promise;
+
+    if (ctx->rejected_promises == NULL
+        || ctx->rejected_promises->items == 0)
+    {
+        return 0;
+    }
+
+    rejected_promise = ctx->rejected_promises->start;
+
+    ret = njs_vm_value_to_string(ctx->vm, &message,
+                                 njs_value_arg(&rejected_promise->message));
+    if (njs_slow_path(ret != NJS_OK)) {
+        return -1;
+    }
+
+    njs_vm_error(ctx->vm, "unhandled promise rejection: %V", &message);
+
+    njs_arr_destroy(ctx->rejected_promises);
+    ctx->rejected_promises = NULL;
+
+    return 1;
+}
+
+
 static void
 ngx_js_cleanup_vm(void *data)
 {
diff -r da8b044e1c61 -r 8aad26845b18 nginx/ngx_js.h
--- a/nginx/ngx_js.h	Thu Jan 18 18:03:24 2024 -0800
+++ b/nginx/ngx_js.h	Thu Jan 18 18:03:35 2024 -0800
@@ -15,6 +15,7 @@
 #include <ngx_event.h>
 #include <njs.h>
 #include <njs_rbtree.h>
+#include <njs_arr.h>
 #include "ngx_js_fetch.h"
 #include "ngx_js_shared_dict.h"
 
@@ -111,6 +112,7 @@ struct ngx_js_event_s {
 
 #define NGX_JS_COMMON_CTX                                                     \
     njs_vm_t              *vm;                                                \
+    njs_arr_t             *rejected_promises;                                 \
     njs_rbtree_t           waiting_events;                                    \
     ngx_socket_t           event_id
 
diff -r da8b044e1c61 -r 8aad26845b18 nginx/ngx_stream_js_module.c
--- a/nginx/ngx_stream_js_module.c	Thu Jan 18 18:03:24 2024 -0800
+++ b/nginx/ngx_stream_js_module.c	Thu Jan 18 18:03:35 2024 -0800
@@ -1778,7 +1778,6 @@ ngx_stream_js_init_conf_vm(ngx_conf_t *c
     ngx_stream_js_uptr[NGX_JS_MAIN_CONF_INDEX] = (uintptr_t) jmcf;
 
     options.backtrace = 1;
-    options.unhandled_rejection = NJS_VM_OPT_UNHANDLED_REJECTION_THROW;
     options.metas = &ngx_stream_js_metas;
     options.addons = njs_stream_js_addon_modules;
     options.argv = ngx_argv;
diff -r da8b044e1c61 -r 8aad26845b18 src/njs.h
--- a/src/njs.h	Thu Jan 18 18:03:24 2024 -0800
+++ b/src/njs.h	Thu Jan 18 18:03:35 2024 -0800
@@ -196,6 +196,9 @@ typedef void *                      njs_
 
 typedef njs_mod_t *(*njs_module_loader_t)(njs_vm_t *vm,
     njs_external_ptr_t external, njs_str_t *name);
+typedef void (*njs_rejection_tracker_t)(njs_vm_t *vm,
+    njs_external_ptr_t external, njs_bool_t is_handled, njs_value_t *promise,
+    njs_value_t *reason);
 
 
 typedef struct {
@@ -225,9 +228,6 @@ typedef struct {
 
     njs_uint_t                      max_stack_size;
 
-#define NJS_VM_OPT_UNHANDLED_REJECTION_IGNORE   0
-#define NJS_VM_OPT_UNHANDLED_REJECTION_THROW    1
-
 /*
  * interactive  - enables "interactive" mode.
  *  (REPL). Allows starting parent VM without cloning.
@@ -240,9 +240,6 @@ typedef struct {
  *   - Function constructors.
  * module        - ES6 "module" mode. Script mode is default.
  * ast           - print AST.
- * unhandled_rejection IGNORE | THROW - tracks unhandled promise rejections:
- *   - throwing inside a Promise without a catch block.
- *   - throwing inside in a finally or catch block.
  */
     uint8_t                         interactive;     /* 1 bit */
     uint8_t                         trailer;         /* 1 bit */
@@ -260,7 +257,6 @@ typedef struct {
 #ifdef NJS_DEBUG_GENERATOR
     uint8_t                         generator_debug; /* 1 bit */
 #endif
-    uint8_t                         unhandled_rejection;
 } njs_vm_opt_t;
 
 
@@ -304,7 +300,9 @@ NJS_EXPORT njs_int_t njs_vm_enqueue_job(
  */
 NJS_EXPORT njs_int_t njs_vm_execute_pending_job(njs_vm_t *vm);
 NJS_EXPORT njs_int_t njs_vm_pending(njs_vm_t *vm);
-NJS_EXPORT njs_int_t njs_vm_unhandled_rejection(njs_vm_t *vm);
+
+NJS_EXPORT void njs_vm_set_rejection_tracker(njs_vm_t *vm,
+        njs_rejection_tracker_t rejection_tracker, void *opaque);
 
 NJS_EXPORT void *njs_vm_completions(njs_vm_t *vm, njs_str_t *expression);
 
@@ -468,6 +466,7 @@ NJS_EXPORT double njs_value_number(const
 NJS_EXPORT njs_function_t *njs_value_function(const njs_value_t *value);
 NJS_EXPORT njs_function_native_t njs_value_native_function(
     const njs_value_t *value);
+NJS_EXPORT void *njs_value_ptr(const njs_value_t *value);
 njs_external_ptr_t njs_value_external(const njs_value_t *value);
 NJS_EXPORT njs_int_t njs_value_external_tag(const njs_value_t *value);
 
diff -r da8b044e1c61 -r 8aad26845b18 src/njs_promise.c
--- a/src/njs_promise.c	Thu Jan 18 18:03:24 2024 -0800
+++ b/src/njs_promise.c	Thu Jan 18 18:03:35 2024 -0800
@@ -61,8 +61,6 @@ static njs_int_t njs_promise_value_const
 static njs_int_t njs_promise_capability_executor(njs_vm_t *vm,
     njs_value_t *args, njs_uint_t nargs, njs_index_t unused,
     njs_value_t *retval);
-static njs_int_t njs_promise_host_rejection_tracker(njs_vm_t *vm,
-    njs_promise_t *promise, njs_promise_rejection_type_t operation);
 static njs_int_t njs_promise_resolve_function(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
 static njs_int_t njs_promise_reject_function(njs_vm_t *vm, njs_value_t *args,
@@ -513,8 +511,8 @@ njs_promise_fulfill(njs_vm_t *vm, njs_pr
 njs_inline njs_value_t *
 njs_promise_reject(njs_vm_t *vm, njs_promise_t *promise, njs_value_t *reason)
 {
-    njs_int_t           ret;
     njs_queue_t         queue;
+    njs_value_t         promise_value;
     njs_promise_data_t  *data;
 
     data = njs_data(&promise->value);
@@ -523,10 +521,10 @@ njs_promise_reject(njs_vm_t *vm, njs_pro
     data->state = NJS_PROMISE_REJECTED;
 
     if (!data->is_handled) {
-        ret = njs_promise_host_rejection_tracker(vm, promise,
-                                                 NJS_PROMISE_REJECT);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return njs_value_arg(&njs_value_null);
+        if (vm->rejection_tracker != NULL) {
+            njs_set_promise(&promise_value, promise);
+            vm->rejection_tracker(vm, vm->rejection_tracker_opaque, 0,
+                                  &promise_value, reason);
         }
     }
 
@@ -548,58 +546,6 @@ njs_promise_reject(njs_vm_t *vm, njs_pro
 
 
 static njs_int_t
-njs_promise_host_rejection_tracker(njs_vm_t *vm, njs_promise_t *promise,
-    njs_promise_rejection_type_t operation)
-{
-    uint32_t            i, length;
-    njs_value_t         *value;
-    njs_promise_data_t  *data;
-
-    if (vm->options.unhandled_rejection
-        == NJS_VM_OPT_UNHANDLED_REJECTION_IGNORE)
-    {
-        return NJS_OK;
-    }
-
-    if (vm->promise_reason == NULL) {
-        vm->promise_reason = njs_array_alloc(vm, 1, 0, NJS_ARRAY_SPARE);
-        if (njs_slow_path(vm->promise_reason == NULL)) {
-            return NJS_ERROR;
-        }
-    }
-
-    data = njs_data(&promise->value);
-
-    if (operation == NJS_PROMISE_REJECT) {
-        if (vm->promise_reason != NULL) {
-            return njs_array_add(vm, vm->promise_reason, &data->result);
-        }
-
-    } else {
-        value = vm->promise_reason->start;
-        length = vm->promise_reason->length;
-
-        for (i = 0; i < length; i++) {
-            if (njs_values_same(&value[i], &data->result)) {
-                length--;
-
-                if (i < length) {
-                    memmove(&value[i], &value[i + 1],
-                            sizeof(njs_value_t) * (length - i));
-                }
-
-                break;
-            }
-        }
-
-        vm->promise_reason->length = length;
-    }
-
-    return NJS_OK;
-}
-
-
-static njs_int_t
 njs_promise_invoke_then(njs_vm_t *vm, njs_value_t *promise, njs_value_t *args,
     njs_int_t nargs, njs_value_t *retval)
 {
@@ -896,7 +842,7 @@ njs_promise_perform_then(njs_vm_t *vm, n
     njs_promise_capability_t *capability, njs_value_t *retval)
 {
     njs_int_t               ret;
-    njs_value_t             arguments[2];
+    njs_value_t             arguments[2], promise_value;
     njs_promise_t           *promise;
     njs_function_t          *function;
     njs_promise_data_t      *data;
@@ -949,10 +895,10 @@ njs_promise_perform_then(njs_vm_t *vm, n
         if (data->state == NJS_PROMISE_REJECTED) {
             njs_set_data(&arguments[0], rejected_reaction, 0);
 
-            ret = njs_promise_host_rejection_tracker(vm, promise,
-                                                     NJS_PROMISE_HANDLE);
-            if (njs_slow_path(ret != NJS_OK)) {
-                return ret;
+            if (vm->rejection_tracker != NULL) {
+                njs_set_promise(&promise_value, promise);
+                vm->rejection_tracker(vm, vm->rejection_tracker_opaque, 1,
+                                      &promise_value, &data->result);
             }
 
         } else {
diff -r da8b044e1c61 -r 8aad26845b18 src/njs_value.c
--- a/src/njs_value.c	Thu Jan 18 18:03:24 2024 -0800
+++ b/src/njs_value.c	Thu Jan 18 18:03:35 2024 -0800
@@ -457,6 +457,13 @@ njs_value_native_function(const njs_valu
 }
 
 
+void *
+njs_value_ptr(const njs_value_t *value)
+{
+    return njs_data(value);
+}
+
+
 njs_external_ptr_t
 njs_value_external(const njs_value_t *value)
 {
diff -r da8b044e1c61 -r 8aad26845b18 src/njs_vm.c
--- a/src/njs_vm.c	Thu Jan 18 18:03:24 2024 -0800
+++ b/src/njs_vm.c	Thu Jan 18 18:03:35 2024 -0800
@@ -627,37 +627,6 @@ njs_vm_pending(njs_vm_t *vm)
 
 
 njs_int_t
-njs_vm_unhandled_rejection(njs_vm_t *vm)
-{
-    njs_int_t    ret;
-    njs_str_t    str;
-    njs_value_t  string;
-
-    if (!(vm->options.unhandled_rejection
-          == NJS_VM_OPT_UNHANDLED_REJECTION_THROW
-          && vm->promise_reason != NULL
-          && vm->promise_reason->length != 0))
-    {
-        return 0;
-    }
-
-    njs_value_assign(&string, &vm->promise_reason->start[0]);
-    ret = njs_value_to_string(vm, &string, &string);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
-
-    njs_string_get(&string, &str);
-    njs_vm_error(vm, "unhandled promise rejection: %V", &str);
-
-    njs_mp_free(vm->mem_pool, vm->promise_reason);
-    vm->promise_reason = NULL;
-
-    return 1;
-}
-
-
-njs_int_t
 njs_vm_enqueue_job(njs_vm_t *vm, njs_function_t *function,
     const njs_value_t *args, njs_uint_t nargs)
 {
@@ -738,6 +707,15 @@ njs_vm_set_module_loader(njs_vm_t *vm, n
 }
 
 
+void
+njs_vm_set_rejection_tracker(njs_vm_t *vm,
+    njs_rejection_tracker_t rejection_tracker, void *opaque)
+{
+    vm->rejection_tracker = rejection_tracker;
+    vm->rejection_tracker_opaque = opaque;
+}
+
+
 njs_int_t
 njs_vm_add_path(njs_vm_t *vm, const njs_str_t *path)
 {
diff -r da8b044e1c61 -r 8aad26845b18 src/njs_vm.h
--- a/src/njs_vm.h	Thu Jan 18 18:03:24 2024 -0800
+++ b/src/njs_vm.h	Thu Jan 18 18:03:35 2024 -0800
@@ -160,8 +160,6 @@ struct njs_vm_s {
     njs_regex_compile_ctx_t  *regex_compile_ctx;
     njs_regex_match_data_t   *single_match_data;
 
-    njs_array_t              *promise_reason;
-
     njs_parser_scope_t       *global_scope;
 
     /*
@@ -185,6 +183,8 @@ struct njs_vm_s {
 
     njs_module_loader_t      module_loader;
     void                     *module_loader_opaque;
+    njs_rejection_tracker_t  rejection_tracker;
+    void                     *rejection_tracker_opaque;
 };
 
 


More information about the nginx-devel mailing list