Commit f088491b authored by Marja Hölttä's avatar Marja Hölttä Committed by Commit Bot

Revert "Reland [Atomics.waitAsync] Implement Atomics.waitAsync"

This reverts commit c5845b47.

Reason for revert: Too many tests are flaky

Original change's description:
> Reland [Atomics.waitAsync] Implement Atomics.waitAsync
> 
> Original design doc:
> https://docs.google.com/document/d/1dthXsVHMc1Sd_oYf9a-KZSFOd_a8dUgnt4REAG8YIXA
> 
> Design changes:
> https://docs.google.com/document/d/1aeEGDm1XSqoJkQQKz9F75WqnuAa2caktxGy_O_KpO9Y
> 
> Previous (reverted) version:  https://chromium-review.googlesource.com/c/v8/v8/+/2202981
> 
> Relanding with fix: tests need --noincremental-marking
> 
> TBR=ishell@chromium.org, ulan@chromium.org, syg@chromium.org, ahaas@chromium.org
> 
> Bug: v8:10239
> Change-Id: Id122225d5d2ed67cbeb3269df115c7208a33a281
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2306791
> Reviewed-by: Marja Hölttä <marja@chromium.org>
> Reviewed-by: Andreas Haas <ahaas@chromium.org>
> Commit-Queue: Marja Hölttä <marja@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#68929}

TBR=ulan@chromium.org,marja@chromium.org,ahaas@chromium.org,ishell@chromium.org,syg@chromium.org

