diff --git a/common.gypi b/common.gypi index 5fe20d8a8ee693..1676d43b469a9b 100644 --- a/common.gypi +++ b/common.gypi @@ -34,7 +34,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.42', + 'v8_embedder_string': '-node.43', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/src/builtins/builtins-microtask-queue-gen.cc b/deps/v8/src/builtins/builtins-microtask-queue-gen.cc index 427fd6edb65f71..b484fec9399d86 100644 --- a/deps/v8/src/builtins/builtins-microtask-queue-gen.cc +++ b/deps/v8/src/builtins/builtins-microtask-queue-gen.cc @@ -202,10 +202,17 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask( TNode const thenable = LoadObjectField( microtask, PromiseResolveThenableJobTask::kThenableOffset); + RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context, + CAST(promise_to_resolve)); + TNode const result = CallBuiltin(Builtins::kPromiseResolveThenableJob, native_context, promise_to_resolve, thenable, then); GotoIfException(result, &if_exception, &var_exception); + + RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context, + CAST(promise_to_resolve)); + RewindEnteredContext(saved_entered_context_count); SetCurrentContext(current_context); Goto(&done); diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index bf278c7ae513ae..e45f925a282d7a 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -16350,7 +16350,18 @@ TEST(PromiseHook) { CHECK_EQ(v8::Promise::kPending, GetPromise("p")->State()); CompileRun("resolve(Promise.resolve(value));\n"); CHECK_EQ(v8::Promise::kFulfilled, GetPromise("p")->State()); - CHECK_EQ(9, promise_hook_data->promise_hook_count); + CHECK_EQ(11, promise_hook_data->promise_hook_count); + + promise_hook_data->Reset(); + source = + "var p = Promise.resolve({\n" + " then(r) {\n" + " r();\n" + " }\n" + "});"; + CompileRun(source); + CHECK_EQ(GetPromise("p")->State(), v8::Promise::kFulfilled); + CHECK_EQ(promise_hook_data->promise_hook_count, 5); delete promise_hook_data; isolate->SetPromiseHook(nullptr); diff --git a/test/async-hooks/test-async-local-storage-thenable.js b/test/async-hooks/test-async-local-storage-thenable.js new file mode 100644 index 00000000000000..1f947fa9345491 --- /dev/null +++ b/test/async-hooks/test-async-local-storage-thenable.js @@ -0,0 +1,53 @@ +'use strict'; + +const common = require('../common'); + +const assert = require('assert'); +const { AsyncLocalStorage } = require('async_hooks'); + +// This test verifies that async local storage works with thenables + +const store = new AsyncLocalStorage(); +const data = Symbol('verifier'); + +const then = common.mustCall((cb) => { + assert.strictEqual(store.getStore(), data); + setImmediate(cb); +}, 4); + +function thenable() { + return { + then + }; +} + +// Await a thenable +store.run(data, async () => { + assert.strictEqual(store.getStore(), data); + await thenable(); + assert.strictEqual(store.getStore(), data); +}); + +// Returning a thenable in an async function +store.run(data, async () => { + try { + assert.strictEqual(store.getStore(), data); + return thenable(); + } finally { + assert.strictEqual(store.getStore(), data); + } +}); + +// Resolving a thenable +store.run(data, () => { + assert.strictEqual(store.getStore(), data); + Promise.resolve(thenable()); + assert.strictEqual(store.getStore(), data); +}); + +// Returning a thenable in a then handler +store.run(data, () => { + assert.strictEqual(store.getStore(), data); + Promise.resolve().then(() => thenable()); + assert.strictEqual(store.getStore(), data); +});