chromium/v8/src/objects/js-atomics-synchronization.cc

// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/objects/js-atomics-synchronization.h"

#include "src/base/macros.h"
#include "src/base/platform/yield-processor.h"
#include "src/execution/isolate-inl.h"
#include "src/objects/js-atomics-synchronization-inl.h"
#include "src/objects/js-promise-inl.h"
#include "src/objects/waiter-queue-node.h"
#include "src/sandbox/external-pointer-inl.h"

namespace v8 {
namespace internal {

namespace detail {
class WaiterQueueNode;
}

namespace {

// TODO(v8:12547): Move this logic into a static method JSPromise::PerformThen
// so that other callsites like this one can use it.
// Set fulfill/reject handlers for a JSPromise object.
MaybeHandle<JSReceiver> PerformPromiseThen(
    Isolate* isolate, Handle<JSReceiver> promise,
    Handle<Object> fulfill_handler,
    MaybeHandle<JSFunction> maybe_reject_handler = MaybeHandle<JSFunction>()) {}

MaybeHandle<Context> SetAsyncUnlockHandlers(
    Isolate* isolate, DirectHandle<JSAtomicsMutex> mutex,
    Handle<JSReceiver> waiting_for_callback_promise,
    DirectHandle<JSPromise> unlocked_promise) {}

void AddPromiseToNativeContext(Isolate* isolate,
                               DirectHandle<JSPromise> promise) {}

void RemovePromiseFromNativeContext(Isolate* isolate,
                                    DirectHandle<JSPromise> promise) {}

template <typename T>
Global<T> GetWeakGlobal(Isolate* isolate, Local<T> object) {}

}  // namespace

namespace detail {

// The waiter queue lock guard provides a RAII-style mechanism for locking the
// waiter queue. It is a non copyable and non movable object and a new state
// must be set before destroying the guard.
class V8_NODISCARD WaiterQueueLockGuard final {};

class V8_NODISCARD SyncWaiterQueueNode final : public WaiterQueueNode {};

template <typename T>
class AsyncWaiterNotifyTask : public CancelableTask {};
template <typename T>
class AsyncWaiterTimeoutTask : public CancelableTask {};

template <typename T>
class V8_NODISCARD AsyncWaiterQueueNode final : public WaiterQueueNode {};
}  // namespace detail

SyncWaiterQueueNode;
LockAsyncWaiterQueueNode;
WaitAsyncWaiterQueueNode;
AsyncWaitTimeoutTask;
AsyncLockTimeoutTask;

// static
void JSSynchronizationPrimitive::IsolateDeinit(Isolate* isolate) {}

void JSSynchronizationPrimitive::CleanupAsyncWaiterLists(
    Isolate* isolate, DequeueMatcher matcher) {}

// static
bool JSSynchronizationPrimitive::TryLockWaiterQueueExplicit(
    std::atomic<StateT>* state, StateT& expected) {}

// static
void JSSynchronizationPrimitive::SetWaiterQueueStateOnly(
    std::atomic<StateT>* state, StateT new_state) {}

Tagged<Object> JSSynchronizationPrimitive::NumWaitersForTesting(
    Isolate* requester) {}

// TODO(lpardosixtos): Consider making and caching a canonical map for this
// result object, like we do for the iterator result object.
// static
Handle<JSObject> JSAtomicsMutex::CreateResultObject(Isolate* isolate,
                                                    DirectHandle<Object> value,
                                                    bool success) {}

// static
void JSAtomicsMutex::CleanupMatchingAsyncWaiters(Isolate* isolate,
                                                 WaiterQueueNode* node,
                                                 DequeueMatcher matcher) {}

// static
bool JSAtomicsMutex::TryLockExplicit(std::atomic<StateT>* state,
                                     StateT& expected) {}

bool JSAtomicsMutex::BackoffTryLock(Isolate* requester,
                                    DirectHandle<JSAtomicsMutex> mutex,
                                    std::atomic<StateT>* state) {}

bool JSAtomicsMutex::MaybeEnqueueNode(Isolate* requester,
                                      DirectHandle<JSAtomicsMutex> mutex,
                                      std::atomic<StateT>* state,
                                      WaiterQueueNode* this_waiter) {}

// static
std::optional<WaiterQueueLockGuard> JSAtomicsMutex::LockWaiterQueueOrJSMutex(
    std::atomic<StateT>* state, StateT& current_state) {}

bool JSAtomicsMutex::LockJSMutexOrDequeueTimedOutWaiter(
    Isolate* requester, std::atomic<StateT>* state,
    WaiterQueueNode* timed_out_waiter) {}

// static
bool JSAtomicsMutex::LockSlowPath(Isolate* requester,
                                  DirectHandle<JSAtomicsMutex> mutex,
                                  std::atomic<StateT>* state,
                                  std::optional<base::TimeDelta> timeout) {}

void JSAtomicsMutex::UnlockSlowPath(Isolate* requester,
                                    std::atomic<StateT>* state) {}

// The lockAsync flow is controlled by a series of promises:
// 1. `internal_locked_promise`, a promise that settles when the mutex is
//    locked. When this promise is resolved, the callback is run. Not exposed to
//    user code.
// 2. `waiting_for_callback_promise`, a promise that settles when the callback
//    completes. When this promise settles, the mutex is unlocked
// 3. `unlocked_promise`, a promise that settles when the mutex is unlocked,
//    either explicitly or by timeout. Returned by lockAsync.
// static
MaybeHandle<JSPromise> JSAtomicsMutex::LockOrEnqueuePromise(
    Isolate* requester, Handle<JSAtomicsMutex> mutex, Handle<Object> callback,
    std::optional<base::TimeDelta> timeout) {}

// static
bool JSAtomicsMutex::LockAsync(Isolate* requester, Handle<JSAtomicsMutex> mutex,
                               Handle<JSPromise> internal_locked_promise,
                               MaybeHandle<JSPromise> unlocked_promise,
                               LockAsyncWaiterQueueNode** waiter_node,
                               std::optional<base::TimeDelta> timeout) {}

// static
Handle<JSPromise> JSAtomicsMutex::LockAsyncWrapperForWait(
    Isolate* requester, Handle<JSAtomicsMutex> mutex) {}

// static
bool JSAtomicsMutex::LockAsyncSlowPath(
    Isolate* isolate, Handle<JSAtomicsMutex> mutex, std::atomic<StateT>* state,
    Handle<JSPromise> internal_locked_promise,
    MaybeHandle<JSPromise> unlocked_promise,
    LockAsyncWaiterQueueNode** waiter_node,
    std::optional<base::TimeDelta> timeout) {}

// static
bool JSAtomicsMutex::LockOrEnqueueAsyncNode(Isolate* isolate,
                                            DirectHandle<JSAtomicsMutex> mutex,
                                            LockAsyncWaiterQueueNode* waiter) {}

void JSAtomicsMutex::UnlockAsyncLockedMutex(
    Isolate* requester, DirectHandle<Foreign> async_locked_waiter_wrapper) {}

bool JSAtomicsMutex::DequeueTimedOutAsyncWaiter(
    Isolate* requester, DirectHandle<JSAtomicsMutex> mutex,
    std::atomic<StateT>* state, WaiterQueueNode* timed_out_waiter) {}

// static
void JSAtomicsMutex::HandleAsyncTimeout(LockAsyncWaiterQueueNode* waiter) {}

// static
void JSAtomicsMutex::HandleAsyncNotify(LockAsyncWaiterQueueNode* waiter) {}

// static
void JSAtomicsCondition::CleanupMatchingAsyncWaiters(Isolate* isolate,
                                                     WaiterQueueNode* node,
                                                     DequeueMatcher matcher) {}

// static
void JSAtomicsCondition::QueueWaiter(Isolate* requester,
                                     DirectHandle<JSAtomicsCondition> cv,
                                     WaiterQueueNode* waiter) {}

// static
bool JSAtomicsCondition::WaitFor(Isolate* requester,
                                 DirectHandle<JSAtomicsCondition> cv,
                                 Handle<JSAtomicsMutex> mutex,
                                 std::optional<base::TimeDelta> timeout) {}

// static
uint32_t JSAtomicsCondition::DequeueExplicit(
    Isolate* requester, DirectHandle<JSAtomicsCondition> cv,
    std::atomic<StateT>* state, const DequeueAction& action_under_lock) {}

// static
uint32_t JSAtomicsCondition::Notify(Isolate* requester,
                                    DirectHandle<JSAtomicsCondition> cv,
                                    uint32_t count) {}

// The lockAsync flow is controlled 2 chained promises, with lock_promise being
// the return value of the API.
// 1. `internal_waiting_promise`, which will be resolved either in the notify
// task or in the
//    timeout task.
// 2. `lock_promise`, which will be resolved when the lock is acquired after
//    waiting.
// static
MaybeHandle<JSReceiver> JSAtomicsCondition::WaitAsync(
    Isolate* requester, Handle<JSAtomicsCondition> cv,
    DirectHandle<JSAtomicsMutex> mutex,
    std::optional<base::TimeDelta> timeout) {}

// static
void JSAtomicsCondition::HandleAsyncTimeout(WaitAsyncWaiterQueueNode* waiter) {}

// static
void JSAtomicsCondition::HandleAsyncNotify(WaitAsyncWaiterQueueNode* waiter) {}

}  // namespace internal
}  // namespace v8