Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f56c785

Browse filesBrowse files
committed
deps: V8: cherry-pick c0fceaa0669b
Original commit message: Reland "[api] JSFunction PromiseHook for v8::Context" This is a reland of d5457f5fb7ea05ca05a697599ffa50d35c1ae3c7 after a speculative revert. Additionally it fixes an issue with throwing promise hooks. Original change's description: > [api] JSFunction PromiseHook for v8::Context > > This will enable Node.js to get much better performance from async_hooks > as currently PromiseHook delegates to C++ for the hook function and then > Node.js delegates it right back to JavaScript, introducing several > unnecessary barrier hops in code that gets called very, very frequently > in modern, promise-heavy applications. > > This API mirrors the form of the original C++ function based PromiseHook > API, however it is intentionally separate to allow it to use JSFunctions > triggered within generated code to, as much as possible, avoid entering > runtime functions entirely. > > Because PromiseHook has internal use also, beyond just the Node.js use, > I have opted to leave the existing API intact and keep this separate to > avoid conflicting with any possible behaviour expectations of other API > users. > > The design ideas for this new API stemmed from discussion with some V8 > team members at a previous Node.js Diagnostics Summit hosted by Google > in Munich, and the relevant documentation of the discussion can be found > here: https://docs.google.com/document/d/1g8OrG5lMIUhRn1zbkutgY83MiTSMx-0NHDs8Bf-nXxM/edit#heading=h.w1bavzz80l1e > > A summary of the reasons for why this new design is important can be > found here: https://docs.google.com/document/d/1vtgoT4_kjgOr-Bl605HR2T6_SC-C8uWzYaOPDK5pmRo/edit?usp=sharing > > Bug: v8:11025 > Change-Id: I0b403b00c37d3020b5af07b654b860659d3a7697 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2759188 > Reviewed-by: Marja Hölttä <marja@chromium.org> > Reviewed-by: Camillo Bruni <cbruni@chromium.org> > Reviewed-by: Anton Bikineev <bikineev@chromium.org> > Reviewed-by: Igor Sheludko <ishell@chromium.org> > Commit-Queue: Camillo Bruni <cbruni@chromium.org> > Cr-Commit-Position: refs/heads/master@{#73858} Bug: v8:11025 Bug: chromium:1197475 Change-Id: I73a71e97d9c3dff89a2b092c3fe4adff81ede8ef Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2823917 Reviewed-by: Marja Hölttä <marja@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Reviewed-by: Anton Bikineev <bikineev@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Commit-Queue: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/master@{#74071} Refs: v8/v8@c0fceaa PR-URL: #38273 Backport-PR-URL: #38991 Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Michael Dawson <midawson@redhat.com> Reviewed-By: Mary Marchini <oss@mmarchini.me>
1 parent 7197fce commit f56c785
Copy full SHA for f56c785
Expand file treeCollapse file tree

32 files changed

+782
-131
lines changed
Open diff view settings
Collapse file

‎common.gypi‎

Copy file name to clipboardExpand all lines: common.gypi
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
# Reset this number to 0 on major V8 upgrades.
3838
# Increment by one for each non-official patch applied to deps/v8.
39-
'v8_embedder_string': '-node.8',
39+
'v8_embedder_string': '-node.9',
4040

4141
##### V8 defaults for Node.js #####
4242

Collapse file

‎deps/v8/AUTHORS‎

Copy file name to clipboardExpand all lines: deps/v8/AUTHORS
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ Seo Sanghyeon <sanxiyn@gmail.com>
211211
Shawn Anastasio <shawnanastasio@gmail.com>
212212
Shawn Presser <shawnpresser@gmail.com>
213213
Stefan Penner <stefan.penner@gmail.com>
214+
Stephen Belanger <stephen.belanger@datadoghq.com>
214215
Sylvestre Ledru <sledru@mozilla.com>
215216
Taketoshi Aono <brn@b6n.ch>
216217
Tao Liqiang <taolq@outlook.com>
Collapse file

‎deps/v8/include/v8.h‎