Change-Id: If06da737749806982d1fb95811f540d6667543d5
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:10239
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2306799Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68935}
parent cb082a60
......@@ -745,7 +745,6 @@ namespace internal {
CPP(AtomicsNotify) \
CPP(AtomicsIsLockFree) \
CPP(AtomicsWait) \
CPP(AtomicsWaitAsync) \
CPP(AtomicsWake) \
\
/* String */ \
......
......@@ -177,22 +177,25 @@ BUILTIN(AtomicsNotify) {
RETURN_RESULT_OR_FAILURE(isolate, AtomicsWake(isolate, array, index, count));
}
Object DoWait(Isolate* isolate, FutexEmulation::WaitMode mode,
Handle<Object> array, Handle<Object> index, Handle<Object> value,
Handle<Object> timeout) {
// 1. Let buffer be ? ValidateSharedIntegerTypedArray(typedArray, true).
// ES #sec-atomics.wait
// Atomics.wait( typedArray, index, value, timeout )
BUILTIN(AtomicsWait) {
HandleScope scope(isolate);
Handle<Object> array = args.atOrUndefined(isolate, 1);
Handle<Object> index = args.atOrUndefined(isolate, 2);
Handle<Object> value = args.atOrUndefined(isolate, 3);
Handle<Object> timeout = args.atOrUndefined(isolate, 4);
Handle<JSTypedArray> sta;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true));
// 2. Let i be ? ValidateAtomicAccess(typedArray, index).
Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
size_t i = maybe_index.FromJust();
// 3. Let arrayTypeName be typedArray.[[TypedArrayName]].
// 4. If arrayTypeName is "BigInt64Array", let v be ? ToBigInt64(value).
// 5. Otherwise, let v be ? ToInt32(value).
// According to the spec, we have to check value's type before
// looking at the timeout.
if (sta->type() == kExternalBigInt64Array) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
BigInt::FromObject(isolate, value));
......@@ -202,8 +205,6 @@ Object DoWait(Isolate* isolate, FutexEmulation::WaitMode mode,
Object::ToInt32(isolate, value));
}
// 6. Let q be ? ToNumber(timeout).
// 7. If q is NaN, let t be +∞, else let t be max(q, 0).
double timeout_number;
if (timeout->IsUndefined(isolate)) {
timeout_number = ReadOnlyRoots(isolate).infinity_value().Number();
......@@ -217,11 +218,7 @@ Object DoWait(Isolate* isolate, FutexEmulation::WaitMode mode,
timeout_number = 0;
}
// 8. If mode is sync, then
// a. Let B be AgentCanSuspend().
// b. If B is false, throw a TypeError exception.
if (mode == FutexEmulation::WaitMode::kSync &&
!isolate->allow_atomics_wait()) {
if (!isolate->allow_atomics_wait()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kAtomicsWaitNotAllowed));
}
......@@ -230,39 +227,15 @@ Object DoWait(Isolate* isolate, FutexEmulation::WaitMode mode,
if (sta->type() == kExternalBigInt64Array) {
return FutexEmulation::WaitJs64(
isolate, mode, array_buffer, GetAddress64(i, sta->byte_offset()),
isolate, array_buffer, GetAddress64(i, sta->byte_offset()),
Handle<BigInt>::cast(value)->AsInt64(), timeout_number);
} else {
DCHECK(sta->type() == kExternalInt32Array);
return FutexEmulation::WaitJs32(isolate, mode, array_buffer,
return FutexEmulation::WaitJs32(isolate, array_buffer,
GetAddress32(i, sta->byte_offset()),
NumberToInt32(*value), timeout_number);
}
}
// ES #sec-atomics.wait
// Atomics.wait( typedArray, index, value, timeout )
BUILTIN(AtomicsWait) {
HandleScope scope(isolate);
Handle<Object> array = args.atOrUndefined(isolate, 1);
Handle<Object> index = args.atOrUndefined(isolate, 2);
Handle<Object> value = args.atOrUndefined(isolate, 3);
Handle<Object> timeout = args.atOrUndefined(isolate, 4);
return DoWait(isolate, FutexEmulation::WaitMode::kSync, array, index, value,
timeout);
}
BUILTIN(AtomicsWaitAsync) {
HandleScope scope(isolate);
Handle<Object> array = args.atOrUndefined(isolate, 1);
Handle<Object> index = args.atOrUndefined(isolate, 2);
Handle<Object> value = args.atOrUndefined(isolate, 3);
Handle<Object> timeout = args.atOrUndefined(isolate, 4);
return DoWait(isolate, FutexEmulation::WaitMode::kAsync, array, index, value,
timeout);
}
} // namespace internal
} // namespace v8
......@@ -6,18 +6,15 @@
#include <limits>
#include "src/api/api-inl.h"
#include "src/base/logging.h"
#include "src/base/macros.h"
#include "src/base/platform/time.h"
#include "src/execution/isolate.h"
#include "src/execution/vm-state-inl.h"
#include "src/handles/handles-inl.h"
#include "src/numbers/conversions.h"
#include "src/objects/bigint.h"
#include "src/objects/js-array-buffer-inl.h"
#include "src/objects/js-promise-inl.h"
#include "src/objects/objects-inl.h"
#include "src/tasks/cancelable-task.h"
namespace v8 {
namespace internal {
......@@ -28,22 +25,7 @@ base::LazyMutex FutexEmulation::mutex_ = LAZY_MUTEX_INITIALIZER;
base::LazyInstance<FutexWaitList>::type FutexEmulation::wait_list_ =
LAZY_INSTANCE_INITIALIZER;
FutexWaitListNode::~FutexWaitListNode() {
// Assert that the timeout task was cancelled.
DCHECK_EQ(CancelableTaskManager::kInvalidTaskId, timeout_task_id_);
}
bool FutexWaitListNode::CancelTimeoutTask() {
if (timeout_task_id_ != CancelableTaskManager::kInvalidTaskId) {
auto return_value = cancelable_task_manager_->TryAbort(timeout_task_id_);
timeout_task_id_ = CancelableTaskManager::kInvalidTaskId;
return return_value != TryAbortResult::kTaskRunning;
}
return true;
}
void FutexWaitListNode::NotifyWake() {
DCHECK(!IsAsync());
// Lock the FutexEmulation mutex before notifying. We know that the mutex
// will have been unlocked if we are currently waiting on the condition
// variable. The mutex will not be locked if FutexEmulation::Wait hasn't
......@@ -55,75 +37,10 @@ void FutexWaitListNode::NotifyWake() {
interrupted_ = true;
}
class ResolveAsyncWaiterPromisesTask : public CancelableTask {
public:
ResolveAsyncWaiterPromisesTask(CancelableTaskManager* cancelable_task_manager,
Isolate* isolate)
: CancelableTask(cancelable_task_manager), isolate_(isolate) {}
void RunInternal() override {
FutexEmulation::ResolveAsyncWaiterPromises(isolate_);
}
private:
Isolate* isolate_;
};
class AsyncWaiterTimeoutTask : public CancelableTask {
public:
AsyncWaiterTimeoutTask(CancelableTaskManager* cancelable_task_manager,
FutexWaitListNode* node)
: CancelableTask(cancelable_task_manager), node_(node) {}
void RunInternal() override {
FutexEmulation::HandleAsyncWaiterTimeout(node_);
}
private:
FutexWaitListNode* node_;
};
void FutexEmulation::NotifyAsyncWaiter(FutexWaitListNode* node) {
// This function can run in any thread.
FutexEmulation::mutex_.Pointer()->AssertHeld();
// Nullify the timeout time; this distinguishes timed out waiters from
// woken up ones.
node->async_timeout_time_ = base::TimeTicks();
// Try to cancel the timeout task. If cancelling fails, the task is already
// running. In that case, it cannot proceed beyond waiting for the mutex,
// since we're holding it. When it gets the mutex, it will see that waiting_
// is false, and ignore the FutexWaitListNode.
// Using the CancelableTaskManager here is OK since the Isolate is guaranteed
// to be alive - FutexEmulation::IsolateDeinit removes all FutexWaitListNodes
// owned by an Isolate which is going to die.
node->CancelTimeoutTask();
wait_list_.Pointer()->RemoveNode(node);
// Schedule a task for resolving the Promise.
auto& isolate_map = wait_list_.Pointer()->isolate_promises_to_resolve_;
auto it = isolate_map.find(node->isolate_for_async_waiters_);
if (it == isolate_map.end()) {
// This Isolate doesn't have other Promises to resolve at the moment.
isolate_map.insert(std::make_pair(node->isolate_for_async_waiters_,
FutexWaitList::HeadAndTail{node, node}));
auto task = std::make_unique<ResolveAsyncWaiterPromisesTask>(
node->cancelable_task_manager_, node->isolate_for_async_waiters_);
node->task_runner_->PostNonNestableTask(std::move(task));
} else {
// Add this Node into the existing list.
node->prev_ = it->second.tail;
it->second.tail->next_ = node;
it->second.tail = node;
}
}
FutexWaitList::FutexWaitList() : head_(nullptr), tail_(nullptr) {}
void FutexWaitList::AddNode(FutexWaitListNode* node) {
DCHECK_NULL(node->prev_);
DCHECK_NULL(node->next_);
DCHECK(node->prev_ == nullptr && node->next_ == nullptr);
if (tail_) {
tail_->next_ = node;
} else {
......@@ -131,31 +48,24 @@ void FutexWaitList::AddNode(FutexWaitListNode* node) {
}
node->prev_ = tail_;
node->next_ = nullptr;
tail_ = node;
Verify();
}
void FutexWaitList::RemoveNode(FutexWaitListNode* node) {
DCHECK(NodeIsOnList(node, head_));
if (node->prev_) {
node->prev_->next_ = node->next_;
} else {
DCHECK_EQ(node, head_);
head_ = node->next_;
}
if (node->next_) {
node->next_->prev_ = node->prev_;
} else {
DCHECK_EQ(node, tail_);
tail_ = node->prev_;
}
node->prev_ = node->next_ = nullptr;
Verify();
}
void AtomicsWaitWakeHandle::Wake() {
......@@ -193,19 +103,19 @@ Object WaitJsTranslateReturn(Isolate* isolate, Object res) {
} // namespace
Object FutexEmulation::WaitJs32(Isolate* isolate, WaitMode mode,
Object FutexEmulation::WaitJs32(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer, size_t addr,
int32_t value, double rel_timeout_ms) {
Object res =
Wait<int32_t>(isolate, mode, array_buffer, addr, value, rel_timeout_ms);
Wait<int32_t>(isolate, array_buffer, addr, value, rel_timeout_ms);
return WaitJsTranslateReturn(isolate, res);
}
Object FutexEmulation::WaitJs64(Isolate* isolate, WaitMode mode,
Object FutexEmulation::WaitJs64(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer, size_t addr,
int64_t value, double rel_timeout_ms) {
Object res =
Wait<int64_t>(isolate, mode, array_buffer, addr, value, rel_timeout_ms);
Wait<int64_t>(isolate, array_buffer, addr, value, rel_timeout_ms);
return WaitJsTranslateReturn(isolate, res);
}
......@@ -213,20 +123,20 @@ Object FutexEmulation::WaitWasm32(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer,
size_t addr, int32_t value,
int64_t rel_timeout_ns) {
return Wait<int32_t>(isolate, WaitMode::kSync, array_buffer, addr, value,
rel_timeout_ns >= 0, rel_timeout_ns);
return Wait<int32_t>(isolate, array_buffer, addr, value, rel_timeout_ns >= 0,
rel_timeout_ns);
}
Object FutexEmulation::WaitWasm64(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer,
size_t addr, int64_t value,
int64_t rel_timeout_ns) {
return Wait<int64_t>(isolate, WaitMode::kSync, array_buffer, addr, value,
rel_timeout_ns >= 0, rel_timeout_ns);
return Wait<int64_t>(isolate, array_buffer, addr, value, rel_timeout_ns >= 0,
rel_timeout_ns);
}
template <typename T>
Object FutexEmulation::Wait(Isolate* isolate, WaitMode mode,
Object FutexEmulation::Wait(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer, size_t addr,
T value, double rel_timeout_ms) {
DCHECK_LT(addr, array_buffer->byte_length());
......@@ -247,8 +157,7 @@ Object FutexEmulation::Wait(Isolate* isolate, WaitMode mode,
rel_timeout_ns = static_cast<int64_t>(timeout_ns);
}
}
return Wait(isolate, mode, array_buffer, addr, value, use_timeout,
rel_timeout_ns);
return Wait(isolate, array_buffer, addr, value, use_timeout, rel_timeout_ns);
}
namespace {
......@@ -261,23 +170,9 @@ double WaitTimeoutInMs(double timeout_ns) {
} // namespace
template <typename T>
Object FutexEmulation::Wait(Isolate* isolate, WaitMode mode,
Object FutexEmulation::Wait(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer, size_t addr,
T value, bool use_timeout, int64_t rel_timeout_ns) {
if (mode == WaitMode::kSync) {
return WaitSync(isolate, array_buffer, addr, value, use_timeout,
rel_timeout_ns);
}
DCHECK_EQ(mode, WaitMode::kAsync);
return WaitAsync(isolate, array_buffer, addr, value, use_timeout,
rel_timeout_ns);
}
template <typename T>
Object FutexEmulation::WaitSync(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer, size_t addr,
T value, bool use_timeout,
int64_t rel_timeout_ns) {
VMState<ATOMICS_WAIT> state(isolate);
base::TimeDelta rel_timeout =
base::TimeDelta::FromNanoseconds(rel_timeout_ns);
......@@ -410,119 +305,6 @@ Object FutexEmulation::WaitSync(Isolate* isolate,
return *result;
}
FutexWaitListNode::FutexWaitListNode(
const std::shared_ptr<BackingStore>& backing_store, size_t wait_addr,
Handle<JSObject> promise, Isolate* isolate)
: isolate_for_async_waiters_(isolate),
backing_store_(backing_store),
wait_addr_(wait_addr),
waiting_(true) {
auto v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
task_runner_ = V8::GetCurrentPlatform()->GetForegroundTaskRunner(v8_isolate);
cancelable_task_manager_ = isolate->cancelable_task_manager();
v8::Local<v8::Promise> local_promise = Utils::PromiseToLocal(promise);
promise_.Reset(v8_isolate, local_promise);
promise_.SetWeak();
Handle<NativeContext> native_context(isolate->native_context());
v8::Local<v8::Context> local_native_context =
Utils::ToLocal(Handle<Context>::cast(native_context));
native_context_.Reset(v8_isolate, local_native_context);
native_context_.SetWeak();
// Add the Promise into the NativeContext's atomics_waitasync_promises set, so
// that the list keeps it alive.
Handle<OrderedHashSet> promises(native_context->atomics_waitasync_promises(),
isolate);
promises = OrderedHashSet::Add(isolate, promises, promise).ToHandleChecked();
native_context->set_atomics_waitasync_promises(*promises);
}
template <typename T>
Object FutexEmulation::WaitAsync(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer,
size_t addr, T value, bool use_timeout,
int64_t rel_timeout_ns) {
DCHECK(FLAG_harmony_atomics_waitasync);
base::TimeDelta rel_timeout =
base::TimeDelta::FromNanoseconds(rel_timeout_ns);
Factory* factory = isolate->factory();
Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
std::shared_ptr<BackingStore> backing_store = array_buffer->GetBackingStore();
// 17. Let w be ! AtomicLoad(typedArray, i).
std::atomic<T>* p = reinterpret_cast<std::atomic<T>*>(
static_cast<int8_t*>(backing_store->buffer_start()) + addr);
if (p->load() != value) {
// 18. If v is not equal to w, then
// a. Perform LeaveCriticalSection(WL).
// ...
// c. Perform ! CreateDataPropertyOrThrow(resultObject, "async", false).
// d. Perform ! CreateDataPropertyOrThrow(resultObject, "value",
// "not-equal").
// e. Return resultObject.
CHECK(
JSReceiver::CreateDataProperty(isolate, result, factory->async_string(),
factory->false_value(), Just(kDontThrow))
.FromJust());
CHECK(JSReceiver::CreateDataProperty(
isolate, result, factory->value_string(),
factory->not_equal_string(), Just(kDontThrow))
.FromJust());
return *result;
}
if (use_timeout && rel_timeout_ns == 0) {
// 19. If t is 0 and mode is async, then
// ...
// b. Perform LeaveCriticalSection(WL).
// c. Perform ! CreateDataPropertyOrThrow(resultObject, "async", false).
// d. Perform ! CreateDataPropertyOrThrow(resultObject, "value",
// "timed-out").
// e. Return resultObject.
CHECK(
JSReceiver::CreateDataProperty(isolate, result, factory->async_string(),
factory->false_value(), Just(kDontThrow))
.FromJust());
CHECK(JSReceiver::CreateDataProperty(
isolate, result, factory->value_string(),
factory->timed_out_string(), Just(kDontThrow))
.FromJust());
return *result;
}
Handle<JSObject> promise_capability = factory->NewJSPromise();
FutexWaitListNode* node =
new FutexWaitListNode(backing_store, addr, promise_capability, isolate);
{
base::MutexGuard lock_guard(mutex_.Pointer());
wait_list_.Pointer()->AddNode(node);
}
if (use_timeout) {
node->async_timeout_time_ = base::TimeTicks::Now() + rel_timeout;
auto task = std::make_unique<AsyncWaiterTimeoutTask>(
node->cancelable_task_manager_, node);
node->timeout_task_id_ = task->id();
node->task_runner_->PostNonNestableDelayedTask(std::move(task),
rel_timeout.InSecondsF());
}
// 26. Perform ! CreateDataPropertyOrThrow(resultObject, "async", true).
// 27. Perform ! CreateDataPropertyOrThrow(resultObject, "value",
// promiseCapability.[[Promise]]).
// 28. Return resultObject.
CHECK(JSReceiver::CreateDataProperty(isolate, result, factory->async_string(),
factory->true_value(), Just(kDontThrow))
.FromJust());
CHECK(JSReceiver::CreateDataProperty(isolate, result, factory->value_string(),
promise_capability, Just(kDontThrow))
.FromJust());
return *result;
}
Object FutexEmulation::Wake(Handle<JSArrayBuffer> array_buffer, size_t addr,
uint32_t num_waiters_to_wake) {
DCHECK_LT(addr, array_buffer->byte_length());
......@@ -533,223 +315,25 @@ Object FutexEmulation::Wake(Handle<JSArrayBuffer> array_buffer, size_t addr,
base::MutexGuard lock_guard(mutex_.Pointer());
FutexWaitListNode* node = wait_list_.Pointer()->head_;
while (node && num_waiters_to_wake > 0) {
bool delete_this_node = false;
std::shared_ptr<BackingStore> node_backing_store =
node->backing_store_.lock();
if (!node->waiting_) {
node = node->next_;
continue;
}
DCHECK(node_backing_store);
if (backing_store.get() == node_backing_store.get() &&
addr == node->wait_addr_) {
addr == node->wait_addr_ && node->waiting_) {
node->waiting_ = false;
// Retrieve the next node to iterate before calling NotifyAsyncWaiter,
// since NotifyAsyncWaiter will take the node out of the linked list.
auto old_node = node;
node = node->next_;
if (old_node->IsAsync()) {
NotifyAsyncWaiter(old_node);
} else {
old_node->cond_.NotifyOne();
}
node->cond_.NotifyOne();
if (num_waiters_to_wake != kWakeAll) {
--num_waiters_to_wake;
}
waiters_woken++;
continue;
}
if (node_backing_store.get() == nullptr &&
node->async_timeout_time_ == base::TimeTicks()) {
// Backing store has been deleted and the node is still waiting, and
// there's no timeout. It's never going to be woken up, so we can clean
// it up now. We don't need to cancel the timeout task, because there is
// none.
DCHECK(node->IsAsync());
DCHECK_EQ(CancelableTaskManager::kInvalidTaskId, node->timeout_task_id_);
delete_this_node = true;
} else if (node->IsAsync() && node->native_context_.IsEmpty()) {
// The NativeContext related to the async waiter has been deleted.
// Ditto, clean up now.
// Using the CancelableTaskManager here is OK since the Isolate is
// guaranteed to be alive - FutexEmulation::IsolateDeinit removes all
// FutexWaitListNodes owned by an Isolate which is going to die.
if (node->CancelTimeoutTask()) {
delete_this_node = true;
}
// If cancelling the timeout task failed, the timeout task is already
// running and will clean up the node.
}
if (delete_this_node) {
auto old_node = node;
node = node->next_;
wait_list_.Pointer()->RemoveNode(old_node);
delete old_node;
} else {
node = node->next_;
}
node = node->next_;
}
return Smi::FromInt(waiters_woken);
}
void FutexEmulation::CleanupAsyncWaiterPromise(FutexWaitListNode* node) {
DCHECK(FLAG_harmony_atomics_waitasync);
DCHECK(node->IsAsync());
Isolate* isolate = node->isolate_for_async_waiters_;
auto v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
// This function must run in the main thread of node's Isolate.
DCHECK_EQ(isolate->thread_id(), ThreadId::Current());
if (!node->promise_.IsEmpty()) {
Handle<JSPromise> promise = Handle<JSPromise>::cast(
Utils::OpenHandle(*node->promise_.Get(v8_isolate)));
// Promise keeps the NativeContext alive.
DCHECK(!node->native_context_.IsEmpty());
Handle<NativeContext> native_context = Handle<NativeContext>::cast(
Utils::OpenHandle(*node->native_context_.Get(v8_isolate)));
// Remove the Promise from the NativeContext's set.
Handle<OrderedHashSet> promises(
native_context->atomics_waitasync_promises(), isolate);
bool was_deleted = OrderedHashSet::Delete(isolate, *promises, *promise);
DCHECK(was_deleted);
USE(was_deleted);
promises = OrderedHashSet::Shrink(isolate, promises);
native_context->set_atomics_waitasync_promises(*promises);
} else {
// NativeContext keeps the Promise alive; if the Promise is dead then
// surely NativeContext is too.
DCHECK(node->native_context_.IsEmpty());
}
}
FutexWaitListNode* FutexEmulation::DeleteAsyncWaiterNode(
FutexWaitListNode* node) {
auto next = node->next_;
delete node;
return next;
}
void FutexEmulation::ResolveAsyncWaiterPromise(FutexWaitListNode* node) {
DCHECK(FLAG_harmony_atomics_waitasync);
// This function must run in the main thread of node's Isolate.
DCHECK_EQ(node->isolate_for_async_waiters_->thread_id(), ThreadId::Current());
auto v8_isolate =
reinterpret_cast<v8::Isolate*>(node->isolate_for_async_waiters_);
if (!node->promise_.IsEmpty()) {
Handle<JSPromise> promise = Handle<JSPromise>::cast(
Utils::OpenHandle(*node->promise_.Get(v8_isolate)));
Handle<String> result_string;
// When waiters are notified, their async_timeout_time_ is reset. Having a
// non-zero async_timeout_time_ here means the waiter timed out.
if (node->async_timeout_time_ != base::TimeTicks()) {
DCHECK(node->waiting_);
result_string =
node->isolate_for_async_waiters_->factory()->timed_out_string();
} else {
DCHECK(!node->waiting_);
result_string = node->isolate_for_async_waiters_->factory()->ok_string();
}
MaybeHandle<Object> resolve_result =
JSPromise::Resolve(promise, result_string);
DCHECK(!resolve_result.is_null());
USE(resolve_result);
}
}
void FutexEmulation::ResolveAsyncWaiterPromises(Isolate* isolate) {
DCHECK(FLAG_harmony_atomics_waitasync);
// This function must run in the main thread of isolate.
DCHECK_EQ(isolate->thread_id(), ThreadId::Current());
base::MutexGuard lock_guard(mutex_.Pointer());
FutexWaitListNode* node;
{
auto& isolate_map = wait_list_.Pointer()->isolate_promises_to_resolve_;
auto it = isolate_map.find(isolate);
DCHECK_NE(isolate_map.end(), it);
node = it->second.head;
isolate_map.erase(it);
}
HandleScope handle_scope(isolate);
while (node) {
DCHECK_EQ(isolate, node->isolate_for_async_waiters_);
DCHECK(!node->waiting_);
ResolveAsyncWaiterPromise(node);
CleanupAsyncWaiterPromise(node);
// We've already tried to cancel the timeout task for the node; since we're
// now in the same thread the timeout task is supposed to run, we know the
// timeout task will never happen, and it's safe to delete the node here.
DCHECK_EQ(CancelableTaskManager::kInvalidTaskId, node->timeout_task_id_);
node = DeleteAsyncWaiterNode(node);
}
}
void FutexEmulation::HandleAsyncWaiterTimeout(FutexWaitListNode* node) {
DCHECK(FLAG_harmony_atomics_waitasync);
DCHECK(node->IsAsync());
// This function must run in the main thread of node's Isolate.
DCHECK_EQ(node->isolate_for_async_waiters_->thread_id(), ThreadId::Current());
base::MutexGuard lock_guard(mutex_.Pointer());
if (!node->waiting_) {
// If the Node is not waiting, it's already scheduled to have its Promise
// resolved. Ignore the timeout.
return;
}
node->timeout_task_id_ = CancelableTaskManager::kInvalidTaskId;
wait_list_.Pointer()->RemoveNode(node);
HandleScope handle_scope(node->isolate_for_async_waiters_);
ResolveAsyncWaiterPromise(node);
CleanupAsyncWaiterPromise(node);
delete node;
}
void FutexEmulation::IsolateDeinit(Isolate* isolate) {
base::MutexGuard lock_guard(mutex_.Pointer());
FutexWaitListNode* node = wait_list_.Pointer()->head_;
while (node) {
if (node->isolate_for_async_waiters_ == isolate) {
// The Isolate is going away; don't bother cleaning up the Promises in the
// NativeContext. Also we don't need to cancel the timeout task, since it
// will be cancelled by Isolate::Deinit.
node->timeout_task_id_ = CancelableTaskManager::kInvalidTaskId;
wait_list_.Pointer()->RemoveNode(node);
node = DeleteAsyncWaiterNode(node);
} else {
node = node->next_;
}
}
auto& isolate_map = wait_list_.Pointer()->isolate_promises_to_resolve_;
auto it = isolate_map.find(isolate);
if (it != isolate_map.end()) {
node = it->second.head;
while (node) {
DCHECK_EQ(isolate, node->isolate_for_async_waiters_);
node = DeleteAsyncWaiterNode(node);
}
isolate_map.erase(it);
}
wait_list_.Pointer()->Verify();
}
Object FutexEmulation::NumWaitersForTesting(Handle<JSArrayBuffer> array_buffer,
size_t addr) {
DCHECK_LT(addr, array_buffer->byte_length());
......@@ -762,6 +346,7 @@ Object FutexEmulation::NumWaitersForTesting(Handle<JSArrayBuffer> array_buffer,
while (node) {
std::shared_ptr<BackingStore> node_backing_store =
node->backing_store_.lock();
DCHECK(node_backing_store);
if (backing_store.get() == node_backing_store.get() &&
addr == node->wait_addr_ && node->waiting_) {
waiters++;
......@@ -773,103 +358,5 @@ Object FutexEmulation::NumWaitersForTesting(Handle<JSArrayBuffer> array_buffer,
return Smi::FromInt(waiters);
}
Object FutexEmulation::NumAsyncWaitersForTesting(Isolate* isolate) {
base::MutexGuard lock_guard(mutex_.Pointer());
int waiters = 0;
FutexWaitListNode* node = wait_list_.Pointer()->head_;
while (node) {
if (node->isolate_for_async_waiters_ == isolate && node->waiting_) {
waiters++;
}
node = node->next_;
}
return Smi::FromInt(waiters);
}
Object FutexEmulation::NumUnresolvedAsyncPromisesForTesting(
Handle<JSArrayBuffer> array_buffer, size_t addr) {
DCHECK_LT(addr, array_buffer->byte_length());
std::shared_ptr<BackingStore> backing_store = array_buffer->GetBackingStore();
base::MutexGuard lock_guard(mutex_.Pointer());
int waiters = 0;
auto& isolate_map = wait_list_.Pointer()->isolate_promises_to_resolve_;
for (auto it : isolate_map) {
FutexWaitListNode* node = it.second.head;
while (node) {
std::shared_ptr<BackingStore> node_backing_store =
node->backing_store_.lock();
if (backing_store.get() == node_backing_store.get() &&
addr == node->wait_addr_ && !node->waiting_) {
waiters++;
}
node = node->next_;
}
}
return Smi::FromInt(waiters);
}
void FutexWaitList::VerifyNode(FutexWaitListNode* node, FutexWaitListNode* head,
FutexWaitListNode* tail) {
#ifdef DEBUG
if (node->next_) {
DCHECK_NE(node, tail);
DCHECK_EQ(node, node->next_->prev_);
} else {
DCHECK_EQ(node, tail);
}
if (node->prev_) {
DCHECK_NE(node, head);
DCHECK_EQ(node, node->prev_->next_);
} else {
DCHECK_EQ(node, head);
}
if (node->async_timeout_time_ != base::TimeTicks()) {
DCHECK(FLAG_harmony_atomics_waitasync);
DCHECK(node->IsAsync());
}
DCHECK(NodeIsOnList(node, head));
#endif // DEBUG
}
void FutexWaitList::Verify() {
#ifdef DEBUG
FutexWaitListNode* node = head_;
while (node) {
VerifyNode(node, head_, tail_);
node = node->next_;
}
for (auto it : isolate_promises_to_resolve_) {
auto node = it.second.head;
while (node) {
VerifyNode(node, it.second.head, it.second.tail);
DCHECK_EQ(it.first, node->isolate_for_async_waiters_);
node = node->next_;
}
}
#endif // DEBUG
}
bool FutexWaitList::NodeIsOnList(FutexWaitListNode* node,
FutexWaitListNode* head) {
auto n = head;
while (n != nullptr) {
if (n == node) {
return true;
}
n = n->next_;
}
return false;
}
} // namespace internal
} // namespace v8
......@@ -7,16 +7,11 @@
#include <stdint.h>
#include <map>
#include "include/v8.h"
#include "src/base/atomicops.h"
#include "src/base/lazy-instance.h"
#include "src/base/macros.h"
#include "src/base/platform/condition-variable.h"
#include "src/base/platform/mutex.h"
#include "src/base/platform/time.h"
#include "src/tasks/cancelable-task.h"
#include "src/utils/allocation.h"
// Support for emulating futexes, a low-level synchronization primitive. They
......@@ -55,93 +50,47 @@ class AtomicsWaitWakeHandle {
class FutexWaitListNode {
public:
// Create a sync FutexWaitListNode.
FutexWaitListNode() = default;
// Create an async FutexWaitListNode.
FutexWaitListNode(const std::shared_ptr<BackingStore>& backing_store,
size_t wait_addr, Handle<JSObject> promise_capability,
Isolate* isolate);
~FutexWaitListNode();
FutexWaitListNode()
: prev_(nullptr),
next_(nullptr),
wait_addr_(0),
waiting_(false),
interrupted_(false) {}
void NotifyWake();
bool IsAsync() const { return isolate_for_async_waiters_ != nullptr; }
// Returns false if the cancelling failed, true otherwise.
bool CancelTimeoutTask();
private:
friend class FutexEmulation;
friend class FutexWaitList;
friend class ResetWaitingOnScopeExit;
// Set only for async FutexWaitListNodes.
Isolate* isolate_for_async_waiters_ = nullptr;
std::shared_ptr<TaskRunner> task_runner_;
CancelableTaskManager* cancelable_task_manager_ = nullptr;
base::ConditionVariable cond_;
// prev_ and next_ are protected by FutexEmulation::mutex_.
FutexWaitListNode* prev_ = nullptr;
FutexWaitListNode* next_ = nullptr;
FutexWaitListNode* prev_;
FutexWaitListNode* next_;
std::weak_ptr<BackingStore> backing_store_;
size_t wait_addr_ = 0;
size_t wait_addr_;
// waiting_ and interrupted_ are protected by FutexEmulation::mutex_
// if this node is currently contained in FutexEmulation::wait_list_
// or an AtomicsWaitWakeHandle has access to it.
bool waiting_ = false;
bool interrupted_ = false;
// Only for async FutexWaitListNodes. Weak Global handle. Must not be
// synchronously resolved by a non-owner Isolate.
v8::Global<v8::Promise> promise_;
// Only for async FutexWaitListNodes. Weak Global handle.
v8::Global<v8::Context> native_context_;
// Only for async FutexWaitListNodes. If async_timeout_time_ is
// base::TimeTicks(), this async waiter doesn't have a timeout or has already
// been notified. Values other than base::TimeTicks() are used for async
// waiters with an active timeout.
base::TimeTicks async_timeout_time_;
CancelableTaskManager::Id timeout_task_id_ =
CancelableTaskManager::kInvalidTaskId;
bool waiting_;
bool interrupted_;
DISALLOW_COPY_AND_ASSIGN(FutexWaitListNode);
};
class FutexWaitList {
public:
FutexWaitList() = default;
FutexWaitList();
void AddNode(FutexWaitListNode* node);
void RemoveNode(FutexWaitListNode* node);
// For checking the internal consistency of the FutexWaitList.
void Verify();
// Verifies the local consistency of |node|. If it's the first node of its
// list, it must be |head|, and if it's the last node, it must be |tail|.
void VerifyNode(FutexWaitListNode* node, FutexWaitListNode* head,
FutexWaitListNode* tail);
// Returns true if |node| is on the linked list starting with |head|.
static bool NodeIsOnList(FutexWaitListNode* node, FutexWaitListNode* head);
private:
friend class FutexEmulation;
FutexWaitListNode* head_ = nullptr;
FutexWaitListNode* tail_ = nullptr;
struct HeadAndTail {
FutexWaitListNode* head;
FutexWaitListNode* tail;
};
// Isolate* -> linked list of Nodes which are waiting for their Promises to
// be resolved.
std::map<Isolate*, HeadAndTail> isolate_promises_to_resolve_;
FutexWaitListNode* head_;
FutexWaitListNode* tail_;
DISALLOW_COPY_AND_ASSIGN(FutexWaitList);
};
......@@ -159,8 +108,6 @@ class ResetWaitingOnScopeExit {
class FutexEmulation : public AllStatic {
public:
enum WaitMode { kSync = 0, kAsync };
// Pass to Wake() to wake all waiters.
static const uint32_t kWakeAll = UINT32_MAX;
......@@ -170,14 +117,12 @@ class FutexEmulation : public AllStatic {
// |rel_timeout_ms| can be Infinity.
// If woken, return "ok", otherwise return "timed-out". The initial check and
// the decision to wait happen atomically.
static Object WaitJs32(Isolate* isolate, WaitMode mode,
Handle<JSArrayBuffer> array_buffer, size_t addr,
int32_t value, double rel_timeout_ms);
static Object WaitJs32(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
size_t addr, int32_t value, double rel_timeout_ms);
// An version of WaitJs32 for int64_t values.
static Object WaitJs64(Isolate* isolate, WaitMode mode,
Handle<JSArrayBuffer> array_buffer, size_t addr,
int64_t value, double rel_timeout_ms);
static Object WaitJs64(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
size_t addr, int64_t value, double rel_timeout_ms);
// Same as WaitJs above except it returns 0 (ok), 1 (not equal) and 2 (timed
// out) as expected by Wasm.
......@@ -201,64 +146,23 @@ class FutexEmulation : public AllStatic {
size_t addr,
uint32_t num_waiters_to_wake);
// Called before |isolate| dies. Removes async waiters owned by |isolate|.
static void IsolateDeinit(Isolate* isolate);
// Return the number of threads or async waiters waiting on |addr|. Should
// only be used for testing.
// Return the number of threads waiting on |addr|. Should only be used for
// testing.
static Object NumWaitersForTesting(Handle<JSArrayBuffer> array_buffer,
size_t addr);
// Return the number of async waiters (which belong to |isolate|) waiting.
// Should only be used for testing.
static Object NumAsyncWaitersForTesting(Isolate* isolate);
// Return the number of async waiters which were waiting for |addr| and are
// now waiting for the Promises to be resolved. Should only be used for
// testing.
static Object NumUnresolvedAsyncPromisesForTesting(
Handle<JSArrayBuffer> array_buffer, size_t addr);
private:
friend class FutexWaitListNode;
friend class AtomicsWaitWakeHandle;
friend class ResolveAsyncWaiterPromisesTask;
friend class AsyncWaiterTimeoutTask;
template <typename T>
static Object Wait(Isolate* isolate, WaitMode mode,
Handle<JSArrayBuffer> array_buffer, size_t addr, T value,
double rel_timeout_ms);
template <typename T>
static Object Wait(Isolate* isolate, WaitMode mode,
Handle<JSArrayBuffer> array_buffer, size_t addr, T value,
bool use_timeout, int64_t rel_timeout_ns);
template <typename T>
static Object WaitSync(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
size_t addr, T value, bool use_timeout,
int64_t rel_timeout_ns);
static Object Wait(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
size_t addr, T value, double rel_timeout_ms);
template <typename T>
static Object WaitAsync(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
size_t addr, T value, bool use_timeout,
int64_t rel_timeout_ns);
// Resolve the Promises of the async waiters which belong to |isolate|.
static void ResolveAsyncWaiterPromises(Isolate* isolate);
static void ResolveAsyncWaiterPromise(FutexWaitListNode* node);
static void HandleAsyncWaiterTimeout(FutexWaitListNode* node);
static void NotifyAsyncWaiter(FutexWaitListNode* node);
// Remove the node's Promise from the NativeContext's Promise set.
static void CleanupAsyncWaiterPromise(FutexWaitListNode* node);
// Deletes |node| and returns the next node of its list.
static FutexWaitListNode* DeleteAsyncWaiterNode(FutexWaitListNode* node);
static Object Wait(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
size_t addr, T value, bool use_timeout,
int64_t rel_timeout_ns);
// `mutex_` protects the composition of `wait_list_` (i.e. no elements may be
// added or removed without holding this mutex), as well as the `waiting_`
......
......@@ -2943,8 +2943,6 @@ void Isolate::Deinit() {
}
#endif // V8_OS_WIN64
FutexEmulation::IsolateDeinit(this);
debug()->Unload();
wasm_engine()->DeleteCompileJobsOnIsolate(this);
......
......@@ -223,8 +223,7 @@ DEFINE_IMPLICATION(harmony_weak_refs_with_cleanup_some, harmony_weak_refs)
V(harmony_regexp_sequence, "RegExp Unicode sequence properties") \
V(harmony_weak_refs_with_cleanup_some, \
"harmony weak references with FinalizationRegistry.prototype.cleanupSome") \
V(harmony_regexp_match_indices, "harmony regexp match indices") \
V(harmony_atomics_waitasync, "harmony Atomics.waitAsync")
V(harmony_regexp_match_indices, "harmony regexp match indices")
#ifdef V8_INTL_SUPPORT
#define HARMONY_INPROGRESS(V) \
......
......@@ -55,7 +55,6 @@
#include "src/objects/js-segmenter.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/js-weak-refs.h"
#include "src/objects/ordered-hash-table.h"
#include "src/objects/property-cell.h"
#include "src/objects/slots-inl.h"
#include "src/objects/templates.h"
......@@ -4132,12 +4131,6 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(
#undef EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE
void Genesis::InitializeGlobal_harmony_atomics_waitasync() {
if (!FLAG_harmony_atomics_waitasync) return;
SimpleInstallFunction(isolate(), isolate()->atomics_object(), "waitAsync",
Builtins::kAtomicsWaitAsync, 4, true);
}
void Genesis::InitializeGlobal_harmony_sharedarraybuffer() {
if (!FLAG_harmony_sharedarraybuffer) return;
......@@ -4745,11 +4738,6 @@ bool Genesis::InstallABunchOfRandomThings() {
map->AppendDescriptor(isolate(), &d);
}
}
{
Handle<OrderedHashSet> promises =
OrderedHashSet::Allocate(isolate(), 0).ToHandleChecked();
native_context()->set_atomics_waitasync_promises(*promises);
}
return true;
}
......
......@@ -5,14 +5,14 @@
#ifndef V8_OBJECTS_CONTEXTS_INL_H_
#define V8_OBJECTS_CONTEXTS_INL_H_
#include "src/heap/heap-write-barrier.h"
#include "src/objects/contexts.h"
#include "src/heap/heap-write-barrier.h"
#include "src/objects/dictionary-inl.h"
#include "src/objects/fixed-array-inl.h"
#include "src/objects/js-objects-inl.h"
#include "src/objects/map-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/ordered-hash-table-inl.h"
#include "src/objects/osr-optimized-code-cache-inl.h"
#include "src/objects/regexp-match-info.h"
#include "src/objects/scope-info.h"
......
......@@ -7,7 +7,6 @@
#include "src/objects/fixed-array.h"
#include "src/objects/function-kind.h"
#include "src/objects/ordered-hash-table.h"
#include "src/objects/osr-optimized-code-cache.h"
#include "torque-generated/field-offsets-tq.h"
// Has to be the last include (doesn't have include guards):
......@@ -234,7 +233,6 @@ enum ContextLookupFlags {
slow_object_with_object_prototype_map) \
V(SLOW_TEMPLATE_INSTANTIATIONS_CACHE_INDEX, SimpleNumberDictionary, \
slow_template_instantiations_cache) \
V(ATOMICS_WAITASYNC_PROMISES, OrderedHashSet, atomics_waitasync_promises) \
/* Fast Path Protectors */ \
V(REGEXP_SPECIES_PROTECTOR_INDEX, PropertyCell, regexp_species_protector) \
/* All *_FUNCTION_MAP_INDEX definitions used by Context::FunctionMapIndex */ \
......
......@@ -36,28 +36,6 @@ RUNTIME_FUNCTION(Runtime_AtomicsNumWaitersForTesting) {
return FutexEmulation::NumWaitersForTesting(array_buffer, addr);
}
RUNTIME_FUNCTION(Runtime_AtomicsNumAsyncWaitersForTesting) {
DCHECK_EQ(0, args.length());
return FutexEmulation::NumAsyncWaitersForTesting(isolate);
}
RUNTIME_FUNCTION(Runtime_AtomicsNumUnresolvedAsyncPromisesForTesting) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
CONVERT_SIZE_ARG_CHECKED(index, 1);
CHECK(!sta->WasDetached());
CHECK(sta->GetBuffer()->is_shared());
CHECK_LT(index, sta->length());
CHECK_EQ(sta->type(), kExternalInt32Array);
Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
size_t addr = (index << 2) + sta->byte_offset();
return FutexEmulation::NumUnresolvedAsyncPromisesForTesting(array_buffer,
addr);
}
RUNTIME_FUNCTION(Runtime_SetAllowAtomicsWait) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......
......@@ -51,19 +51,17 @@ namespace internal {
F(TransitionElementsKind, 2, 1) \
F(TransitionElementsKindWithKind, 2, 1)
#define FOR_EACH_INTRINSIC_ATOMICS(F, I) \
F(AtomicsLoad64, 2, 1) \
F(AtomicsStore64, 3, 1) \
F(AtomicsAdd, 3, 1) \
F(AtomicsAnd, 3, 1) \
F(AtomicsCompareExchange, 4, 1) \
F(AtomicsExchange, 3, 1) \
F(AtomicsNumWaitersForTesting, 2, 1) \
F(AtomicsNumAsyncWaitersForTesting, 0, 1) \
F(AtomicsNumUnresolvedAsyncPromisesForTesting, 2, 1) \
F(AtomicsOr, 3, 1) \
F(AtomicsSub, 3, 1) \
F(AtomicsXor, 3, 1) \
#define FOR_EACH_INTRINSIC_ATOMICS(F, I) \
F(AtomicsLoad64, 2, 1) \
F(AtomicsStore64, 3, 1) \
F(AtomicsAdd, 3, 1) \
F(AtomicsAnd, 3, 1) \
F(AtomicsCompareExchange, 4, 1) \
F(AtomicsExchange, 3, 1) \
F(AtomicsNumWaitersForTesting, 2, 1) \
F(AtomicsOr, 3, 1) \
F(AtomicsSub, 3, 1) \
F(AtomicsXor, 3, 1) \
F(SetAllowAtomicsWait, 1, 1)
#define FOR_EACH_INTRINSIC_BIGINT(F, I) \
......
......@@ -32,7 +32,6 @@ enum class TryAbortResult { kTaskRemoved, kTaskRunning, kTaskAborted };
class V8_EXPORT_PRIVATE CancelableTaskManager {
public:
using Id = uint64_t;
static constexpr Id kInvalidTaskId = 0;
CancelableTaskManager();
......@@ -69,6 +68,8 @@ class V8_EXPORT_PRIVATE CancelableTaskManager {
bool canceled() const { return canceled_; }
private:
static constexpr Id kInvalidTaskId = 0;
// Only called by {Cancelable} destructor. The task is done with executing,
// but needs to be removed.
void RemoveFinishedTask(Id id);
......
// Copyright 2020 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.
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer --harmony-atomics-waitasync
(function test() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
// Create a waiter with a long timeout.
const result_slow = Atomics.waitAsync(i32a, 0, 0, 200000);
// Create a waiter with a short timeout.
const result_fast = Atomics.waitAsync(i32a, 0, 0, 1);
assertEquals(true, result_slow.async);
assertEquals(true, result_fast.async);
assertEquals(2, %AtomicsNumWaitersForTesting(i32a, 0));
let slow_value = undefined;
result_slow.value.then(
(value) => { slow_value = value; },
() => { assertUnreachable(); });
let fast_value = undefined;
result_fast.value.then(
(value) => { fast_value = value; },
() => { assertUnreachable(); });
// Verify that the waiter with the short time out times out.
let rounds = 1000;
function continuation1() {
--rounds;
assertTrue(rounds > 0);
if (fast_value == undefined) {
setTimeout(continuation1, 0);
} else {
assertEquals("timed-out", fast_value);
// Wake up the waiter with the long time out.
let notify_return_value = Atomics.notify(i32a, 0, 1);
assertEquals(1, notify_return_value);
setTimeout(continuation2, 0);
}
}
function continuation2() {
assertEquals("ok", slow_value);
}
setTimeout(continuation1, 0);
})();
// Copyright 2020 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.
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer --harmony-atomics-waitasync --expose-gc --no-stress-opt --noincremental-marking
(function test() {
let timed_out = false;
(function() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
// Create a waiter with a timeout.
const result = Atomics.waitAsync(i32a, 0, 0, 1);
result.value.then(
(value) => { assertEquals('timed-out', value); timed_out = true; },
() => { assertUnreachable(); });
})();
// Make sure sab, ia32 and result get gc()d.
gc();
assertEquals(1, %AtomicsNumAsyncWaitersForTesting());
// Even if the buffer went out of scope, we keep the waitAsync alive so that it can still time out.
let resolved = false;
const sab2 = new SharedArrayBuffer(16);
const i32a2 = new Int32Array(sab2);
const result2 = Atomics.waitAsync(i32a2, 0, 0);
result2.value.then(
(value) => { assertEquals("ok", value); resolved = true; },
() => { assertUnreachable(); });
assertEquals(2, %AtomicsNumAsyncWaitersForTesting());
const notify_return_value = Atomics.notify(i32a2, 0);
assertEquals(1, notify_return_value);
assertEquals(1, %AtomicsNumAsyncWaitersForTesting());
// Verify that the waiter gets woken up.
let rounds = 1000;
function wait() {
--rounds;
assertTrue(rounds > 0);
if (!timed_out) {
setTimeout(wait, 0);
}
}
setTimeout(wait, 0);
})();
// Copyright 2020 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.
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer --harmony-atomics-waitasync --expose-gc --no-stress-opt --noincremental-marking
(function test() {
(function() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
const result = Atomics.waitAsync(i32a, 0, 0);
result.value.then(
(value) => { assertUnreachable(); },
() => { assertUnreachable(); });
})();
// Make sure sab, ia32 and result get gc()d.
gc();
assertEquals(1, %AtomicsNumAsyncWaitersForTesting());
// The next time iterate the waiter list, we clean up the waiter which can
// never be woken up.
let resolved = false;
const sab2 = new SharedArrayBuffer(16);
const i32a2 = new Int32Array(sab2);
const result2 = Atomics.waitAsync(i32a2, 0, 0);
result2.value.then(
(value) => { assertEquals("ok", value); resolved = true; },
() => { assertUnreachable(); });
assertEquals(2, %AtomicsNumAsyncWaitersForTesting());
const notify_return_value = Atomics.notify(i32a2, 0);
assertEquals(1, notify_return_value);
assertEquals(0, %AtomicsNumAsyncWaitersForTesting());
setTimeout(()=> {
assertTrue(resolved);
}, 0);
})();
// Copyright 2020 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.
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer --harmony-atomics-waitasync --expose-gc --noincremental-marking
(function test() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
let resolved = false;
(function() {
const result = Atomics.waitAsync(i32a, 0, 0);
result.value.then(
(value) => { assertEquals("ok", value); resolved = true; },
() => { assertUnreachable(); });
})();
// Make sure result gets gc()d.
gc();
const notify_return_value = Atomics.notify(i32a, 0, 1);
assertEquals(1, notify_return_value);
assertEquals(0, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(1, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
setTimeout(()=> {
assertTrue(resolved);
assertEquals(0, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
}, 0);
})();
// Copyright 2020 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.
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer --harmony-atomics-waitasync
(function test() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
// Create a waiter with a timeout.
const result = Atomics.waitAsync(i32a, 0, 0, 1);
assertEquals(true, result.async);
assertEquals(1, %AtomicsNumWaitersForTesting(i32a, 0));
let resolved = false;
result.value.then(
(value) => { assertEquals("timed-out", value); resolved = true; },
() => { assertUnreachable(); });
// Verify that the waiter gets woken up.
let rounds = 1000;
function wait() {
--rounds;
assertTrue(rounds > 0);
if (!resolved) {
setTimeout(wait, 0);
}
}
setTimeout(wait, 0);
})();
// Copyright 2020 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.
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer --harmony-atomics-waitasync
(function test() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
const N = 10;
let log = [];
// Create N async waiters; the even ones without timeout and the odd ones
// with timeout.
for (let i = 0; i < N; ++i) {
let result;
if (i % 2 == 0) {
result = Atomics.waitAsync(i32a, 0, 0);
} else {
result = Atomics.waitAsync(i32a, 0, 0, i);
}
assertEquals(true, result.async);
result.value.then(
(value) => { log.push(value + " " + i); },
() => { assertUnreachable(); });
}
assertEquals(N, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(0, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
// Wait until the timed out waiters time out.
let rounds = 10000;
let previous_length = 0;
function wait() {
--rounds;
assertTrue(rounds > 0);
if (log.length > previous_length) {
// Made progress. Give the test more time.
previous_length = log.length;
rounds = 10000;
}
if (log.length < N / 2) {
setTimeout(wait, 0);
} else {
continuation1();
}
}
setTimeout(wait, 0);
function continuation1() {
// Verify that all timed out waiters timed out in FIFO order.
assertEquals(N / 2, log.length);
let waiter_no = 1;
for (let i = 0; i < N / 2; ++i) {
assertEquals("timed-out " + waiter_no, log[i]);
waiter_no += 2;
}
// Wake up all waiters
let notify_return_value = Atomics.notify(i32a, 0);
assertEquals(N / 2, notify_return_value);
assertEquals(0, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(N / 2, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
setTimeout(continuation2, 0);
}
function continuation2() {
// Verify that the waiters woke up in FIFO order.
assertEquals(N, log.length);
let waiter_no = 0;
for (let i = N / 2; i < N; ++i) {
assertEquals("ok " + waiter_no, log[i]);
waiter_no += 2;
}
}
})();
// Copyright 2020 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.
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer --harmony-atomics-waitasync
(function test() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
const N = 10;
let log = [];
// Create N async waiters.
for (let i = 0; i < N; ++i) {
const result = Atomics.waitAsync(i32a, 0, 0);
assertEquals(true, result.async);
result.value.then(
(value) => { assertEquals("ok", value); log.push(i); },
() => { assertUnreachable(); });
}
assertEquals(N, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(0, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
// Wake up all waiters.
let notify_return_value = Atomics.notify(i32a, 0);
assertEquals(N, notify_return_value);
assertEquals(0, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(N, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
function continuation() {
assertEquals(N, log.length);
for (let i = 0; i < N; ++i) {
assertEquals(i, log[i]);
}
}
setTimeout(continuation, 0);
})();
// Copyright 2020 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.
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer --harmony-atomics-waitasync
(function test() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
// Create 2 async waiters.
const result1 = Atomics.waitAsync(i32a, 0, 0);
const result2 = Atomics.waitAsync(i32a, 0, 0);
assertEquals(true, result1.async);
assertEquals(true, result2.async);
assertEquals(2, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(0, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
let log = [];
result1.value.then(
(value) => { assertEquals("ok", value); log.push(1); },
() => { assertUnreachable(); });
result2.value.then(
(value) => { assertEquals("ok", value); log.push(2); },
() => { assertUnreachable(); });
// Wake up one waiter.
const notify_return_value = Atomics.notify(i32a, 0, 1);
assertEquals(1, notify_return_value);
assertEquals(1, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(1, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
function continuation1() {
assertEquals(1, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(0, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
assertEquals([1], log);
// Wake up one waiter.
const notify_return_value = Atomics.notify(i32a, 0, 1);
assertEquals(1, notify_return_value);
assertEquals(0, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(1, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
setTimeout(continuation2, 0);
}
function continuation2() {
assertEquals(0, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(0, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
assertEquals([1, 2], log);
}
setTimeout(continuation1, 0);
})();
// Copyright 2020 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.
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer --harmony-atomics-waitasync
(function test() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
const result = Atomics.waitAsync(i32a, 0, 0);
assertEquals(true, result.async);
assertTrue(result.value instanceof Promise);
assertEquals(1, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(0, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
let resolved = false;
result.value.then(
(value) => { assertEquals("ok", value); resolved = true; },
() => { assertUnreachable(); });
const notify_return_value = Atomics.notify(i32a, 0, 1);
assertEquals(1, notify_return_value);
assertEquals(0, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(1, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
setTimeout(()=> {
assertTrue(resolved);
assertEquals(0, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
}, 0);
})();
// Copyright 2020 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.
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer --harmony-atomics-waitasync --expose-gc --noincremental-marking
(function test() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
(function createWorker() {
const script = `onmessage = function(msg) {
if (msg.sab) {
const i32a = new Int32Array(msg.sab);
const result = Atomics.waitAsync(i32a, 0, 0);
postMessage('worker waiting');
}
}`;
const w = new Worker(script, {type : 'string'});
w.postMessage({sab: sab});
const m = w.getMessage();
assertEquals('worker waiting', m);
w.terminate();
})();
gc();
Atomics.notify(i32a, 0, 1);
})();
// Copyright 2020 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.
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer --harmony-atomics-waitasync --expose-gc --noincremental-marking
(function test() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
(function createWorker() {
const script = `onmessage = function(msg) {
if (msg.sab) {
const i32a = new Int32Array(msg.sab);
const result = Atomics.waitAsync(i32a, 0, 0, 100000);
postMessage('worker waiting');
}
}`;
const w = new Worker(script, {type : 'string'});
w.postMessage({sab: sab});
const m = w.getMessage();
assertEquals('worker waiting', m);
w.terminate();
})();
gc();
Atomics.notify(i32a, 0, 1);
})();
// Copyright 2020 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.
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer --harmony-atomics-waitasync
(function testOutOfBounds() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
assertThrows(() => {
Atomics.waitAsync(i32a, 20, 0, 1000);
}, RangeError);
})();
(function testValueNotEquals() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
const result = Atomics.waitAsync(i32a, 0, 1, 1000);
assertEquals(false, result.async);
assertEquals("not-equal", result.value);
})();
(function testZeroTimeout() {
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
const result = Atomics.waitAsync(i32a, 0, 0, 0);
assertEquals(false, result.async);
assertEquals("timed-out", result.value);
})();
......@@ -849,17 +849,6 @@
# Tier down/up Wasm NativeModule in debugging is non-deterministic with
# multiple isolates (https://crbug.com/v8/10099).
'wasm/tier-down-to-liftoff': [SKIP],
# waitAsync tests modify the global state (across Isolates)
'harmony/atomics-waitasync': [SKIP],
'harmony/atomics-waitasync-1thread-2timeout': [SKIP],
'harmony/atomics-waitasync-1thread-buffer-out-of-scope': [SKIP],
'harmony/atomics-waitasync-1thread-promise-out-of-scope': [SKIP],
'harmony/atomics-waitasync-1thread-timeout': [SKIP],
'harmony/atomics-waitasync-1thread-wake-up-fifo': [SKIP],
'harmony/atomics-waitasync-1thread-wake-up-simple': [SKIP],
'harmony/atomics-waitasync-worker-shutdown-before-wait-finished-timeout': [SKIP],
'harmony/atomics-waitasync-worker-shutdown-before-wait-finished-no-timeout': [SKIP],
}], # 'isolates'
##############################################################################
......
......@@ -533,6 +533,109 @@
# https://bugs.chromium.org/p/v8/issues/detail?id=10383
'built-ins/RegExp/prototype/Symbol.replace/fn-invoke-args-empty-result': [FAIL],
# http://crbug/v8/10239
'built-ins/Atomics/waitAsync/bad-range': [FAIL],
'built-ins/Atomics/waitAsync/bigint/bad-range': [FAIL],
'built-ins/Atomics/waitAsync/bigint/false-for-timeout': [FAIL],
'built-ins/Atomics/waitAsync/bigint/false-for-timeout-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/good-views': [FAIL],
'built-ins/Atomics/waitAsync/bigint/nan-for-timeout-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/negative-index-throws': [FAIL],
'built-ins/Atomics/waitAsync/bigint/negative-timeout': [FAIL],
'built-ins/Atomics/waitAsync/bigint/negative-timeout-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-no-operation': [FAIL],
'built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-add': [FAIL],
'built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-and': [FAIL],
'built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-compareExchange': [FAIL],
'built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-exchange': [FAIL],
'built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-or': [FAIL],
'built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-store': [FAIL],
'built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-sub': [FAIL],
'built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-xor': [FAIL],
'built-ins/Atomics/waitAsync/bigint/non-bigint64-typedarray-throws': [FAIL],
'built-ins/Atomics/waitAsync/bigint/non-shared-bufferdata-throws': [FAIL],
'built-ins/Atomics/waitAsync/bigint/not-a-typedarray-throws': [FAIL],
'built-ins/Atomics/waitAsync/bigint/not-an-object-throws': [FAIL],
'built-ins/Atomics/waitAsync/bigint/null-bufferdata-throws': [FAIL],
'built-ins/Atomics/waitAsync/bigint/null-for-timeout': [FAIL],
'built-ins/Atomics/waitAsync/bigint/null-for-timeout-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/object-for-timeout': [FAIL],
'built-ins/Atomics/waitAsync/bigint/object-for-timeout-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/out-of-range-index-throws': [FAIL],
'built-ins/Atomics/waitAsync/bigint/poisoned-object-for-timeout-throws': [FAIL],
'built-ins/Atomics/waitAsync/bigint/poisoned-object-for-timeout-throws-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/symbol-for-index-throws': [FAIL],
'built-ins/Atomics/waitAsync/bigint/symbol-for-index-throws-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/symbol-for-timeout-throws': [FAIL],
'built-ins/Atomics/waitAsync/bigint/symbol-for-timeout-throws-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/symbol-for-value-throws': [FAIL],
'built-ins/Atomics/waitAsync/bigint/symbol-for-value-throws-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/true-for-timeout': [FAIL],
'built-ins/Atomics/waitAsync/bigint/true-for-timeout-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/undefined-for-timeout': [FAIL],
'built-ins/Atomics/waitAsync/bigint/undefined-for-timeout-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/undefined-index-defaults-to-zero-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/value-not-equal': [FAIL],
'built-ins/Atomics/waitAsync/bigint/value-not-equal-agent': [FAIL],
'built-ins/Atomics/waitAsync/bigint/waiterlist-block-indexedposition-wake': [FAIL],
'built-ins/Atomics/waitAsync/bigint/was-woken-before-timeout': [FAIL],
'built-ins/Atomics/waitAsync/descriptor': [FAIL],
'built-ins/Atomics/waitAsync/false-for-timeout': [FAIL],
'built-ins/Atomics/waitAsync/is-function': [FAIL],
'built-ins/Atomics/waitAsync/length': [FAIL],
'built-ins/Atomics/waitAsync/name': [FAIL],
'built-ins/Atomics/waitAsync/nan-for-timeout-agent': [FAIL],
'built-ins/Atomics/waitAsync/negative-index-throws': [FAIL],
'built-ins/Atomics/waitAsync/negative-timeout': [FAIL],
'built-ins/Atomics/waitAsync/non-int32-typedarray-throws': [FAIL],
'built-ins/Atomics/waitAsync/non-shared-bufferdata-throws': [FAIL],
'built-ins/Atomics/waitAsync/not-a-typedarray-throws': [FAIL],
'built-ins/Atomics/waitAsync/not-an-object-throws': [FAIL],
'built-ins/Atomics/waitAsync/null-bufferdata-throws': [FAIL],
'built-ins/Atomics/waitAsync/null-for-timeout': [FAIL],
'built-ins/Atomics/waitAsync/object-for-timeout': [FAIL],
'built-ins/Atomics/waitAsync/out-of-range-index-throws': [FAIL],
'built-ins/Atomics/waitAsync/poisoned-object-for-timeout-throws': [FAIL],
'built-ins/Atomics/waitAsync/poisoned-object-for-timeout-throws-agent': [FAIL],
'built-ins/Atomics/waitAsync/returns-result-object-value-is-promise-resolves-to-ok': [FAIL],
'built-ins/Atomics/waitAsync/returns-result-object-value-is-promise-resolves-to-timed-out': [FAIL],
'built-ins/Atomics/waitAsync/returns-result-object-value-is-string-not-equal': [FAIL],
'built-ins/Atomics/waitAsync/returns-result-object-value-is-string-timed-out': [FAIL],
'built-ins/Atomics/waitAsync/symbol-for-index-throws': [FAIL],
'built-ins/Atomics/waitAsync/symbol-for-index-throws-agent': [FAIL],
'built-ins/Atomics/waitAsync/symbol-for-timeout-throws': [FAIL],
'built-ins/Atomics/waitAsync/symbol-for-timeout-throws-agent': [FAIL],
'built-ins/Atomics/waitAsync/symbol-for-value-throws': [FAIL],
'built-ins/Atomics/waitAsync/symbol-for-value-throws-agent': [FAIL],
'built-ins/Atomics/waitAsync/true-for-timeout': [FAIL],
'built-ins/Atomics/waitAsync/undefined-for-timeout-agent': [FAIL],
'built-ins/Atomics/waitAsync/undefined-for-timeout': [FAIL],
'built-ins/Atomics/waitAsync/undefined-index-defaults-to-zero-agent': [FAIL],
'built-ins/Atomics/waitAsync/validate-arraytype-before-index-coercion': [FAIL],
'built-ins/Atomics/waitAsync/validate-arraytype-before-timeout-coercion': [FAIL],
'built-ins/Atomics/waitAsync/validate-arraytype-before-value-coercion': [FAIL],
'built-ins/Atomics/waitAsync/value-not-equal': [FAIL],
'built-ins/Atomics/waitAsync/waiterlist-block-indexedposition-wake': [FAIL],
'built-ins/Atomics/waitAsync/was-woken-before-timeout': [FAIL],
# SKIP the following TIMEOUT tests instead of FAIL
'built-ins/Atomics/waitAsync/false-for-timeout-agent': [SKIP],
'built-ins/Atomics/waitAsync/good-views': [SKIP],
'built-ins/Atomics/waitAsync/negative-timeout-agent': [SKIP],
'built-ins/Atomics/waitAsync/no-spurious-wakeup-no-operation': [SKIP],
'built-ins/Atomics/waitAsync/no-spurious-wakeup-on-add': [SKIP],
'built-ins/Atomics/waitAsync/no-spurious-wakeup-on-and': [SKIP],
'built-ins/Atomics/waitAsync/no-spurious-wakeup-on-compareExchange': [SKIP],
'built-ins/Atomics/waitAsync/no-spurious-wakeup-on-exchange': [SKIP],
'built-ins/Atomics/waitAsync/no-spurious-wakeup-on-or': [SKIP],
'built-ins/Atomics/waitAsync/no-spurious-wakeup-on-store': [SKIP],
'built-ins/Atomics/waitAsync/no-spurious-wakeup-on-sub': [SKIP],
'built-ins/Atomics/waitAsync/no-spurious-wakeup-on-xor': [SKIP],
'built-ins/Atomics/waitAsync/null-for-timeout-agent': [SKIP],
'built-ins/Atomics/waitAsync/object-for-timeout-agent': [SKIP],
'built-ins/Atomics/waitAsync/true-for-timeout-agent': [SKIP],
'built-ins/Atomics/waitAsync/value-not-equal-agent': [SKIP],
# https://crbug.com/v8/10687
'built-ins/Atomics/add/bigint/non-shared-bufferdata': [FAIL],
'built-ins/Atomics/add/non-shared-bufferdata': [FAIL],
......
......@@ -65,7 +65,6 @@ FEATURE_FLAGS = {
'AggregateError': '--harmony-promise-any',
'logical-assignment-operators': '--harmony-logical-assignment',
'Promise.any': '--harmony-promise-any',
'Atomics.waitAsync': '--harmony-atomics-waitasync',
}
SKIPPED_FEATURES = set([])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment