Commit de5f8614 authored by Shu-yu Guo's avatar Shu-yu Guo Committed by Commit Bot

[atomics] Fix critical section for Atomics.waitAsync

Loading the value at the index for the futex wait should be protected by
the waiterlist mutex for both sync and async waits.

Bug: chromium:1194026
Change-Id: Ie9896cab6828763ebb963f5ad96f264d57c9377f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2796159
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73753}
parent 3fddc150
...@@ -517,13 +517,6 @@ FutexWaitListNode::FutexWaitListNode( ...@@ -517,13 +517,6 @@ FutexWaitListNode::FutexWaitListNode(
Utils::ToLocal(Handle<Context>::cast(native_context)); Utils::ToLocal(Handle<Context>::cast(native_context));
native_context_.Reset(v8_isolate, local_native_context); native_context_.Reset(v8_isolate, local_native_context);
native_context_.SetWeak(); 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> template <typename T>
...@@ -536,77 +529,108 @@ Object FutexEmulation::WaitAsync(Isolate* isolate, ...@@ -536,77 +529,108 @@ Object FutexEmulation::WaitAsync(Isolate* isolate,
Factory* factory = isolate->factory(); Factory* factory = isolate->factory();
Handle<JSObject> result = factory->NewJSObject(isolate->object_function()); Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
Handle<JSObject> promise_capability = factory->NewJSPromise();
std::shared_ptr<BackingStore> backing_store = array_buffer->GetBackingStore(); enum { kNotEqual, kTimedOut, kAsync } result_kind;
FutexWaitListNode* node = nullptr;
{
// 16. Perform EnterCriticalSection(WL).
NoGarbageCollectionMutexGuard lock_guard(g_mutex.Pointer());
std::shared_ptr<BackingStore> backing_store =
array_buffer->GetBackingStore();
// 17. Let w be ! AtomicLoad(typedArray, i). // 17. Let w be ! AtomicLoad(typedArray, i).
std::atomic<T>* p = reinterpret_cast<std::atomic<T>*>( std::atomic<T>* p = reinterpret_cast<std::atomic<T>*>(
static_cast<int8_t*>(backing_store->buffer_start()) + addr); static_cast<int8_t*>(backing_store->buffer_start()) + addr);
if (p->load() != value) { if (p->load() != value) {
// 18. If v is not equal to w, then result_kind = kNotEqual;
// a. Perform LeaveCriticalSection(WL). } else if (use_timeout && rel_timeout_ns == 0) {
// ... result_kind = kTimedOut;
// c. Perform ! CreateDataPropertyOrThrow(resultObject, "async", false). } else {
// d. Perform ! CreateDataPropertyOrThrow(resultObject, "value", result_kind = kAsync;
// "not-equal"). node = new FutexWaitListNode(backing_store, addr, promise_capability,
// e. Return resultObject. isolate);
CHECK( g_wait_list.Pointer()->AddNode(node);
JSReceiver::CreateDataProperty(isolate, result, factory->async_string(), }
factory->false_value(), Just(kDontThrow))
.FromJust()); // Leaving the block collapses the following steps:
CHECK(JSReceiver::CreateDataProperty( // 18.a. Perform LeaveCriticalSection(WL).
isolate, result, factory->value_string(), // 19.b. Perform LeaveCriticalSection(WL).
factory->not_equal_string(), Just(kDontThrow)) // 24. Perform LeaveCriticalSection(WL).
.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(); switch (result_kind) {
FutexWaitListNode* node = case kNotEqual:
new FutexWaitListNode(backing_store, addr, promise_capability, isolate); // 18. If v is not equal to w, then
// ...
// 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());
break;
{ case kTimedOut:
NoGarbageCollectionMutexGuard lock_guard(g_mutex.Pointer()); // 19. If t is 0 and mode is async, then
g_wait_list.Pointer()->AddNode(node); // ...
// 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());
break;
case kAsync:
DCHECK_NOT_NULL(node);
// Add the Promise into the NativeContext's atomics_waitasync_promises
// set, so that the list keeps it alive.
Handle<NativeContext> native_context(isolate->native_context());
Handle<OrderedHashSet> promises(
native_context->atomics_waitasync_promises(), isolate);
promises = OrderedHashSet::Add(isolate, promises, promise_capability)
.ToHandleChecked();
native_context->set_atomics_waitasync_promises(*promises);
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());
break;
} }
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; return *result;
} }
......
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