Copy file name to clipboardExpand all lines: deps/v8/include/v8.h
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10585,6 +10585,18 @@ class V8_EXPORT Context : public Data {
1058510585
*/
1058610586
void SetContinuationPreservedEmbedderData(Local<Value> context);
1058710587

10588+
/**
10589+
* Set or clear hooks to be invoked for promise lifecycle operations.
10590+
* To clear a hook, set it to an empty v8::Function. Each function will
10591+
* receive the observed promise as the first argument. If a chaining
10592+
* operation is used on a promise, the init will additionally receive
10593+
* the parent promise as the second argument.
10594+
*/
10595+
void SetPromiseHooks(Local<Function> init_hook,
10596+
Local<Function> before_hook,
10597+
Local<Function> after_hook,
10598+
Local<Function> resolve_hook);
10599+
1058810600
/**
1058910601
* Stack-allocated class which sets the execution context for all
1059010602
* operations executed within a local scope.
Collapse file

‎deps/v8/src/api/api.cc‎

Copy file name to clipboardExpand all lines: deps/v8/src/api/api.cc
+39Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6220,6 +6220,45 @@ void Context::SetContinuationPreservedEmbedderData(Local<Value> data) {
62206220
*i::Handle<i::HeapObject>::cast(Utils::OpenHandle(*data)));
62216221
}
62226222

6223+
void v8::Context::SetPromiseHooks(Local<Function> init_hook,
6224+
Local<Function> before_hook,
6225+
Local<Function> after_hook,
6226+
Local<Function> resolve_hook) {
6227+
i::Handle<i::Context> context = Utils::OpenHandle(this);
6228+
i::Isolate* isolate = context->GetIsolate();
6229+
6230+
i::Handle<i::Object> init = isolate->factory()->undefined_value();
6231+
i::Handle<i::Object> before = isolate->factory()->undefined_value();
6232+
i::Handle<i::Object> after = isolate->factory()->undefined_value();
6233+
i::Handle<i::Object> resolve = isolate->factory()->undefined_value();
6234+
6235+
bool has_hook = false;
6236+
6237+
if (!init_hook.IsEmpty()) {
6238+
init = Utils::OpenHandle(*init_hook);
6239+
has_hook = true;
6240+
}
6241+
if (!before_hook.IsEmpty()) {
6242+
before = Utils::OpenHandle(*before_hook);
6243+
has_hook = true;
6244+
}
6245+
if (!after_hook.IsEmpty()) {
6246+
after = Utils::OpenHandle(*after_hook);
6247+
has_hook = true;
6248+
}
6249+
if (!resolve_hook.IsEmpty()) {
6250+
resolve = Utils::OpenHandle(*resolve_hook);
6251+
has_hook = true;
6252+
}
6253+
6254+
isolate->SetHasContextPromiseHooks(has_hook);
6255+
6256+
context->native_context().set_promise_hook_init_function(*init);
6257+
context->native_context().set_promise_hook_before_function(*before);
6258+
context->native_context().set_promise_hook_after_function(*after);
6259+
context->native_context().set_promise_hook_resolve_function(*resolve);
6260+
}
6261+
62236262
MaybeLocal<Context> metrics::Recorder::GetContext(
62246263
Isolate* isolate, metrics::Recorder::ContextId id) {
62256264
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
Collapse file

‎deps/v8/src/builtins/builtins-async-function-gen.cc‎

Copy file name to clipboardExpand all lines: deps/v8/src/builtins/builtins-async-function-gen.cc
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,14 @@ TF_BUILTIN(AsyncFunctionEnter, AsyncFunctionBuiltinsAssembler) {
157157
StoreObjectFieldNoWriteBarrier(
158158
async_function_object, JSAsyncFunctionObject::kPromiseOffset, promise);
159159

160+
RunContextPromiseHookInit(context, promise, UndefinedConstant());
161+
160162
// Fire promise hooks if enabled and push the Promise under construction
161163
// in an async function on the catch prediction stack to handle exceptions
162164
// thrown before the first await.
163165
Label if_instrumentation(this, Label::kDeferred),
164166
if_instrumentation_done(this);
165-
Branch(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
167+
Branch(IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
166168
&if_instrumentation, &if_instrumentation_done);
167169
BIND(&if_instrumentation);
168170
{
Collapse file

‎deps/v8/src/builtins/builtins-async-gen.cc‎

Copy file name to clipboardExpand all lines: deps/v8/src/builtins/builtins-async-gen.cc
+40-22Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,11 @@ TNode<Object> AsyncBuiltinsAssembler::AwaitOld(
9797

9898
TVARIABLE(HeapObject, var_throwaway, UndefinedConstant());
9999

100-
// Deal with PromiseHooks and debug support in the runtime. This
101-
// also allocates the throwaway promise, which is only needed in
102-
// case of PromiseHooks or debugging.
103-
Label if_debugging(this, Label::kDeferred), do_resolve_promise(this);
104-
Branch(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
105-
&if_debugging, &do_resolve_promise);
106-
BIND(&if_debugging);
107-
var_throwaway =
108-
CAST(CallRuntime(Runtime::kAwaitPromisesInitOld, context, value, promise,
109-
outer_promise, on_reject, is_predicted_as_caught));
110-
Goto(&do_resolve_promise);
111-
BIND(&do_resolve_promise);
100+
RunContextPromiseHookInit(context, promise, outer_promise);
101+
102+
InitAwaitPromise(Runtime::kAwaitPromisesInitOld, context, value, promise,
103+
outer_promise, on_reject, is_predicted_as_caught,
104+
&var_throwaway);
112105

113106
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « promise »).
114107
CallBuiltin(Builtins::kResolvePromise, context, promise, value);
@@ -168,21 +161,46 @@ TNode<Object> AsyncBuiltinsAssembler::AwaitOptimized(
168161

169162
TVARIABLE(HeapObject, var_throwaway, UndefinedConstant());
170163

164+
InitAwaitPromise(Runtime::kAwaitPromisesInit, context, promise, promise,
165+
outer_promise, on_reject, is_predicted_as_caught,
166+
&var_throwaway);
167+
168+
return CallBuiltin(Builtins::kPerformPromiseThen, native_context, promise,
169+
on_resolve, on_reject, var_throwaway.value());
170+
}
171+
172+
void AsyncBuiltinsAssembler::InitAwaitPromise(
173+
Runtime::FunctionId id, TNode<Context> context, TNode<Object> value,
174+
TNode<Object> promise, TNode<Object> outer_promise,
175+
TNode<HeapObject> on_reject, TNode<Oddball> is_predicted_as_caught,
176+
TVariable<HeapObject>* var_throwaway) {
171177
// Deal with PromiseHooks and debug support in the runtime. This
172178
// also allocates the throwaway promise, which is only needed in
173179
// case of PromiseHooks or debugging.
174-
Label if_debugging(this, Label::kDeferred), do_perform_promise_then(this);
175-
Branch(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
176-
&if_debugging, &do_perform_promise_then);
180+
Label if_debugging(this, Label::kDeferred),
181+
if_promise_hook(this, Label::kDeferred),
182+
not_debugging(this),
183+
do_nothing(this);
184+
TNode<Uint32T> promiseHookFlags = PromiseHookFlags();
185+
Branch(IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(
186+
promiseHookFlags), &if_debugging, &not_debugging);
177187
BIND(&if_debugging);
178-
var_throwaway =
179-
CAST(CallRuntime(Runtime::kAwaitPromisesInit, context, promise, promise,
188+
*var_throwaway =
189+
CAST(CallRuntime(id, context, value, promise,
180190
outer_promise, on_reject, is_predicted_as_caught));
181-
Goto(&do_perform_promise_then);
182-
BIND(&do_perform_promise_then);
183-
184-
return CallBuiltin(Builtins::kPerformPromiseThen, native_context, promise,
185-
on_resolve, on_reject, var_throwaway.value());
191+
Goto(&do_nothing);
192+
BIND(&not_debugging);
193+
194+
// This call to NewJSPromise is to keep behaviour parity with what happens
195+
// in Runtime::kAwaitPromisesInit above if native hooks are set. It will
196+
// create a throwaway promise that will trigger an init event and will get
197+
// passed into Builtins::kPerformPromiseThen below.
198+
Branch(IsContextPromiseHookEnabled(promiseHookFlags), &if_promise_hook,
199+
&do_nothing);
200+
BIND(&if_promise_hook);
201+
*var_throwaway = NewJSPromise(context, promise);
202+
Goto(&do_nothing);
203+
BIND(&do_nothing);
186204
}
187205

188206
TNode<Object> AsyncBuiltinsAssembler::Await(
Collapse file

‎deps/v8/src/builtins/builtins-async-gen.h‎

Copy file name to clipboardExpand all lines: deps/v8/src/builtins/builtins-async-gen.h
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler {
6262
TNode<SharedFunctionInfo> on_resolve_sfi,
6363
TNode<SharedFunctionInfo> on_reject_sfi,
6464
TNode<Oddball> is_predicted_as_caught);
65+
66+
void InitAwaitPromise(
67+
Runtime::FunctionId id, TNode<Context> context, TNode<Object> value,
68+
TNode<Object> promise, TNode<Object> outer_promise,
69+
TNode<HeapObject> on_reject, TNode<Oddball> is_predicted_as_caught,
70+
TVariable<HeapObject>* var_throwaway);
6571
};
6672

6773
} // namespace internal
Collapse file

‎deps/v8/src/builtins/builtins-async-generator-gen.cc‎

Copy file name to clipboardExpand all lines: deps/v8/src/builtins/builtins-async-generator-gen.cc
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ TF_BUILTIN(AsyncGeneratorResolve, AsyncGeneratorBuiltinsAssembler) {
518518
// the "promiseResolve" hook would not be fired otherwise.
519519
Label if_fast(this), if_slow(this, Label::kDeferred), return_promise(this);
520520
GotoIfForceSlowPath(&if_slow);
521-
GotoIf(IsPromiseHookEnabled(), &if_slow);
521+
GotoIf(IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate(), &if_slow);
522522
Branch(IsPromiseThenProtectorCellInvalid(), &if_slow, &if_fast);
523523

524524
BIND(&if_fast);
Collapse file

‎deps/v8/src/builtins/builtins-microtask-queue-gen.cc‎

Copy file name to clipboardExpand all lines: deps/v8/src/builtins/builtins-microtask-queue-gen.cc
+48-14Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ class MicrotaskQueueBuiltinsAssembler : public CodeStubAssembler {
4646
void EnterMicrotaskContext(TNode<Context> native_context);
4747
void RewindEnteredContext(TNode<IntPtrT> saved_entered_context_count);
4848

49+
void RunAllPromiseHooks(PromiseHookType type, TNode<Context> context,
50+
TNode<HeapObject> promise_or_capability);
4951
void RunPromiseHook(Runtime::FunctionId id, TNode<Context> context,
50-
TNode<HeapObject> promise_or_capability);
52+
TNode<HeapObject> promise_or_capability,
53+
TNode<Uint32T> promiseHookFlags);
5154
};
5255

5356
TNode<RawPtrT> MicrotaskQueueBuiltinsAssembler::GetMicrotaskQueue(
@@ -199,7 +202,7 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
199202
const TNode<Object> thenable = LoadObjectField(
200203
microtask, PromiseResolveThenableJobTask::kThenableOffset);
201204

202-
RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
205+
RunAllPromiseHooks(PromiseHookType::kBefore, microtask_context,
203206
CAST(promise_to_resolve));
204207

205208
{
@@ -208,7 +211,7 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
208211
promise_to_resolve, thenable, then);
209212
}
210213

211-
RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
214+
RunAllPromiseHooks(PromiseHookType::kAfter, microtask_context,
212215
CAST(promise_to_resolve));
213216

214217
RewindEnteredContext(saved_entered_context_count);
@@ -243,8 +246,8 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
243246
BIND(&preserved_data_done);
244247

245248
// Run the promise before/debug hook if enabled.
246-
RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
247-
promise_or_capability);
249+
RunAllPromiseHooks(PromiseHookType::kBefore, microtask_context,
250+
promise_or_capability);
248251

249252
{
250253
ScopedExceptionHandler handler(this, &if_exception, &var_exception);
@@ -253,8 +256,8 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
253256
}
254257

255258
// Run the promise after/debug hook if enabled.
256-
RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
257-
promise_or_capability);
259+
RunAllPromiseHooks(PromiseHookType::kAfter, microtask_context,
260+
promise_or_capability);
258261

259262
Label preserved_data_reset_done(this);
260263
GotoIf(IsUndefined(preserved_embedder_data), &preserved_data_reset_done);
@@ -296,8 +299,8 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
296299
BIND(&preserved_data_done);
297300

298301
// Run the promise before/debug hook if enabled.
299-
RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
300-
promise_or_capability);
302+
RunAllPromiseHooks(PromiseHookType::kBefore, microtask_context,
303+
promise_or_capability);
301304

302305
{
303306
ScopedExceptionHandler handler(this, &if_exception, &var_exception);
@@ -306,8 +309,8 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
306309
}
307310

308311
// Run the promise after/debug hook if enabled.
309-
RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
310-
promise_or_capability);
312+
RunAllPromiseHooks(PromiseHookType::kAfter, microtask_context,
313+
promise_or_capability);
311314

312315
Label preserved_data_reset_done(this);
313316
GotoIf(IsUndefined(preserved_embedder_data), &preserved_data_reset_done);
@@ -465,12 +468,43 @@ void MicrotaskQueueBuiltinsAssembler::RewindEnteredContext(
465468
saved_entered_context_count);
466469
}
467470

471+
void MicrotaskQueueBuiltinsAssembler::RunAllPromiseHooks(
472+
PromiseHookType type, TNode<Context> context,
473+
TNode<HeapObject> promise_or_capability) {
474+
Label hook(this, Label::kDeferred), done_hook(this);
475+
TNode<Uint32T> promiseHookFlags = PromiseHookFlags();
476+
Branch(IsAnyPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(
477+
promiseHookFlags), &hook, &done_hook);
478+
BIND(&hook);
479+
{
480+
switch (type) {
481+
case PromiseHookType::kBefore:
482+
RunContextPromiseHookBefore(context, promise_or_capability,
483+
promiseHookFlags);
484+
RunPromiseHook(Runtime::kPromiseHookBefore, context,
485+
promise_or_capability, promiseHookFlags);
486+
break;
487+
case PromiseHookType::kAfter:
488+
RunContextPromiseHookAfter(context, promise_or_capability,
489+
promiseHookFlags);
490+
RunPromiseHook(Runtime::kPromiseHookAfter, context,
491+
promise_or_capability, promiseHookFlags);
492+
break;
493+
default:
494+
UNREACHABLE();
495+
}
496+
Goto(&done_hook);
497+
}
498+
BIND(&done_hook);
499+
}
500+
468501
void MicrotaskQueueBuiltinsAssembler::RunPromiseHook(
469502
Runtime::FunctionId id, TNode<Context> context,
470-
TNode<HeapObject> promise_or_capability) {
503+
TNode<HeapObject> promise_or_capability,
504+
TNode<Uint32T> promiseHookFlags) {
471505
Label hook(this, Label::kDeferred), done_hook(this);
472-
Branch(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(), &hook,
473-
&done_hook);
506+
Branch(IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(
507+
promiseHookFlags), &hook, &done_hook);
474508
BIND(&hook);
475509
{
476510
// Get to the underlying JSPromise instance.
Collapse file

‎deps/v8/src/builtins/cast.tq‎

Copy file name to clipboardExpand all lines: deps/v8/src/builtins/cast.tq
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,12 @@ Cast<Undefined|Callable>(o: HeapObject): Undefined|Callable
386386
return HeapObjectToCallable(o) otherwise CastError;
387387
}
388388

389+
Cast<Undefined|JSFunction>(o: HeapObject): Undefined|JSFunction
390+
labels CastError {
391+
if (o == Undefined) return Undefined;
392+
return Cast<JSFunction>(o) otherwise CastError;
393+
}
394+
389395
macro Cast<T : type extends Symbol>(o: Symbol): T labels CastError;
390396
Cast<PublicSymbol>(s: Symbol): PublicSymbol labels CastError {
391397
if (s.flags.is_private) goto CastError;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.