diff --git a/quickjs.c b/quickjs.c index 62cf83bc2..115811e8a 100644 --- a/quickjs.c +++ b/quickjs.c @@ -50210,6 +50210,32 @@ static JSValue promise_reaction_job(JSContext *ctx, int argc, return res2; } +static JSValue promise_rejection_tracker_job(JSContext *ctx, int argc, + JSValueConst *argv) +{ + JSRuntime *rt; + JSPromiseData *s; + JSValueConst promise; + + assert(argc == 1); + + rt = ctx->rt; + promise = argv[0]; + s = JS_GetOpaque(promise, JS_CLASS_PROMISE); + + if (!s || s->promise_state != JS_PROMISE_REJECTED) + return JS_UNDEFINED; /* should never happen */ + + promise_trace(ctx, "promise_rejection_tracker_job\n"); + + // Check again in case the hook was removed. + if (rt->host_promise_rejection_tracker) + rt->host_promise_rejection_tracker( + ctx, promise, s->promise_result, s->is_handled, rt->host_promise_rejection_tracker_opaque); + + return JS_UNDEFINED; +} + void JS_SetPromiseHook(JSRuntime *rt, JSPromiseHook promise_hook, void *opaque) { rt->promise_hook = promise_hook; @@ -50247,14 +50273,6 @@ static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise, } } - if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) { - JSRuntime *rt = ctx->rt; - if (rt->host_promise_rejection_tracker) { - rt->host_promise_rejection_tracker(ctx, promise, value, false, - rt->host_promise_rejection_tracker_opaque); - } - } - list_for_each_safe(el, el1, &s->promise_reactions[is_reject]) { rd = list_entry(el, JSPromiseReactionData, link); args[0] = rd->resolving_funcs[0]; @@ -50272,6 +50290,12 @@ static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise, list_del(&rd->link); promise_reaction_data_free(ctx->rt, rd); } + + if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) { + JSRuntime *rt = ctx->rt; + if (rt->host_promise_rejection_tracker) + JS_EnqueueJob(ctx, promise_rejection_tracker_job, 1, &promise); + } } static JSValue js_promise_resolve_thenable_job(JSContext *ctx, @@ -51018,10 +51042,8 @@ static __exception int perform_promise_then(JSContext *ctx, JSValueConst args[5]; if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) { JSRuntime *rt = ctx->rt; - if (rt->host_promise_rejection_tracker) { - rt->host_promise_rejection_tracker(ctx, promise, s->promise_result, - true, rt->host_promise_rejection_tracker_opaque); - } + if (rt->host_promise_rejection_tracker) + JS_EnqueueJob(ctx, promise_rejection_tracker_job, 1, &promise); } i = s->promise_state - JS_PROMISE_FULFILLED; rd = rd_array[i]; diff --git a/run-test262.c b/run-test262.c index 03afe82df..d91f7f455 100644 --- a/run-test262.c +++ b/run-test262.c @@ -1716,7 +1716,8 @@ JSContext *JS_NewCustomContext(JSRuntime *rt) int run_test_buf(ThreadLocalStorage *tls, const char *filename, char *harness, namelist_t *ip, char *buf, size_t buf_len, const char* error_type, int eval_flags, bool is_negative, - bool is_async, bool can_block, int *msec) + bool is_async, bool can_block, bool track_promise_rejections, + int *msec) { JSRuntime *rt; JSContext *ctx; @@ -1741,6 +1742,9 @@ int run_test_buf(ThreadLocalStorage *tls, const char *filename, char *harness, /* loader for ES6 modules */ JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, (void *) filename); + if (track_promise_rejections) + JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker, NULL); + add_helpers(ctx); for (i = 0; i < ip->count; i++) { @@ -1787,6 +1791,7 @@ int run_test(ThreadLocalStorage *tls, const char *filename, int *msec) int ret, eval_flags, use_strict, use_nostrict; bool is_negative, is_nostrict, is_onlystrict, is_async, is_module, skip; bool detect_module = true; + bool track_promise_rejections = false; bool can_block; namelist_t include_list = { 0 }, *ip = &include_list; @@ -1845,6 +1850,9 @@ int run_test(ThreadLocalStorage *tls, const char *filename, int *msec) else if (str_equal(option, "qjs:no-detect-module")) { detect_module = false; } + else if (str_equal(option, "qjs:track-promise-rejections")) { + track_promise_rejections = true; + } else if (str_equal(option, "module")) { is_module = true; skip |= skip_module; @@ -1939,12 +1947,13 @@ int run_test(ThreadLocalStorage *tls, const char *filename, int *msec) if (use_nostrict) { ret = run_test_buf(tls, filename, harness, ip, buf, buf_len, error_type, eval_flags, is_negative, is_async, - can_block, msec); + can_block, track_promise_rejections, msec); } if (use_strict) { ret |= run_test_buf(tls, filename, harness, ip, buf, buf_len, error_type, eval_flags | JS_EVAL_FLAG_STRICT, - is_negative, is_async, can_block, msec); + is_negative, is_async, can_block, + track_promise_rejections, msec); } } namelist_free(&include_list); diff --git a/tests/bug39.js b/tests/bug39.js new file mode 100644 index 000000000..9084ea2e2 --- /dev/null +++ b/tests/bug39.js @@ -0,0 +1,6 @@ +/*--- +flags: [qjs:track-promise-rejections] +---*/ + +Promise.reject().catch(() => print('oops')) +Promise.resolve().then(() => print('ok'))