Skip to content

Commit

Permalink
Bug 1842773 - Part 28: Enable Atomics with resizable buffers. r=sfink
Browse files Browse the repository at this point in the history
Part 17 disabled Atomics for resizable buffers. Remove this restriction again.

Inlining Atomics functions for resizable buffers isn't affected by this change.

Differential Revision: https://phabricator.services.mozilla.com/D183345
  • Loading branch information
anba committed Jan 26, 2024
1 parent 50bf5ea commit dad58b4
Showing 1 changed file with 56 additions and 35 deletions.
91 changes: 56 additions & 35 deletions js/src/builtin/AtomicsObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ static bool ReportDetachedArrayBuffer(JSContext* cx) {
return false;
}

static bool ReportResizedArrayBuffer(JSContext* cx) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_TYPED_ARRAY_RESIZED_BOUNDS);
return false;
}

static bool ReportOutOfRange(JSContext* cx) {
// Use JSMSG_BAD_INDEX here, it is what ToIndex uses for some cases that it
// reports directly.
Expand All @@ -60,13 +66,11 @@ static bool ReportOutOfRange(JSContext* cx) {
// 24.4.1.1 ValidateIntegerTypedArray ( typedArray [ , waitable ] )
static bool ValidateIntegerTypedArray(
JSContext* cx, HandleValue typedArray, bool waitable,
MutableHandle<FixedLengthTypedArrayObject*> unwrappedTypedArray) {
MutableHandle<TypedArrayObject*> unwrappedTypedArray) {
// Step 1 (implicit).

// TODO(anba): support resizable buffers

// Step 2.
auto* unwrapped = UnwrapAndTypeCheckValue<FixedLengthTypedArrayObject>(
auto* unwrapped = UnwrapAndTypeCheckValue<TypedArrayObject>(
cx, typedArray, [cx]() { ReportBadArrayType(cx); });
if (!unwrapped) {
return false;
Expand Down Expand Up @@ -108,26 +112,31 @@ static bool ValidateIntegerTypedArray(

// ES2021 draft rev bd868f20b8c574ad6689fba014b62a1dba819e56
// 24.4.1.2 ValidateAtomicAccess ( typedArray, requestIndex )
static bool ValidateAtomicAccess(
JSContext* cx, Handle<FixedLengthTypedArrayObject*> typedArray,
HandleValue requestIndex, size_t* index) {
// Step 1 (implicit).

static bool ValidateAtomicAccess(JSContext* cx,
Handle<TypedArrayObject*> typedArray,
HandleValue requestIndex, size_t* index) {
MOZ_ASSERT(!typedArray->hasDetachedBuffer());
size_t length = typedArray->length();

// Step 2.
// Steps 1-2.
mozilla::Maybe<size_t> length = typedArray->length();
if (!length) {
// ValidateIntegerTypedArray doesn't check for out-of-bounds in our
// implementation, so we have to handle this case here.
return ReportResizedArrayBuffer(cx);
}

// Steps 3-4.
uint64_t accessIndex;
if (!ToIndex(cx, requestIndex, &accessIndex)) {
return false;
}

// Steps 3-5.
if (accessIndex >= length) {
// Step 5.
if (accessIndex >= *length) {
return ReportOutOfRange(cx);
}

// Step 6.
// Steps 6-9.
*index = size_t(accessIndex);
return true;
}
Expand Down Expand Up @@ -243,7 +252,7 @@ struct ArrayOps<uint64_t> {
template <typename Op>
bool AtomicAccess(JSContext* cx, HandleValue obj, HandleValue index, Op op) {
// Step 1.
Rooted<FixedLengthTypedArrayObject*> unwrappedTypedArray(cx);
Rooted<TypedArrayObject*> unwrappedTypedArray(cx);
if (!ValidateIntegerTypedArray(cx, obj, false, &unwrappedTypedArray)) {
return false;
}
Expand Down Expand Up @@ -283,14 +292,23 @@ bool AtomicAccess(JSContext* cx, HandleValue obj, HandleValue index, Op op) {
}

template <typename T>
static SharedMem<T*> TypedArrayData(JSContext* cx,
FixedLengthTypedArrayObject* typedArray,
static SharedMem<T*> TypedArrayData(JSContext* cx, TypedArrayObject* typedArray,
size_t index) {
if (typedArray->hasDetachedBuffer()) {
// RevalidateAtomicAccess, steps 1-3.
mozilla::Maybe<size_t> length = typedArray->length();

// RevalidateAtomicAccess, step 4.
if (!length) {
ReportDetachedArrayBuffer(cx);
return {};
}

// RevalidateAtomicAccess, step 5.
if (index >= *length) {
ReportOutOfRange(cx);
return {};
}

SharedMem<void*> typedArrayData = typedArray->dataPointerEither();
return typedArrayData.cast<T*>() + index;
}
Expand All @@ -305,8 +323,7 @@ static bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp) {

return AtomicAccess(
cx, typedArray, index,
[cx, &args](auto ops,
Handle<FixedLengthTypedArrayObject*> unwrappedTypedArray,
[cx, &args](auto ops, Handle<TypedArrayObject*> unwrappedTypedArray,
size_t index) {
using T = typename decltype(ops)::Type;

Expand Down Expand Up @@ -343,8 +360,7 @@ static bool atomics_load(JSContext* cx, unsigned argc, Value* vp) {

return AtomicAccess(
cx, typedArray, index,
[cx, &args](auto ops,
Handle<FixedLengthTypedArrayObject*> unwrappedTypedArray,
[cx, &args](auto ops, Handle<TypedArrayObject*> unwrappedTypedArray,
size_t index) {
using T = typename decltype(ops)::Type;

Expand All @@ -369,8 +385,7 @@ static bool atomics_store(JSContext* cx, unsigned argc, Value* vp) {

return AtomicAccess(
cx, typedArray, index,
[cx, &args](auto ops,
Handle<FixedLengthTypedArrayObject*> unwrappedTypedArray,
[cx, &args](auto ops, Handle<TypedArrayObject*> unwrappedTypedArray,
size_t index) {
using T = typename decltype(ops)::Type;

Expand Down Expand Up @@ -400,8 +415,7 @@ static bool AtomicReadModifyWrite(JSContext* cx, const CallArgs& args,

return AtomicAccess(
cx, typedArray, index,
[cx, &args, op](auto ops,
Handle<FixedLengthTypedArrayObject*> unwrappedTypedArray,
[cx, &args, op](auto ops, Handle<TypedArrayObject*> unwrappedTypedArray,
size_t index) {
using T = typename decltype(ops)::Type;

Expand Down Expand Up @@ -627,9 +641,10 @@ FutexThread::WaitResult js::atomics_wait_impl(
// ES2021 draft rev bd868f20b8c574ad6689fba014b62a1dba819e56
// 24.4.11 Atomics.wait ( typedArray, index, value, timeout ), steps 6-25.
template <typename T>
static bool DoAtomicsWait(
JSContext* cx, Handle<FixedLengthTypedArrayObject*> unwrappedTypedArray,
size_t index, T value, HandleValue timeoutv, MutableHandleValue r) {
static bool DoAtomicsWait(JSContext* cx,
Handle<TypedArrayObject*> unwrappedTypedArray,
size_t index, T value, HandleValue timeoutv,
MutableHandleValue r) {
mozilla::Maybe<mozilla::TimeDuration> timeout;
if (!timeoutv.isUndefined()) {
// Step 6.
Expand All @@ -654,12 +669,15 @@ static bool DoAtomicsWait(
cx, unwrappedTypedArray->bufferShared());

// Step 11.
size_t offset = unwrappedTypedArray->byteOffset();
mozilla::Maybe<size_t> offset = unwrappedTypedArray->byteOffset();
MOZ_ASSERT(
offset,
"offset can't become invalid because shared buffers can only grow");

// Steps 12-13.
// The computation will not overflow because range checks have been
// performed.
size_t indexedPosition = index * sizeof(T) + offset;
size_t indexedPosition = index * sizeof(T) + *offset;

// Steps 8-9, 14-25.
switch (atomics_wait_impl(cx, unwrappedSab->rawBufferObject(),
Expand Down Expand Up @@ -691,7 +709,7 @@ static bool atomics_wait(JSContext* cx, unsigned argc, Value* vp) {
MutableHandleValue r = args.rval();

// Step 1.
Rooted<FixedLengthTypedArrayObject*> unwrappedTypedArray(cx);
Rooted<TypedArrayObject*> unwrappedTypedArray(cx);
if (!ValidateIntegerTypedArray(cx, objv, true, &unwrappedTypedArray)) {
return false;
}
Expand Down Expand Up @@ -784,7 +802,7 @@ static bool atomics_notify(JSContext* cx, unsigned argc, Value* vp) {
MutableHandleValue r = args.rval();

// Step 1.
Rooted<FixedLengthTypedArrayObject*> unwrappedTypedArray(cx);
Rooted<TypedArrayObject*> unwrappedTypedArray(cx);
if (!ValidateIntegerTypedArray(cx, objv, true, &unwrappedTypedArray)) {
return false;
}
Expand Down Expand Up @@ -823,13 +841,16 @@ static bool atomics_notify(JSContext* cx, unsigned argc, Value* vp) {
cx, unwrappedTypedArray->bufferShared());

// Step 6.
size_t offset = unwrappedTypedArray->byteOffset();
mozilla::Maybe<size_t> offset = unwrappedTypedArray->byteOffset();
MOZ_ASSERT(
offset,
"offset can't become invalid because shared buffers can only grow");

// Steps 7-9.
// The computation will not overflow because range checks have been
// performed.
size_t elementSize = Scalar::byteSize(unwrappedTypedArray->type());
size_t indexedPosition = intIndex * elementSize + offset;
size_t indexedPosition = intIndex * elementSize + *offset;

// Steps 10-16.
r.setNumber(double(atomics_notify_impl(unwrappedSab->rawBufferObject(),
Expand Down

0 comments on commit dad58b4

Please sign in to comment.