Commit a64bb799 authored by Marja Hölttä's avatar Marja Hölttä Committed by V8 LUCI CQ

[rab/gsab] Atomics.*: Support RAB / GSAB

Bug: v8:11111
Change-Id: I3c350dd98b3da995b52c8366876d66b87fc47c28
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3605611
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80244}
parent b0874438
......@@ -216,7 +216,7 @@ void ArrayBuiltinsAssembler::VisitAllTypedArrayElements(
Label process(this);
if (can_shrink) {
// If `index` is out of bounds, Get returns undefined.
CheckJSTypedArrayIndex(index, typed_array, &detached);
CheckJSTypedArrayIndex(typed_array, index, &detached);
} else {
GotoIf(IsDetachedBuffer(array_buffer), &detached);
}
......
......@@ -14311,7 +14311,7 @@ TNode<BoolT> CodeStubAssembler::IsJSArrayBufferViewDetachedOrOutOfBoundsBoolean(
}
void CodeStubAssembler::CheckJSTypedArrayIndex(
TNode<UintPtrT> index, TNode<JSTypedArray> typed_array,
TNode<JSTypedArray> typed_array, TNode<UintPtrT> index,
Label* detached_or_out_of_bounds) {
TNode<UintPtrT> len = LoadJSTypedArrayLengthAndCheckDetached(
typed_array, detached_or_out_of_bounds);
......@@ -14597,6 +14597,22 @@ TNode<BoolT> CodeStubAssembler::IsElementsKindLessThanOrEqual(
return Int32LessThanOrEqual(target_kind, Int32Constant(reference_kind));
}
TNode<Int32T> CodeStubAssembler::GetNonRabGsabElementsKind(
TNode<Int32T> elements_kind) {
Label is_rab_gsab(this), end(this);
TVARIABLE(Int32T, result);
result = elements_kind;
Branch(Int32GreaterThanOrEqual(elements_kind,
Int32Constant(RAB_GSAB_UINT8_ELEMENTS)),
&is_rab_gsab, &end);
BIND(&is_rab_gsab);
result = Int32Sub(elements_kind,
Int32Constant(RAB_GSAB_UINT8_ELEMENTS - UINT8_ELEMENTS));
Goto(&end);
BIND(&end);
return result.value();
}
TNode<BoolT> CodeStubAssembler::IsDebugActive() {
TNode<Uint8T> is_debug_active = Load<Uint8T>(
ExternalConstant(ExternalReference::debug_is_active_address(isolate())));
......
......@@ -2754,6 +2754,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
ElementsKind higher_reference_kind) {
return IsInRange(target_kind, lower_reference_kind, higher_reference_kind);
}
TNode<Int32T> GetNonRabGsabElementsKind(TNode<Int32T> elements_kind);
// String helpers.
// Load a character from a String (might flatten a ConsString).
......@@ -3728,8 +3729,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsJSArrayBufferViewDetachedOrOutOfBoundsBoolean(
TNode<JSArrayBufferView> array_buffer_view);
void CheckJSTypedArrayIndex(TNode<UintPtrT> index,
TNode<JSTypedArray> typed_array,
void CheckJSTypedArrayIndex(TNode<JSTypedArray> typed_array,
TNode<UintPtrT> index,
Label* detached_or_out_of_bounds);
TNode<IntPtrT> RabGsabElementsKindToElementByteSize(
......
......@@ -379,9 +379,12 @@ struct Xor {
V(Uint32, uint32, UINT32, uint32_t) \
V(Int32, int32, INT32, int32_t)
#define THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta, method_name) \
#define THROW_ERROR_RETURN_FAILURE_ON_DETACHED_OR_OUT_OF_BOUNDS( \
isolate, sta, index, method_name) \
do { \
if (V8_UNLIKELY(sta->WasDetached())) { \
bool out_of_bounds = false; \
auto length = sta->GetLengthOrOutOfBounds(out_of_bounds); \
if (V8_UNLIKELY(sta->WasDetached() || out_of_bounds || index >= length)) { \
THROW_NEW_ERROR_RETURN_FAILURE( \
isolate, NewTypeError(MessageTemplate::kDetachedOperation, \
isolate->factory()->NewStringFromAsciiChecked( \
......@@ -409,7 +412,8 @@ Object GetModifySetValueInBuffer(RuntimeArguments args, Isolate* isolate,
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, bigint,
BigInt::FromObject(isolate, value_obj));
THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta, method_name);
THROW_ERROR_RETURN_FAILURE_ON_DETACHED_OR_OUT_OF_BOUNDS(isolate, sta, index,
method_name);
CHECK_LT(index, sta->length());
if (sta->type() == kExternalBigInt64Array) {
......@@ -423,7 +427,8 @@ Object GetModifySetValueInBuffer(RuntimeArguments args, Isolate* isolate,
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
Object::ToInteger(isolate, value_obj));
THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta, method_name);
THROW_ERROR_RETURN_FAILURE_ON_DETACHED_OR_OUT_OF_BOUNDS(isolate, sta, index,
method_name);
CHECK_LT(index, sta->length());
......@@ -453,7 +458,7 @@ RUNTIME_FUNCTION(Runtime_AtomicsLoad64) {
DCHECK(sta->type() == kExternalBigInt64Array ||
sta->type() == kExternalBigUint64Array);
DCHECK(!sta->WasDetached());
DCHECK(!sta->IsDetachedOrOutOfBounds());
CHECK_LT(index, sta->length());
if (sta->type() == kExternalBigInt64Array) {
return Load<int64_t>::Do(isolate, source, index);
......@@ -476,11 +481,12 @@ RUNTIME_FUNCTION(Runtime_AtomicsStore64) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, bigint,
BigInt::FromObject(isolate, value_obj));
THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta, "Atomics.store");
THROW_ERROR_RETURN_FAILURE_ON_DETACHED_OR_OUT_OF_BOUNDS(isolate, sta, index,
"Atomics.store");
DCHECK(sta->type() == kExternalBigInt64Array ||
sta->type() == kExternalBigUint64Array);
CHECK_LT(index, sta->length());
CHECK_LT(index, sta->GetLength());
if (sta->type() == kExternalBigInt64Array) {
Store<int64_t>::Do(isolate, source, index, bigint);
return *bigint;
......@@ -514,8 +520,8 @@ RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, new_bigint, BigInt::FromObject(isolate, new_value_obj));
THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta,
"Atomics.compareExchange");
THROW_ERROR_RETURN_FAILURE_ON_DETACHED_OR_OUT_OF_BOUNDS(
isolate, sta, index, "Atomics.compareExchange");
CHECK_LT(index, sta->length());
if (sta->type() == kExternalBigInt64Array) {
......@@ -534,8 +540,8 @@ RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, new_value,
Object::ToInteger(isolate, new_value_obj));
THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta,
"Atomics.compareExchange");
THROW_ERROR_RETURN_FAILURE_ON_DETACHED_OR_OUT_OF_BOUNDS(
isolate, sta, index, "Atomics.compareExchange");
switch (sta->type()) {
#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype) \
......
// Copyright 2021 the V8 project authors. All rights reserved.
// 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.
......@@ -141,3 +141,28 @@ d8.file.execute('test/mjsunit/typedarray-helpers.js');
TypeError);
});
})();
(function TestAtomics() {
for (let ctor of intCtors) {
const gsab = CreateGrowableSharedArrayBuffer(4 * ctor.BYTES_PER_ELEMENT,
8 * ctor.BYTES_PER_ELEMENT);
const lengthTracking = new ctor(gsab, 0);
TestAtomicsOperations(lengthTracking, 0);
AssertAtomicsOperationsThrow(lengthTracking, 4, RangeError);
gsab.grow(6 * ctor.BYTES_PER_ELEMENT);
TestAtomicsOperations(lengthTracking, 4);
}
})();
(function AtomicsFailWithNonIntegerArray() {
const gsab = CreateGrowableSharedArrayBuffer(400, 800);
const ui8ca = new Uint8ClampedArray(gsab);
const f32a = new Float32Array(gsab);
const f64a = new Float64Array(gsab);
const mf32a = new MyFloat32Array(gsab);
[ui8ca, f32a, f64a, mf32a].forEach((ta) => {
AssertAtomicsOperationsThrow(ta, 0, TypeError); });
})();
......@@ -11,6 +11,7 @@ const ctors = [
Int8Array,
Uint16Array,
Int16Array,
Uint32Array,
Int32Array,
Float32Array,
Float64Array,
......@@ -28,6 +29,19 @@ const floatCtors = [
MyFloat32Array
];
const intCtors = [
Uint8Array,
Int8Array,
Uint16Array,
Int16Array,
Uint32Array,
Int32Array,
BigUint64Array,
BigInt64Array,
MyUint8Array,
MyBigInt64Array,
];
// Each element of the following array is [getter, setter, size, isBigInt].
const dataViewAccessorsAndSizes = [[DataView.prototype.getUint8,
DataView.prototype.setUint8, 1, false],
......@@ -252,3 +266,45 @@ function ObjectDefinePropertiesHelper(ta, index, value) {
}
Object.defineProperties(ta, values);
}
function TestAtomicsOperations(ta, index) {
const one = IsBigIntTypedArray(ta) ? 1n : 1;
const two = IsBigIntTypedArray(ta) ? 2n : 2;
const three = IsBigIntTypedArray(ta) ? 3n : 3;
Atomics.store(ta, index, one);
assertEquals(one, Atomics.load(ta, index));
assertEquals(one, Atomics.exchange(ta, index, two));
assertEquals(two, Atomics.load(ta, index));
assertEquals(two, Atomics.compareExchange(ta, index, two, three));
assertEquals(three, Atomics.load(ta, index));
assertEquals(three, Atomics.sub(ta, index, two)); // 3 - 2 = 1
assertEquals(one, Atomics.load(ta, index));
assertEquals(one, Atomics.add(ta, index, one)); // 1 + 1 = 2
assertEquals(two, Atomics.load(ta, index));
assertEquals(two, Atomics.or(ta, index, one)); // 2 | 1 = 3
assertEquals(three, Atomics.load(ta, index));
assertEquals(three, Atomics.xor(ta, index, one)); // 3 ^ 1 = 2
assertEquals(two, Atomics.load(ta, index));
assertEquals(two, Atomics.and(ta, index, three)); // 2 & 3 = 2
assertEquals(two, Atomics.load(ta, index));
}
function AssertAtomicsOperationsThrow(ta, index, error) {
const one = IsBigIntTypedArray(ta) ? 1n : 1;
assertThrows(() => { Atomics.store(ta, index, one); }, error);
assertThrows(() => { Atomics.load(ta, index); }, error);
assertThrows(() => { Atomics.exchange(ta, index, one); }, error);
assertThrows(() => { Atomics.compareExchange(ta, index, one, one); },
error);
assertThrows(() => { Atomics.add(ta, index, one); }, error);
assertThrows(() => { Atomics.sub(ta, index, one); }, error);
assertThrows(() => { Atomics.and(ta, index, one); }, error);
assertThrows(() => { Atomics.or(ta, index, one); }, error);
assertThrows(() => { Atomics.xor(ta, index, one); }, error);
}
This diff is collapsed.
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