37 DCHECK_LT(addr, array_buffer->GetByteLength());
41 array_buffer->GetBackingStore()->buffer_start());
42 return static_cast<uint8_t*
>(array_buffer->backing_store()) + addr;
50 if (node->prev_ !=
nullptr) {
51 node->prev_->next_ = next;
53 if (next !=
nullptr) {
66 if (node->IsAsync() &&
67 node->async_state_->isolate_for_async_waiters == isolate) {
68 node->async_state_->timeout_task_id =
72 if (new_head ==
nullptr) {
129 auto* cancelable_task_manager =
130 async_state_->isolate_for_async_waiters->cancelable_task_manager();
132 cancelable_task_manager->TryAbort(
async_state_->timeout_task_id);
196 auto it = isolate_map.find(node->async_state_->isolate_for_async_waiters);
197 if (it == isolate_map.end()) {
200 std::make_pair(node->async_state_->isolate_for_async_waiters,
202 auto task = std::make_unique<ResolveAsyncWaiterPromisesTask>(
203 node->async_state_->isolate_for_async_waiters);
204 node->async_state_->task_runner->PostNonNestableTask(std::move(task));
207 node->prev_ = it->second.tail;
208 it->second.tail->next_ =
node;
209 it->second.tail =
node;
216 auto [it, inserted] =
219 it->second.tail->next_ =
node;
220 node->prev_ = it->second.tail;
221 it->second.tail =
node;
228 if (!node->prev_ && !node->next_) {
233 }
else if (node->prev_ && node->next_) {
236 node->prev_->next_ = node->next_;
237 node->next_->prev_ = node->prev_;
238 node->prev_ = node->next_ =
nullptr;
248 node->prev_->next_ =
nullptr;
250 it->second.tail = node->prev_;
251 node->prev_ =
nullptr;
254 it->second.head = node->next_;
256 node->next_->prev_ =
nullptr;
257 node->next_ =
nullptr;
273 return ReadOnlyRoots(isolate).ok_string();
275 return ReadOnlyRoots(isolate).not_equal_string();
277 return ReadOnlyRoots(isolate).timed_out_string();
289 size_t addr, int32_t value,
double rel_timeout_ms) {
291 Wait<int32_t>(isolate, mode, array_buffer, addr, value, rel_timeout_ms);
292 return WaitJsTranslateReturn(isolate, res);
297 size_t addr, int64_t value,
double rel_timeout_ms) {
299 Wait<int64_t>(isolate, mode, array_buffer, addr, value, rel_timeout_ms);
300 return WaitJsTranslateReturn(isolate, res);
305 int32_t value, int64_t rel_timeout_ns) {
312 int64_t value, int64_t rel_timeout_ns) {
320 size_t addr, T value,
321 double rel_timeout_ms) {
322 DCHECK_LT(addr, array_buffer->GetByteLength());
325 int64_t rel_timeout_ns = -1;
329 double timeout_ns = rel_timeout_ms *
332 if (timeout_ns >
static_cast<double>(std::numeric_limits<int64_t>::max())) {
337 rel_timeout_ns =
static_cast<int64_t
>(timeout_ns);
340 return Wait(isolate, mode, array_buffer, addr, value, use_timeout,
347 size_t addr, T value,
bool use_timeout,
348 int64_t rel_timeout_ns,
351 return WaitSync(isolate, array_buffer, addr, value, use_timeout,
352 rel_timeout_ns, call_type);
355 return WaitAsync(isolate, array_buffer, addr, value, use_timeout,
356 rel_timeout_ns, call_type);
362 T value,
bool use_timeout, int64_t rel_timeout_ns,
CallType call_type) {
376 timeout_time = current_time + rel_timeout;
386 std::atomic<T>* p =
reinterpret_cast<std::atomic<T>*
>(wait_location);
387 T loaded_value = p->load();
388#if defined(V8_TARGET_BIG_ENDIAN)
395 if (loaded_value != value) {
401 node->wait_location_ = wait_location;
402 node->waiting_ =
true;
408 node->interrupted_ =
false;
428 isolate->stack_guard()->HandleInterrupts();
432 if (IsException(interrupt_object, isolate)) {
443 if (!node->waiting_) {
452 if (current_time >= timeout_time) {
460 bool wait_for_result =
461 node->cond_.WaitFor(wait_list->
mutex(), time_until_timeout);
462 USE(wait_for_result);
464 node->cond_.Wait(wait_list->
mutex());
470 node->waiting_ =
false;
492 : wait_location_(wait_location),
496 V8::GetCurrentPlatform()->GetForegroundTaskRunner(
497 reinterpret_cast<
v8::
Isolate*>(isolate)),
498 std::move(backing_store),
499 GetWeakGlobal(isolate,
Utils::PromiseToLocal(promise)),
505 T value,
bool use_timeout, int64_t rel_timeout_ns,
CallType call_type) {
509 Factory* factory = isolate->factory();
515 ResultKind result_kind;
519 std::weak_ptr<BackingStore> backing_store{array_buffer->GetBackingStore()};
526 std::atomic<T>* p =
static_cast<std::atomic<T>*
>(wait_location);
527 T loaded_value = p->load();
528#if defined(V8_TARGET_BIG_ENDIAN)
535 if (loaded_value != value) {
536 result_kind = ResultKind::kNotEqual;
537 }
else if (use_timeout && rel_timeout_ns == 0) {
538 result_kind = ResultKind::kTimedOut;
540 result_kind = ResultKind::kAsync;
543 std::move(backing_store), wait_location, promise_capability, isolate);
547 auto task = std::make_unique<AsyncWaiterTimeoutTask>(
548 node->async_state_->isolate_for_async_waiters
549 ->cancelable_task_manager(),
551 node->async_state_->timeout_task_id = task->id();
552 node->async_state_->task_runner->PostNonNestableDelayedTask(
565 switch (result_kind) {
566 case ResultKind::kNotEqual:
574 isolate,
result, factory->async_string(),
578 isolate,
result, factory->value_string(),
583 case ResultKind::kTimedOut:
591 isolate,
result, factory->async_string(),
595 isolate,
result, factory->value_string(),
600 case ResultKind::kAsync:
615 isolate,
result, factory->async_string(), factory->true_value(),
619 factory->value_string(),
629 uint32_t num_waiters_to_wake) {
631 return Wake(wait_location, num_waiters_to_wake);
635 int num_waiters_woken = 0;
640 auto it = location_lists.find(wait_location);
641 if (it == location_lists.end())
return num_waiters_woken;
644 while (node && num_waiters_to_wake > 0) {
645 if (!node->waiting_) {
659 bool matching_backing_store =
660 !node->IsAsync() || !node->async_state_->backing_store.expired();
662 node->waiting_ =
false;
667 if (node->IsAsync()) {
671 node->cond_.NotifyOne();
674 if (num_waiters_to_wake !=
kWakeAll) {
675 --num_waiters_to_wake;
686 bool delete_this_node =
false;
688 if (node->async_state_->timeout_time.IsNull()) {
699 node->async_state_->timeout_task_id);
700 delete_this_node =
true;
702 if (node->async_state_->native_context.IsEmpty()) {
709 if (node->CancelTimeoutTask()) {
710 delete_this_node =
true;
717 if (delete_this_node) {
724 return num_waiters_woken;
733 Isolate* isolate = node->async_state_->isolate_for_async_waiters;
736 if (!node->async_state_->promise.IsEmpty()) {
740 DCHECK(!node->async_state_->native_context.IsEmpty());
742 *node->async_state_->native_context.Get(v8_isolate)));
755 DCHECK(node->async_state_->native_context.IsEmpty());
763 Isolate* isolate = node->async_state_->isolate_for_async_waiters;
773 bool success = node->CancelTimeoutTask();
777 if (!node->async_state_->promise.IsEmpty()) {
778 DCHECK(!node->async_state_->native_context.IsEmpty());
780 node->async_state_->native_context.Get(v8_isolate);
789 result_string = isolate->factory()->timed_out_string();
792 result_string = isolate->factory()->ok_string();
810 auto it = isolate_map.find(isolate);
813 node = it->second.head;
814 isolate_map.erase(it);
824 DCHECK_EQ(isolate, node->async_state_->isolate_for_async_waiters);
832 node->async_state_->timeout_task_id);
847 if (!node->waiting_) {
858 HandleScope handle_scope(node->async_state_->isolate_for_async_waiters);
874 auto it = location_lists.begin();
875 while (it != location_lists.end()) {
880 DCHECK_EQ(head ==
nullptr, tail ==
nullptr);
881 if (head ==
nullptr) {
882 it = location_lists.erase(it);
891 auto it = isolate_map.find(isolate);
892 if (it != isolate_map.end()) {
895 DCHECK_EQ(isolate, node->async_state_->isolate_for_async_waiters);
896 node->async_state_->timeout_task_id =
900 isolate_map.erase(it);
915 auto it = location_lists.find(wait_location);
916 if (it == location_lists.end())
return num_waiters;
919 if (!node->waiting_)
continue;
920 if (node->IsAsync()) {
921 if (node->async_state_->backing_store.expired())
continue;
922 DCHECK_EQ(array_buffer->GetBackingStore(),
923 node->async_state_->backing_store.lock());
939 for (
const auto& it : isolate_map) {
942 if (node->waiting_)
continue;
943 if (wait_location != node->wait_location_)
continue;
944 if (node->async_state_->backing_store.expired())
continue;
945 DCHECK_EQ(array_buffer->GetBackingStore(),
946 node->async_state_->backing_store.lock());
958 if (node->next_ !=
nullptr) {
964 if (node->prev_ !=
nullptr) {
975 auto [head, tail] = head_and_tail;
977 VerifyNode(node, head, tail);
982 auto [head, tail] = head_and_tail;
985 VerifyNode(node, head, tail);
986 DCHECK_EQ(isolate, node->async_state_->isolate_for_async_waiters);
995 if (n == node)
return true;
V8_INLINE void SetWeak(P *parameter, typename WeakCallbackInfo< P >::Callback callback, WeakCallbackType type)
static v8::internal::Handle< To > OpenHandle(v8::Local< From > handle)
static v8::internal::DirectHandle< To > OpenDirectHandle(v8::Local< From > handle)
V8_INLINE void AssertHeld() const
static constexpr int64_t kNanosecondsPerMicrosecond
static constexpr int64_t kMicrosecondsPerMillisecond
static constexpr TimeDelta FromNanoseconds(int64_t nanoseconds)
double InSecondsF() const
int64_t InMicroseconds() const
void RunInternal() override
FutexWaitListNode * node_
AsyncWaiterTimeoutTask(CancelableTaskManager *cancelable_task_manager, FutexWaitListNode *node)
static constexpr Id kInvalidTaskId
Handle< JSObject > NewJSObject(DirectHandle< JSFunction > constructor, AllocationType allocation=AllocationType::kYoung, NewJSObjectType=NewJSObjectType::kNoAPIWrapper)
Handle< JSPromise > NewJSPromise()
static void HandleAsyncWaiterTimeout(FutexWaitListNode *node)
static Tagged< Object > WaitSync(Isolate *isolate, DirectHandle< JSArrayBuffer > array_buffer, size_t addr, T value, bool use_timeout, int64_t rel_timeout_ns, CallType call_type)
static Tagged< Object > Wait(Isolate *isolate, WaitMode mode, DirectHandle< JSArrayBuffer > array_buffer, size_t addr, T value, double rel_timeout_ms)
static int NumUnresolvedAsyncPromisesForTesting(Tagged< JSArrayBuffer > array_buffer, size_t addr)
static int NumWaitersForTesting(Tagged< JSArrayBuffer > array_buffer, size_t addr)
static V8_EXPORT_PRIVATE Tagged< Object > WaitWasm64(Isolate *isolate, DirectHandle< JSArrayBuffer > array_buffer, size_t addr, int64_t value, int64_t rel_timeout_ns)
static const uint32_t kWakeAll
friend class FutexWaitListNode
static void NotifyAsyncWaiter(FutexWaitListNode *node)
static Tagged< Object > WaitAsync(Isolate *isolate, DirectHandle< JSArrayBuffer > array_buffer, size_t addr, T value, bool use_timeout, int64_t rel_timeout_ns, CallType call_type)
static Tagged< Object > WaitJs64(Isolate *isolate, WaitMode mode, DirectHandle< JSArrayBuffer > array_buffer, size_t addr, int64_t value, double rel_timeout_ms)
static Tagged< Object > WaitJs32(Isolate *isolate, WaitMode mode, DirectHandle< JSArrayBuffer > array_buffer, size_t addr, int32_t value, double rel_timeout_ms)
static V8_EXPORT_PRIVATE Tagged< Object > WaitWasm32(Isolate *isolate, DirectHandle< JSArrayBuffer > array_buffer, size_t addr, int32_t value, int64_t rel_timeout_ns)
static void IsolateDeinit(Isolate *isolate)
static void ResolveAsyncWaiterPromise(FutexWaitListNode *node)
static void CleanupAsyncWaiterPromise(FutexWaitListNode *node)
static V8_EXPORT_PRIVATE int Wake(Tagged< JSArrayBuffer > array_buffer, size_t addr, uint32_t num_waiters_to_wake)
static void ResolveAsyncWaiterPromises(Isolate *isolate)
FutexWaitListNode * prev_
base::ConditionVariable cond_
FutexWaitListNode()=default
const std::unique_ptr< AsyncState > async_state_
FutexWaitListNode * next_
void AddNode(FutexWaitListNode *node)
static FutexWaitListNode * DeleteAsyncWaiterNode(FutexWaitListNode *node)
void RemoveNode(FutexWaitListNode *node)
static void DeleteNodesForIsolate(Isolate *isolate, FutexWaitListNode **head, FutexWaitListNode **tail)
static bool NodeIsOnList(FutexWaitListNode *node, FutexWaitListNode *head)
static void * ToWaitLocation(Tagged< JSArrayBuffer > array_buffer, size_t addr)
base::SmallMap< std::map< void *, HeadAndTail >, 16 > location_lists_
FutexWaitList & operator=(const FutexWaitList &)=delete
base::SmallMap< std::map< Isolate *, HeadAndTail > > isolate_promises_to_resolve_
FutexWaitList(const FutexWaitList &)=delete
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > Resolve(DirectHandle< JSPromise > promise, DirectHandle< Object > resolution)
static V8_WARN_UNUSED_RESULT Maybe< bool > CreateDataProperty(Isolate *isolate, DirectHandle< JSReceiver > object, DirectHandle< Name > key, DirectHandle< Object > value, Maybe< ShouldThrow > should_throw)
V8_INLINE bool is_null() const
static HandleType< OrderedHashSet >::MaybeType Add(Isolate *isolate, HandleType< OrderedHashSet > table, DirectHandle< Object > value)
static HandleType< OrderedHashSet > Shrink(Isolate *isolate, HandleType< OrderedHashSet > table)
static bool Delete(Isolate *isolate, Tagged< OrderedHashSet > table, Tagged< Object > key)
void RunInternal() override
ResolveAsyncWaiterPromisesTask(Isolate *isolate)
static constexpr int ToInt(const Tagged< Object > object)
static constexpr Tagged< Smi > FromInt(int value)
ZoneVector< RpoNumber > & result
#define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName,...)
LiftoffAssembler::CacheState state
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
static V ByteReverse(V value)
!IsContextMap !IsContextMap native_context
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
bool ToLocal(v8::internal::MaybeDirectHandle< v8::internal::Object > maybe, Local< T > *local)
Maybe< T > Just(const T &t)
#define DCHECK_NOT_NULL(val)
#define DCHECK_NE(v1, v2)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
#define V8_LIKELY(condition)
#define V8_UNLIKELY(condition)