summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins
diff options
context:
space:
mode:
authorStephen Belanger <stephen.belanger@datadoghq.com>2021-04-20 18:10:05 -0700
committerStephen Belanger <stephen.belanger@datadoghq.com>2021-05-06 15:17:35 -0700
commit50dd62ed96e745a087c9289a76721e5f5e0fecbb (patch)
tree6b52857a9e737dc9cc6304bd2c44e7c61ad18c9d /deps/v8/src/builtins
parent2465062c45bb73025ecf06f475339bcf6e783de2 (diff)
downloadnode-new-50dd62ed96e745a087c9289a76721e5f5e0fecbb.tar.gz
deps: V8: backport 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: https://github.com/v8/v8/commit/c0fceaa0669b39136c9e780f278e2596d71b4e8a PR-URL: https://github.com/nodejs/node/pull/36394 Reviewed-By: Bryan English <bryan@bryanenglish.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Vladimir de Turckheim <vlad2t@hotmail.com> Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de> Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'deps/v8/src/builtins')
-rw-r--r--deps/v8/src/builtins/builtins-async-function-gen.cc4
-rw-r--r--deps/v8/src/builtins/builtins-async-gen.cc62
-rw-r--r--deps/v8/src/builtins/builtins-async-gen.h6
-rw-r--r--deps/v8/src/builtins/builtins-async-generator-gen.cc2
-rw-r--r--deps/v8/src/builtins/builtins-microtask-queue-gen.cc62
-rw-r--r--deps/v8/src/builtins/cast.tq6
-rw-r--r--deps/v8/src/builtins/promise-abstract-operations.tq15
-rw-r--r--deps/v8/src/builtins/promise-all.tq2
-rw-r--r--deps/v8/src/builtins/promise-constructor.tq7
-rw-r--r--deps/v8/src/builtins/promise-jobs.tq2
-rw-r--r--deps/v8/src/builtins/promise-misc.tq122
-rw-r--r--deps/v8/src/builtins/promise-resolve.tq2
12 files changed, 238 insertions, 54 deletions
diff --git a/deps/v8/src/builtins/builtins-async-function-gen.cc b/deps/v8/src/builtins/builtins-async-function-gen.cc
index 49b00caa04..1644997ed0 100644
--- a/deps/v8/src/builtins/builtins-async-function-gen.cc
+++ b/deps/v8/src/builtins/builtins-async-function-gen.cc
@@ -157,12 +157,14 @@ TF_BUILTIN(AsyncFunctionEnter, AsyncFunctionBuiltinsAssembler) {
StoreObjectFieldNoWriteBarrier(
async_function_object, JSAsyncFunctionObject::kPromiseOffset, promise);
+ RunContextPromiseHookInit(context, promise, UndefinedConstant());
+
// Fire promise hooks if enabled and push the Promise under construction
// in an async function on the catch prediction stack to handle exceptions
// thrown before the first await.
Label if_instrumentation(this, Label::kDeferred),
if_instrumentation_done(this);
- Branch(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
+ Branch(IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
&if_instrumentation, &if_instrumentation_done);
BIND(&if_instrumentation);
{
diff --git a/deps/v8/src/builtins/builtins-async-gen.cc b/deps/v8/src/builtins/builtins-async-gen.cc
index fa05e9b32a..1a660abece 100644
--- a/deps/v8/src/builtins/builtins-async-gen.cc
+++ b/deps/v8/src/builtins/builtins-async-gen.cc
@@ -99,18 +99,11 @@ TNode<Object> AsyncBuiltinsAssembler::AwaitOld(
TVARIABLE(HeapObject, var_throwaway, UndefinedConstant());
- // Deal with PromiseHooks and debug support in the runtime. This
- // also allocates the throwaway promise, which is only needed in
- // case of PromiseHooks or debugging.
- Label if_debugging(this, Label::kDeferred), do_resolve_promise(this);
- Branch(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
- &if_debugging, &do_resolve_promise);
- BIND(&if_debugging);
- var_throwaway =
- CAST(CallRuntime(Runtime::kAwaitPromisesInitOld, context, value, promise,
- outer_promise, on_reject, is_predicted_as_caught));
- Goto(&do_resolve_promise);
- BIND(&do_resolve_promise);
+ RunContextPromiseHookInit(context, promise, outer_promise);
+
+ InitAwaitPromise(Runtime::kAwaitPromisesInitOld, context, value, promise,
+ outer_promise, on_reject, is_predicted_as_caught,
+ &var_throwaway);
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « promise »).
CallBuiltin(Builtins::kResolvePromise, context, promise, value);
@@ -170,21 +163,46 @@ TNode<Object> AsyncBuiltinsAssembler::AwaitOptimized(
TVARIABLE(HeapObject, var_throwaway, UndefinedConstant());
+ InitAwaitPromise(Runtime::kAwaitPromisesInit, context, promise, promise,
+ outer_promise, on_reject, is_predicted_as_caught,
+ &var_throwaway);
+
+ return CallBuiltin(Builtins::kPerformPromiseThen, native_context, promise,
+ on_resolve, on_reject, var_throwaway.value());
+}
+
+void AsyncBuiltinsAssembler::InitAwaitPromise(
+ Runtime::FunctionId id, TNode<Context> context, TNode<Object> value,
+ TNode<Object> promise, TNode<Object> outer_promise,
+ TNode<HeapObject> on_reject, TNode<Oddball> is_predicted_as_caught,
+ TVariable<HeapObject>* var_throwaway) {
// Deal with PromiseHooks and debug support in the runtime. This
// also allocates the throwaway promise, which is only needed in
// case of PromiseHooks or debugging.
- Label if_debugging(this, Label::kDeferred), do_perform_promise_then(this);
- Branch(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(),
- &if_debugging, &do_perform_promise_then);
+ Label if_debugging(this, Label::kDeferred),
+ if_promise_hook(this, Label::kDeferred),
+ not_debugging(this),
+ do_nothing(this);
+ TNode<Uint32T> promiseHookFlags = PromiseHookFlags();
+ Branch(IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(
+ promiseHookFlags), &if_debugging, &not_debugging);
BIND(&if_debugging);
- var_throwaway =
- CAST(CallRuntime(Runtime::kAwaitPromisesInit, context, promise, promise,
+ *var_throwaway =
+ CAST(CallRuntime(id, context, value, promise,
outer_promise, on_reject, is_predicted_as_caught));
- Goto(&do_perform_promise_then);
- BIND(&do_perform_promise_then);
-
- return CallBuiltin(Builtins::kPerformPromiseThen, native_context, promise,
- on_resolve, on_reject, var_throwaway.value());
+ Goto(&do_nothing);
+ BIND(&not_debugging);
+
+ // This call to NewJSPromise is to keep behaviour parity with what happens
+ // in Runtime::kAwaitPromisesInit above if native hooks are set. It will
+ // create a throwaway promise that will trigger an init event and will get
+ // passed into Builtins::kPerformPromiseThen below.
+ Branch(IsContextPromiseHookEnabled(promiseHookFlags), &if_promise_hook,
+ &do_nothing);
+ BIND(&if_promise_hook);
+ *var_throwaway = NewJSPromise(context, promise);
+ Goto(&do_nothing);
+ BIND(&do_nothing);
}
TNode<Object> AsyncBuiltinsAssembler::Await(
diff --git a/deps/v8/src/builtins/builtins-async-gen.h b/deps/v8/src/builtins/builtins-async-gen.h
index 833e78d45d..34b7a0ce1d 100644
--- a/deps/v8/src/builtins/builtins-async-gen.h
+++ b/deps/v8/src/builtins/builtins-async-gen.h
@@ -62,6 +62,12 @@ class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler {
TNode<SharedFunctionInfo> on_resolve_sfi,
TNode<SharedFunctionInfo> on_reject_sfi,
TNode<Oddball> is_predicted_as_caught);
+
+ void InitAwaitPromise(
+ Runtime::FunctionId id, TNode<Context> context, TNode<Object> value,
+ TNode<Object> promise, TNode<Object> outer_promise,
+ TNode<HeapObject> on_reject, TNode<Oddball> is_predicted_as_caught,
+ TVariable<HeapObject>* var_throwaway);
};
} // namespace internal
diff --git a/deps/v8/src/builtins/builtins-async-generator-gen.cc b/deps/v8/src/builtins/builtins-async-generator-gen.cc
index 374b13dd63..5d053063ff 100644
--- a/deps/v8/src/builtins/builtins-async-generator-gen.cc
+++ b/deps/v8/src/builtins/builtins-async-generator-gen.cc
@@ -520,7 +520,7 @@ TF_BUILTIN(AsyncGeneratorResolve, AsyncGeneratorBuiltinsAssembler) {
// the "promiseResolve" hook would not be fired otherwise.
Label if_fast(this), if_slow(this, Label::kDeferred), return_promise(this);
GotoIfForceSlowPath(&if_slow);
- GotoIf(IsPromiseHookEnabled(), &if_slow);
+ GotoIf(IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate(), &if_slow);
Branch(IsPromiseThenProtectorCellInvalid(), &if_slow, &if_fast);
BIND(&if_fast);
diff --git a/deps/v8/src/builtins/builtins-microtask-queue-gen.cc b/deps/v8/src/builtins/builtins-microtask-queue-gen.cc
index 9f16186d13..1ec9e350f6 100644
--- a/deps/v8/src/builtins/builtins-microtask-queue-gen.cc
+++ b/deps/v8/src/builtins/builtins-microtask-queue-gen.cc
@@ -46,8 +46,11 @@ class MicrotaskQueueBuiltinsAssembler : public CodeStubAssembler {
void EnterMicrotaskContext(TNode<Context> native_context);
void RewindEnteredContext(TNode<IntPtrT> saved_entered_context_count);
+ void RunAllPromiseHooks(PromiseHookType type, TNode<Context> context,
+ TNode<HeapObject> promise_or_capability);
void RunPromiseHook(Runtime::FunctionId id, TNode<Context> context,
- TNode<HeapObject> promise_or_capability);
+ TNode<HeapObject> promise_or_capability,
+ TNode<Uint32T> promiseHookFlags);
};
TNode<RawPtrT> MicrotaskQueueBuiltinsAssembler::GetMicrotaskQueue(
@@ -199,7 +202,7 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
const TNode<Object> thenable = LoadObjectField(
microtask, PromiseResolveThenableJobTask::kThenableOffset);
- RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
+ RunAllPromiseHooks(PromiseHookType::kBefore, microtask_context,
CAST(promise_to_resolve));
{
@@ -208,7 +211,7 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
promise_to_resolve, thenable, then);
}
- RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
+ RunAllPromiseHooks(PromiseHookType::kAfter, microtask_context,
CAST(promise_to_resolve));
RewindEnteredContext(saved_entered_context_count);
@@ -243,8 +246,8 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
BIND(&preserved_data_done);
// Run the promise before/debug hook if enabled.
- RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
- promise_or_capability);
+ RunAllPromiseHooks(PromiseHookType::kBefore, microtask_context,
+ promise_or_capability);
{
ScopedExceptionHandler handler(this, &if_exception, &var_exception);
@@ -253,8 +256,8 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
}
// Run the promise after/debug hook if enabled.
- RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
- promise_or_capability);
+ RunAllPromiseHooks(PromiseHookType::kAfter, microtask_context,
+ promise_or_capability);
Label preserved_data_reset_done(this);
GotoIf(IsUndefined(preserved_embedder_data), &preserved_data_reset_done);
@@ -296,8 +299,8 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
BIND(&preserved_data_done);
// Run the promise before/debug hook if enabled.
- RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
- promise_or_capability);
+ RunAllPromiseHooks(PromiseHookType::kBefore, microtask_context,
+ promise_or_capability);
{
ScopedExceptionHandler handler(this, &if_exception, &var_exception);
@@ -306,8 +309,8 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
}
// Run the promise after/debug hook if enabled.
- RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
- promise_or_capability);
+ RunAllPromiseHooks(PromiseHookType::kAfter, microtask_context,
+ promise_or_capability);
Label preserved_data_reset_done(this);
GotoIf(IsUndefined(preserved_embedder_data), &preserved_data_reset_done);
@@ -465,12 +468,43 @@ void MicrotaskQueueBuiltinsAssembler::RewindEnteredContext(
saved_entered_context_count);
}
+void MicrotaskQueueBuiltinsAssembler::RunAllPromiseHooks(
+ PromiseHookType type, TNode<Context> context,
+ TNode<HeapObject> promise_or_capability) {
+ Label hook(this, Label::kDeferred), done_hook(this);
+ TNode<Uint32T> promiseHookFlags = PromiseHookFlags();
+ Branch(IsAnyPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(
+ promiseHookFlags), &hook, &done_hook);
+ BIND(&hook);
+ {
+ switch (type) {
+ case PromiseHookType::kBefore:
+ RunContextPromiseHookBefore(context, promise_or_capability,
+ promiseHookFlags);
+ RunPromiseHook(Runtime::kPromiseHookBefore, context,
+ promise_or_capability, promiseHookFlags);
+ break;
+ case PromiseHookType::kAfter:
+ RunContextPromiseHookAfter(context, promise_or_capability,
+ promiseHookFlags);
+ RunPromiseHook(Runtime::kPromiseHookAfter, context,
+ promise_or_capability, promiseHookFlags);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ Goto(&done_hook);
+ }
+ BIND(&done_hook);
+}
+
void MicrotaskQueueBuiltinsAssembler::RunPromiseHook(
Runtime::FunctionId id, TNode<Context> context,
- TNode<HeapObject> promise_or_capability) {
+ TNode<HeapObject> promise_or_capability,
+ TNode<Uint32T> promiseHookFlags) {
Label hook(this, Label::kDeferred), done_hook(this);
- Branch(IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(), &hook,
- &done_hook);
+ Branch(IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(
+ promiseHookFlags), &hook, &done_hook);
BIND(&hook);
{
// Get to the underlying JSPromise instance.
diff --git a/deps/v8/src/builtins/cast.tq b/deps/v8/src/builtins/cast.tq
index b490055a19..2bec3d86be 100644
--- a/deps/v8/src/builtins/cast.tq
+++ b/deps/v8/src/builtins/cast.tq
@@ -386,6 +386,12 @@ Cast<Undefined|Callable>(o: HeapObject): Undefined|Callable
return HeapObjectToCallable(o) otherwise CastError;
}
+Cast<Undefined|JSFunction>(o: HeapObject): Undefined|JSFunction
+ labels CastError {
+ if (o == Undefined) return Undefined;
+ return Cast<JSFunction>(o) otherwise CastError;
+}
+
macro Cast<T : type extends Symbol>(o: Symbol): T labels CastError;
Cast<PublicSymbol>(s: Symbol): PublicSymbol labels CastError {
if (s.flags.is_private) goto CastError;
diff --git a/deps/v8/src/builtins/promise-abstract-operations.tq b/deps/v8/src/builtins/promise-abstract-operations.tq
index b7a1b571e6..0e435afad9 100644
--- a/deps/v8/src/builtins/promise-abstract-operations.tq
+++ b/deps/v8/src/builtins/promise-abstract-operations.tq
@@ -196,6 +196,8 @@ FulfillPromise(implicit context: Context)(
// Assert: The value of promise.[[PromiseState]] is "pending".
assert(promise.Status() == PromiseState::kPending);
+ RunContextPromiseHookResolve(promise);
+
// 2. Let reactions be promise.[[PromiseFulfillReactions]].
const reactions =
UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result);
@@ -214,17 +216,24 @@ FulfillPromise(implicit context: Context)(
}
extern macro PromiseBuiltinsAssembler::
- IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(): bool;
+ IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(): bool;
+
+extern macro PromiseBuiltinsAssembler::
+ IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(uint32):
+ bool;
// https://tc39.es/ecma262/#sec-rejectpromise
transitioning builtin
RejectPromise(implicit context: Context)(
promise: JSPromise, reason: JSAny, debugEvent: Boolean): JSAny {
+ const promiseHookFlags = PromiseHookFlags();
+
// If promise hook is enabled or the debugger is active, let
// the runtime handle this operation, which greatly reduces
// the complexity here and also avoids a couple of back and
// forth between JavaScript and C++ land.
- if (IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() ||
+ if (IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(
+ promiseHookFlags) ||
!promise.HasHandler()) {
// 7. If promise.[[PromiseIsHandled]] is false, perform
// HostPromiseRejectionTracker(promise, "reject").
@@ -233,6 +242,8 @@ RejectPromise(implicit context: Context)(
return runtime::RejectPromise(promise, reason, debugEvent);
}
+ RunContextPromiseHookResolve(promise, promiseHookFlags);
+
// 2. Let reactions be promise.[[PromiseRejectReactions]].
const reactions =
UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result);
diff --git a/deps/v8/src/builtins/promise-all.tq b/deps/v8/src/builtins/promise-all.tq
index 41dee8b9e7..294c5e911c 100644
--- a/deps/v8/src/builtins/promise-all.tq
+++ b/deps/v8/src/builtins/promise-all.tq
@@ -232,7 +232,7 @@ Reject(Object) {
// PerformPromiseThen), since this is only necessary for DevTools and
// PromiseHooks.
if (promiseResolveFunction != Undefined ||
- IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() ||
+ IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() ||
IsPromiseSpeciesProtectorCellInvalid() || Is<Smi>(nextValue) ||
!IsPromiseThenLookupChainIntact(
nativeContext, UnsafeCast<HeapObject>(nextValue).map)) {
diff --git a/deps/v8/src/builtins/promise-constructor.tq b/deps/v8/src/builtins/promise-constructor.tq
index 3c5a5e560d..b5f7292a77 100644
--- a/deps/v8/src/builtins/promise-constructor.tq
+++ b/deps/v8/src/builtins/promise-constructor.tq
@@ -40,7 +40,8 @@ extern macro ConstructorBuiltinsAssembler::FastNewObject(
Context, JSFunction, JSReceiver): JSObject;
extern macro
-PromiseBuiltinsAssembler::IsPromiseHookEnabledOrHasAsyncEventDelegate(): bool;
+PromiseBuiltinsAssembler::IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate(
+ uint32): bool;
// https://tc39.es/ecma262/#sec-promise-executor
transitioning javascript builtin
@@ -73,9 +74,7 @@ PromiseConstructor(
result = UnsafeCast<JSPromise>(
FastNewObject(context, promiseFun, UnsafeCast<JSReceiver>(newTarget)));
PromiseInit(result);
- if (IsPromiseHookEnabledOrHasAsyncEventDelegate()) {
- runtime::PromiseHookInit(result, Undefined);
- }
+ RunAnyPromiseHookInit(result, Undefined);
}
const isDebugActive = IsDebugActive();
diff --git a/deps/v8/src/builtins/promise-jobs.tq b/deps/v8/src/builtins/promise-jobs.tq
index 80e98f373b..6fa81dcd28 100644
--- a/deps/v8/src/builtins/promise-jobs.tq
+++ b/deps/v8/src/builtins/promise-jobs.tq
@@ -25,7 +25,7 @@ PromiseResolveThenableJob(implicit context: Context)(
const promiseThen = *NativeContextSlot(ContextSlot::PROMISE_THEN_INDEX);
const thenableMap = thenable.map;
if (TaggedEqual(then, promiseThen) && IsJSPromiseMap(thenableMap) &&
- !IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() &&
+ !IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() &&
IsPromiseSpeciesLookupChainIntact(nativeContext, thenableMap)) {
// We know that the {thenable} is a JSPromise, which doesn't require
// any special treatment and that {then} corresponds to the initial
diff --git a/deps/v8/src/builtins/promise-misc.tq b/deps/v8/src/builtins/promise-misc.tq
index 67e5e38687..c6661e3717 100644
--- a/deps/v8/src/builtins/promise-misc.tq
+++ b/deps/v8/src/builtins/promise-misc.tq
@@ -8,6 +8,9 @@
namespace runtime {
extern transitioning runtime
AllowDynamicFunction(implicit context: Context)(JSAny): JSAny;
+
+extern transitioning runtime
+ReportMessageFromMicrotask(implicit context: Context)(JSAny): JSAny;
}
// Unsafe functions that should be used very carefully.
@@ -17,6 +20,12 @@ extern macro PromiseBuiltinsAssembler::ZeroOutEmbedderOffsets(JSPromise): void;
extern macro PromiseBuiltinsAssembler::AllocateJSPromise(Context): HeapObject;
}
+extern macro
+PromiseBuiltinsAssembler::IsContextPromiseHookEnabled(uint32): bool;
+
+extern macro
+PromiseBuiltinsAssembler::PromiseHookFlags(): uint32;
+
namespace promise {
extern macro IsFunctionWithPrototypeSlotMap(Map): bool;
@@ -90,6 +99,110 @@ macro NewPromiseRejectReactionJobTask(implicit context: Context)(
};
}
+@export
+transitioning macro RunContextPromiseHookInit(implicit context: Context)(
+ promise: JSPromise, parent: Object) {
+ const maybeHook = *NativeContextSlot(
+ ContextSlot::PROMISE_HOOK_INIT_FUNCTION_INDEX);
+ if (IsUndefined(maybeHook)) return;
+
+ const hook = Cast<JSFunction>(maybeHook) otherwise unreachable;
+ const parentObject = Is<JSPromise>(parent) ? Cast<JSPromise>(parent)
+ otherwise unreachable: Undefined;
+
+ try {
+ Call(context, hook, Undefined, promise, parentObject);
+ } catch (e) {
+ runtime::ReportMessageFromMicrotask(e);
+ }
+}
+
+@export
+transitioning macro RunContextPromiseHookResolve(implicit context: Context)(
+ promise: JSPromise) {
+ RunContextPromiseHook(
+ ContextSlot::PROMISE_HOOK_RESOLVE_FUNCTION_INDEX, promise,
+ PromiseHookFlags());
+}
+
+@export
+transitioning macro RunContextPromiseHookResolve(implicit context: Context)(
+ promise: JSPromise, flags: uint32) {
+ RunContextPromiseHook(
+ ContextSlot::PROMISE_HOOK_RESOLVE_FUNCTION_INDEX, promise, flags);
+}
+
+@export
+transitioning macro RunContextPromiseHookBefore(implicit context: Context)(
+ promiseOrCapability: JSPromise|PromiseCapability) {
+ RunContextPromiseHook(
+ ContextSlot::PROMISE_HOOK_BEFORE_FUNCTION_INDEX, promiseOrCapability,
+ PromiseHookFlags());
+}
+
+@export
+transitioning macro RunContextPromiseHookBefore(implicit context: Context)(
+ promiseOrCapability: JSPromise|PromiseCapability, flags: uint32) {
+ RunContextPromiseHook(
+ ContextSlot::PROMISE_HOOK_BEFORE_FUNCTION_INDEX, promiseOrCapability,
+ flags);
+}
+
+@export
+transitioning macro RunContextPromiseHookAfter(implicit context: Context)(
+ promiseOrCapability: JSPromise|PromiseCapability) {
+ RunContextPromiseHook(
+ ContextSlot::PROMISE_HOOK_AFTER_FUNCTION_INDEX, promiseOrCapability,
+ PromiseHookFlags());
+}
+
+@export
+transitioning macro RunContextPromiseHookAfter(implicit context: Context)(
+ promiseOrCapability: JSPromise|PromiseCapability, flags: uint32) {
+ RunContextPromiseHook(
+ ContextSlot::PROMISE_HOOK_AFTER_FUNCTION_INDEX, promiseOrCapability,
+ flags);
+}
+
+transitioning macro RunContextPromiseHook(implicit context: Context)(
+ slot: Slot<NativeContext, Undefined|JSFunction>,
+ promiseOrCapability: JSPromise|PromiseCapability, flags: uint32) {
+ if (!IsContextPromiseHookEnabled(flags)) return;
+ const maybeHook = *NativeContextSlot(slot);
+ if (IsUndefined(maybeHook)) return;
+
+ const hook = Cast<JSFunction>(maybeHook) otherwise unreachable;
+
+ let promise: JSPromise;
+ typeswitch (promiseOrCapability) {
+ case (jspromise: JSPromise): {
+ promise = jspromise;
+ }
+ case (capability: PromiseCapability): {
+ promise = Cast<JSPromise>(capability.promise) otherwise return;
+ }
+ }
+
+ try {
+ Call(context, hook, Undefined, promise);
+ } catch (e) {
+ runtime::ReportMessageFromMicrotask(e);
+ }
+}
+
+transitioning macro RunAnyPromiseHookInit(implicit context: Context)(
+ promise: JSPromise, parent: Object) {
+ const promiseHookFlags = PromiseHookFlags();
+ // Fast return if no hooks are set.
+ if (promiseHookFlags == 0) return;
+ if (IsContextPromiseHookEnabled(promiseHookFlags)) {
+ RunContextPromiseHookInit(promise, parent);
+ }
+ if (IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate(promiseHookFlags)) {
+ runtime::PromiseHookInit(promise, parent);
+ }
+}
+
// These allocate and initialize a promise with pending state and
// undefined fields.
//
@@ -100,9 +213,7 @@ transitioning macro NewJSPromise(implicit context: Context)(parent: Object):
JSPromise {
const instance = InnerNewJSPromise();
PromiseInit(instance);
- if (IsPromiseHookEnabledOrHasAsyncEventDelegate()) {
- runtime::PromiseHookInit(instance, parent);
- }
+ RunAnyPromiseHookInit(instance, parent);
return instance;
}
@@ -124,10 +235,7 @@ transitioning macro NewJSPromise(implicit context: Context)(
instance.reactions_or_result = result;
instance.SetStatus(status);
promise_internal::ZeroOutEmbedderOffsets(instance);
-
- if (IsPromiseHookEnabledOrHasAsyncEventDelegate()) {
- runtime::PromiseHookInit(instance, Undefined);
- }
+ RunAnyPromiseHookInit(instance, Undefined);
return instance;
}
diff --git a/deps/v8/src/builtins/promise-resolve.tq b/deps/v8/src/builtins/promise-resolve.tq
index e933dfbae0..3125054e87 100644
--- a/deps/v8/src/builtins/promise-resolve.tq
+++ b/deps/v8/src/builtins/promise-resolve.tq
@@ -97,7 +97,7 @@ ResolvePromise(implicit context: Context)(
// We also let the runtime handle it if promise == resolution.
// We can use pointer comparison here, since the {promise} is guaranteed
// to be a JSPromise inside this function and thus is reference comparable.
- if (IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() ||
+ if (IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() ||
TaggedEqual(promise, resolution))
deferred {
return runtime::ResolvePromise(promise, resolution);