[atomics] Relax Atomics methods to work on ArrayBuffers
This reached consensus in the March 2020 TC39. https://github.com/tc39/ecma262/pull/1908 This aligns JS with wasm, which allows atomics operations on non-shared linear memory. Bug: v8:10687, v8:9921 Change-Id: I7b60473b271cee6bccb342e97a4fd3781aedddb4 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2330802 Commit-Queue: Shu-yu Guo <syg@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#69392}
This commit is contained in:
parent
c5722641da
commit
6962221295
@ -23,10 +23,10 @@ class SharedArrayBufferBuiltinsAssembler : public CodeStubAssembler {
|
|||||||
Node* base, Node* offset,
|
Node* base, Node* offset,
|
||||||
Node* value,
|
Node* value,
|
||||||
Node* value_high);
|
Node* value_high);
|
||||||
void ValidateSharedTypedArray(TNode<Object> maybe_array,
|
TNode<JSArrayBuffer> ValidateIntegerTypedArray(
|
||||||
TNode<Context> context,
|
TNode<Object> maybe_array, TNode<Context> context,
|
||||||
TNode<Int32T>* out_elements_kind,
|
TNode<Int32T>* out_elements_kind, TNode<RawPtrT>* out_backing_store,
|
||||||
TNode<RawPtrT>* out_backing_store);
|
Label* detached);
|
||||||
|
|
||||||
TNode<UintPtrT> ValidateAtomicAccess(TNode<JSTypedArray> array,
|
TNode<UintPtrT> ValidateAtomicAccess(TNode<JSTypedArray> array,
|
||||||
TNode<Object> index,
|
TNode<Object> index,
|
||||||
@ -38,7 +38,8 @@ class SharedArrayBufferBuiltinsAssembler : public CodeStubAssembler {
|
|||||||
void AtomicBinopBuiltinCommon(TNode<Object> maybe_array, TNode<Object> index,
|
void AtomicBinopBuiltinCommon(TNode<Object> maybe_array, TNode<Object> index,
|
||||||
TNode<Object> value, TNode<Context> context,
|
TNode<Object> value, TNode<Context> context,
|
||||||
AssemblerFunction function,
|
AssemblerFunction function,
|
||||||
Runtime::FunctionId runtime_function);
|
Runtime::FunctionId runtime_function,
|
||||||
|
const char* method_name);
|
||||||
|
|
||||||
// Create a BigInt from the result of a 64-bit atomic operation, using
|
// Create a BigInt from the result of a 64-bit atomic operation, using
|
||||||
// projections on 32-bit platforms.
|
// projections on 32-bit platforms.
|
||||||
@ -46,12 +47,17 @@ class SharedArrayBufferBuiltinsAssembler : public CodeStubAssembler {
|
|||||||
TNode<BigInt> BigIntFromUnsigned64(Node* unsigned64);
|
TNode<BigInt> BigIntFromUnsigned64(Node* unsigned64);
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://tc39.es/ecma262/#sec-validatesharedintegertypedarray
|
// https://tc39.es/ecma262/#sec-validateintegertypedarray
|
||||||
void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray(
|
TNode<JSArrayBuffer>
|
||||||
|
SharedArrayBufferBuiltinsAssembler::ValidateIntegerTypedArray(
|
||||||
TNode<Object> maybe_array, TNode<Context> context,
|
TNode<Object> maybe_array, TNode<Context> context,
|
||||||
TNode<Int32T>* out_elements_kind, TNode<RawPtrT>* out_backing_store) {
|
TNode<Int32T>* out_elements_kind, TNode<RawPtrT>* out_backing_store,
|
||||||
|
Label* detached) {
|
||||||
Label not_float_or_clamped(this), invalid(this);
|
Label not_float_or_clamped(this), invalid(this);
|
||||||
|
|
||||||
|
// The logic of TypedArrayBuiltinsAssembler::ValidateTypedArrayBuffer is
|
||||||
|
// inlined to avoid duplicate error branches.
|
||||||
|
|
||||||
// Fail if it is not a heap object.
|
// Fail if it is not a heap object.
|
||||||
GotoIf(TaggedIsSmi(maybe_array), &invalid);
|
GotoIf(TaggedIsSmi(maybe_array), &invalid);
|
||||||
|
|
||||||
@ -60,10 +66,9 @@ void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray(
|
|||||||
GotoIfNot(IsJSTypedArrayMap(map), &invalid);
|
GotoIfNot(IsJSTypedArrayMap(map), &invalid);
|
||||||
TNode<JSTypedArray> array = CAST(maybe_array);
|
TNode<JSTypedArray> array = CAST(maybe_array);
|
||||||
|
|
||||||
// Fail if the array's JSArrayBuffer is not shared.
|
// Fail if the array's JSArrayBuffer is detached.
|
||||||
TNode<JSArrayBuffer> array_buffer = LoadJSArrayBufferViewBuffer(array);
|
TNode<JSArrayBuffer> array_buffer = GetTypedArrayBuffer(context, array);
|
||||||
TNode<Uint32T> bitfield = LoadJSArrayBufferBitField(array_buffer);
|
GotoIf(IsDetachedBuffer(array_buffer), detached);
|
||||||
GotoIfNot(IsSetWord32<JSArrayBuffer::IsSharedBit>(bitfield), &invalid);
|
|
||||||
|
|
||||||
// Fail if the array's element type is float32, float64 or clamped.
|
// Fail if the array's element type is float32, float64 or clamped.
|
||||||
STATIC_ASSERT(INT8_ELEMENTS < FLOAT32_ELEMENTS);
|
STATIC_ASSERT(INT8_ELEMENTS < FLOAT32_ELEMENTS);
|
||||||
@ -82,7 +87,7 @@ void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray(
|
|||||||
|
|
||||||
BIND(&invalid);
|
BIND(&invalid);
|
||||||
{
|
{
|
||||||
ThrowTypeError(context, MessageTemplate::kNotIntegerSharedTypedArray,
|
ThrowTypeError(context, MessageTemplate::kNotIntegerTypedArray,
|
||||||
maybe_array);
|
maybe_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +97,8 @@ void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray(
|
|||||||
TNode<RawPtrT> backing_store = LoadJSArrayBufferBackingStorePtr(array_buffer);
|
TNode<RawPtrT> backing_store = LoadJSArrayBufferBackingStorePtr(array_buffer);
|
||||||
TNode<UintPtrT> byte_offset = LoadJSArrayBufferViewByteOffset(array);
|
TNode<UintPtrT> byte_offset = LoadJSArrayBufferViewByteOffset(array);
|
||||||
*out_backing_store = RawPtrAdd(backing_store, Signed(byte_offset));
|
*out_backing_store = RawPtrAdd(backing_store, Signed(byte_offset));
|
||||||
|
|
||||||
|
return array_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://tc39.github.io/ecma262/#sec-validateatomicaccess
|
// https://tc39.github.io/ecma262/#sec-validateatomicaccess
|
||||||
@ -100,24 +107,35 @@ TNode<UintPtrT> SharedArrayBufferBuiltinsAssembler::ValidateAtomicAccess(
|
|||||||
TNode<JSTypedArray> array, TNode<Object> index, TNode<Context> context) {
|
TNode<JSTypedArray> array, TNode<Object> index, TNode<Context> context) {
|
||||||
Label done(this), range_error(this);
|
Label done(this), range_error(this);
|
||||||
|
|
||||||
|
// 1. Assert: typedArray is an Object that has a [[ViewedArrayBuffer]]
|
||||||
|
// internal slot.
|
||||||
|
// 2. Let length be typedArray.[[ArrayLength]].
|
||||||
|
TNode<UintPtrT> array_length = LoadJSTypedArrayLength(array);
|
||||||
|
|
||||||
|
// 3. Let accessIndex be ? ToIndex(requestIndex).
|
||||||
TNode<UintPtrT> index_uintptr = ToIndex(context, index, &range_error);
|
TNode<UintPtrT> index_uintptr = ToIndex(context, index, &range_error);
|
||||||
|
|
||||||
TNode<UintPtrT> array_length = LoadJSTypedArrayLength(array);
|
// 4. Assert: accessIndex ≥ 0.
|
||||||
|
// 5. If accessIndex ≥ length, throw a RangeError exception.
|
||||||
Branch(UintPtrLessThan(index_uintptr, array_length), &done, &range_error);
|
Branch(UintPtrLessThan(index_uintptr, array_length), &done, &range_error);
|
||||||
|
|
||||||
BIND(&range_error);
|
BIND(&range_error);
|
||||||
ThrowRangeError(context, MessageTemplate::kInvalidAtomicAccessIndex);
|
ThrowRangeError(context, MessageTemplate::kInvalidAtomicAccessIndex);
|
||||||
|
|
||||||
|
// 6. Return accessIndex.
|
||||||
BIND(&done);
|
BIND(&done);
|
||||||
return index_uintptr;
|
return index_uintptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedArrayBufferBuiltinsAssembler::DebugSanityCheckAtomicIndex(
|
void SharedArrayBufferBuiltinsAssembler::DebugSanityCheckAtomicIndex(
|
||||||
TNode<JSTypedArray> array, TNode<UintPtrT> index) {
|
TNode<JSTypedArray> array, TNode<UintPtrT> index) {
|
||||||
// In Debug mode, we re-validate the index as a sanity check because
|
// In Debug mode, we re-validate the index as a sanity check because ToInteger
|
||||||
// ToInteger above calls out to JavaScript. A SharedArrayBuffer can't be
|
// above calls out to JavaScript. Atomics work on ArrayBuffers, which may be
|
||||||
// detached and the TypedArray length can't change either, so skipping this
|
// detached, and detachment state must be checked and throw before this
|
||||||
// check in Release mode is safe.
|
// check. The length cannot change.
|
||||||
|
//
|
||||||
|
// This function must always be called after ValidateIntegerTypedArray, which
|
||||||
|
// will ensure that LoadJSArrayBufferViewBuffer will not be null.
|
||||||
CSA_ASSERT(this, Word32BinaryNot(
|
CSA_ASSERT(this, Word32BinaryNot(
|
||||||
IsDetachedBuffer(LoadJSArrayBufferViewBuffer(array))));
|
IsDetachedBuffer(LoadJSArrayBufferViewBuffer(array))));
|
||||||
CSA_ASSERT(this, UintPtrLessThan(index, LoadJSTypedArrayLength(array)));
|
CSA_ASSERT(this, UintPtrLessThan(index, LoadJSTypedArrayLength(array)));
|
||||||
@ -151,14 +169,27 @@ TF_BUILTIN(AtomicsLoad, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
TNode<Object> index = CAST(Parameter(Descriptor::kIndex));
|
TNode<Object> index = CAST(Parameter(Descriptor::kIndex));
|
||||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||||
|
|
||||||
|
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray).
|
||||||
|
Label detached(this);
|
||||||
TNode<Int32T> elements_kind;
|
TNode<Int32T> elements_kind;
|
||||||
TNode<RawPtrT> backing_store;
|
TNode<RawPtrT> backing_store;
|
||||||
ValidateSharedTypedArray(maybe_array, context, &elements_kind,
|
TNode<JSArrayBuffer> array_buffer = ValidateIntegerTypedArray(
|
||||||
&backing_store);
|
maybe_array, context, &elements_kind, &backing_store, &detached);
|
||||||
TNode<JSTypedArray> array = CAST(maybe_array);
|
TNode<JSTypedArray> array = CAST(maybe_array);
|
||||||
|
|
||||||
|
// 2. Let i be ? ValidateAtomicAccess(typedArray, index).
|
||||||
TNode<UintPtrT> index_word = ValidateAtomicAccess(array, index, context);
|
TNode<UintPtrT> index_word = ValidateAtomicAccess(array, index, context);
|
||||||
|
|
||||||
|
// 3. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||||
|
// 4. NOTE: The above check is not redundant with the check in
|
||||||
|
// ValidateIntegerTypedArray because the call to ValidateAtomicAccess on the
|
||||||
|
// preceding line can have arbitrary side effects, which could cause the
|
||||||
|
// buffer to become detached.
|
||||||
|
GotoIf(IsDetachedBuffer(array_buffer), &detached);
|
||||||
|
|
||||||
|
// Steps 5-10.
|
||||||
|
//
|
||||||
|
// (Not copied from ecma262 due to the axiomatic nature of the memory model.)
|
||||||
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
|
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
|
||||||
i64(this), u64(this), other(this);
|
i64(this), u64(this), other(this);
|
||||||
int32_t case_values[] = {
|
int32_t case_values[] = {
|
||||||
@ -213,9 +244,16 @@ TF_BUILTIN(AtomicsLoad, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
Return(BigIntFromUnsigned64(AtomicLoad(MachineType::Uint64(), backing_store,
|
Return(BigIntFromUnsigned64(AtomicLoad(MachineType::Uint64(), backing_store,
|
||||||
WordShl(index_word, 3))));
|
WordShl(index_word, 3))));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This shouldn't happen, we've already validated the type.
|
// This shouldn't happen, we've already validated the type.
|
||||||
BIND(&other);
|
BIND(&other);
|
||||||
Unreachable();
|
Unreachable();
|
||||||
|
|
||||||
|
BIND(&detached);
|
||||||
|
{
|
||||||
|
ThrowTypeError(context, MessageTemplate::kDetachedOperation,
|
||||||
|
"Atomics.load");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://tc39.es/ecma262/#sec-atomics.store
|
// https://tc39.es/ecma262/#sec-atomics.store
|
||||||
@ -225,24 +263,43 @@ TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
|
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
|
||||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||||
|
|
||||||
|
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray).
|
||||||
|
Label detached(this);
|
||||||
TNode<Int32T> elements_kind;
|
TNode<Int32T> elements_kind;
|
||||||
TNode<RawPtrT> backing_store;
|
TNode<RawPtrT> backing_store;
|
||||||
ValidateSharedTypedArray(maybe_array, context, &elements_kind,
|
TNode<JSArrayBuffer> array_buffer = ValidateIntegerTypedArray(
|
||||||
&backing_store);
|
maybe_array, context, &elements_kind, &backing_store, &detached);
|
||||||
TNode<JSTypedArray> array = CAST(maybe_array);
|
TNode<JSTypedArray> array = CAST(maybe_array);
|
||||||
|
|
||||||
|
// 2. Let i be ? ValidateAtomicAccess(typedArray, index).
|
||||||
TNode<UintPtrT> index_word = ValidateAtomicAccess(array, index, context);
|
TNode<UintPtrT> index_word = ValidateAtomicAccess(array, index, context);
|
||||||
|
|
||||||
Label u8(this), u16(this), u32(this), u64(this), other(this);
|
Label u8(this), u16(this), u32(this), u64(this), other(this);
|
||||||
|
|
||||||
|
// 3. Let arrayTypeName be typedArray.[[TypedArrayName]].
|
||||||
|
// 4. If arrayTypeName is "BigUint64Array" or "BigInt64Array",
|
||||||
|
// let v be ? ToBigInt(value).
|
||||||
STATIC_ASSERT(BIGINT64_ELEMENTS > INT32_ELEMENTS);
|
STATIC_ASSERT(BIGINT64_ELEMENTS > INT32_ELEMENTS);
|
||||||
STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS);
|
STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS);
|
||||||
GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &u64);
|
GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &u64);
|
||||||
|
|
||||||
|
// 5. Otherwise, let v be ? ToInteger(value).
|
||||||
TNode<Number> value_integer = ToInteger_Inline(context, value);
|
TNode<Number> value_integer = ToInteger_Inline(context, value);
|
||||||
|
|
||||||
|
// 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||||
|
// 7. NOTE: The above check is not redundant with the check in
|
||||||
|
// ValidateIntegerTypedArray because the call to ToBigInt or ToInteger on the
|
||||||
|
// preceding lines can have arbitrary side effects, which could cause the
|
||||||
|
// buffer to become detached.
|
||||||
|
GotoIf(IsDetachedBuffer(array_buffer), &detached);
|
||||||
|
|
||||||
TNode<Word32T> value_word32 = TruncateTaggedToWord32(context, value_integer);
|
TNode<Word32T> value_word32 = TruncateTaggedToWord32(context, value_integer);
|
||||||
|
|
||||||
DebugSanityCheckAtomicIndex(array, index_word);
|
DebugSanityCheckAtomicIndex(array, index_word);
|
||||||
|
|
||||||
|
// Steps 8-13.
|
||||||
|
//
|
||||||
|
// (Not copied from ecma262 due to the axiomatic nature of the memory model.)
|
||||||
int32_t case_values[] = {
|
int32_t case_values[] = {
|
||||||
INT8_ELEMENTS, UINT8_ELEMENTS, INT16_ELEMENTS,
|
INT8_ELEMENTS, UINT8_ELEMENTS, INT16_ELEMENTS,
|
||||||
UINT16_ELEMENTS, INT32_ELEMENTS, UINT32_ELEMENTS,
|
UINT16_ELEMENTS, INT32_ELEMENTS, UINT32_ELEMENTS,
|
||||||
@ -272,8 +329,13 @@ TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
Return(CallRuntime(Runtime::kAtomicsStore64, context, array, index_number,
|
Return(CallRuntime(Runtime::kAtomicsStore64, context, array, index_number,
|
||||||
value));
|
value));
|
||||||
#else
|
#else
|
||||||
|
// 4. If arrayTypeName is "BigUint64Array" or "BigInt64Array",
|
||||||
|
// let v be ? ToBigInt(value).
|
||||||
TNode<BigInt> value_bigint = ToBigInt(context, value);
|
TNode<BigInt> value_bigint = ToBigInt(context, value);
|
||||||
|
|
||||||
|
// 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||||
|
GotoIf(IsDetachedBuffer(array_buffer), &detached);
|
||||||
|
|
||||||
DebugSanityCheckAtomicIndex(array, index_word);
|
DebugSanityCheckAtomicIndex(array, index_word);
|
||||||
|
|
||||||
TVARIABLE(UintPtrT, var_low);
|
TVARIABLE(UintPtrT, var_low);
|
||||||
@ -288,6 +350,12 @@ TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
// This shouldn't happen, we've already validated the type.
|
// This shouldn't happen, we've already validated the type.
|
||||||
BIND(&other);
|
BIND(&other);
|
||||||
Unreachable();
|
Unreachable();
|
||||||
|
|
||||||
|
BIND(&detached);
|
||||||
|
{
|
||||||
|
ThrowTypeError(context, MessageTemplate::kDetachedOperation,
|
||||||
|
"Atomics.store");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://tc39.es/ecma262/#sec-atomics.exchange
|
// https://tc39.es/ecma262/#sec-atomics.exchange
|
||||||
@ -297,12 +365,18 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
|
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
|
||||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||||
|
|
||||||
|
// Inlines AtomicReadModifyWrite
|
||||||
|
// https://tc39.es/ecma262/#sec-atomicreadmodifywrite
|
||||||
|
|
||||||
|
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray).
|
||||||
|
Label detached(this);
|
||||||
TNode<Int32T> elements_kind;
|
TNode<Int32T> elements_kind;
|
||||||
TNode<RawPtrT> backing_store;
|
TNode<RawPtrT> backing_store;
|
||||||
ValidateSharedTypedArray(maybe_array, context, &elements_kind,
|
TNode<JSArrayBuffer> array_buffer = ValidateIntegerTypedArray(
|
||||||
&backing_store);
|
maybe_array, context, &elements_kind, &backing_store, &detached);
|
||||||
TNode<JSTypedArray> array = CAST(maybe_array);
|
TNode<JSTypedArray> array = CAST(maybe_array);
|
||||||
|
|
||||||
|
// 2. Let i be ? ValidateAtomicAccess(typedArray, index).
|
||||||
TNode<UintPtrT> index_word = ValidateAtomicAccess(array, index, context);
|
TNode<UintPtrT> index_word = ValidateAtomicAccess(array, index, context);
|
||||||
|
|
||||||
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
|
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
|
||||||
@ -313,16 +387,30 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
|
|
||||||
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
|
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
|
||||||
i64(this), u64(this), big(this), other(this);
|
i64(this), u64(this), big(this), other(this);
|
||||||
|
|
||||||
|
// 3. Let arrayTypeName be typedArray.[[TypedArrayName]].
|
||||||
|
// 4. If typedArray.[[ContentType]] is BigInt, let v be ? ToBigInt(value).
|
||||||
STATIC_ASSERT(BIGINT64_ELEMENTS > INT32_ELEMENTS);
|
STATIC_ASSERT(BIGINT64_ELEMENTS > INT32_ELEMENTS);
|
||||||
STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS);
|
STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS);
|
||||||
GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &big);
|
GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &big);
|
||||||
|
|
||||||
|
// 5. Otherwise, let v be ? ToInteger(value).
|
||||||
TNode<Number> value_integer = ToInteger_Inline(context, value);
|
TNode<Number> value_integer = ToInteger_Inline(context, value);
|
||||||
|
|
||||||
|
// 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||||
|
// 7. NOTE: The above check is not redundant with the check in
|
||||||
|
// ValidateIntegerTypedArray because the call to ToBigInt or ToInteger on the
|
||||||
|
// preceding lines can have arbitrary side effects, which could cause the
|
||||||
|
// buffer to become detached.
|
||||||
|
GotoIf(IsDetachedBuffer(array_buffer), &detached);
|
||||||
|
|
||||||
DebugSanityCheckAtomicIndex(array, index_word);
|
DebugSanityCheckAtomicIndex(array, index_word);
|
||||||
|
|
||||||
TNode<Word32T> value_word32 = TruncateTaggedToWord32(context, value_integer);
|
TNode<Word32T> value_word32 = TruncateTaggedToWord32(context, value_integer);
|
||||||
|
|
||||||
|
// Steps 8-12.
|
||||||
|
//
|
||||||
|
// (Not copied from ecma262 due to the axiomatic nature of the memory model.)
|
||||||
int32_t case_values[] = {
|
int32_t case_values[] = {
|
||||||
INT8_ELEMENTS, UINT8_ELEMENTS, INT16_ELEMENTS,
|
INT8_ELEMENTS, UINT8_ELEMENTS, INT16_ELEMENTS,
|
||||||
UINT16_ELEMENTS, INT32_ELEMENTS, UINT32_ELEMENTS,
|
UINT16_ELEMENTS, INT32_ELEMENTS, UINT32_ELEMENTS,
|
||||||
@ -360,8 +448,12 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
WordShl(index_word, 2), value_word32)));
|
WordShl(index_word, 2), value_word32)));
|
||||||
|
|
||||||
BIND(&big);
|
BIND(&big);
|
||||||
|
// 4. If typedArray.[[ContentType]] is BigInt, let v be ? ToBigInt(value).
|
||||||
TNode<BigInt> value_bigint = ToBigInt(context, value);
|
TNode<BigInt> value_bigint = ToBigInt(context, value);
|
||||||
|
|
||||||
|
// 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||||
|
GotoIf(IsDetachedBuffer(array_buffer), &detached);
|
||||||
|
|
||||||
DebugSanityCheckAtomicIndex(array, index_word);
|
DebugSanityCheckAtomicIndex(array, index_word);
|
||||||
|
|
||||||
TVARIABLE(UintPtrT, var_low);
|
TVARIABLE(UintPtrT, var_low);
|
||||||
@ -388,6 +480,12 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
// This shouldn't happen, we've already validated the type.
|
// This shouldn't happen, we've already validated the type.
|
||||||
BIND(&other);
|
BIND(&other);
|
||||||
Unreachable();
|
Unreachable();
|
||||||
|
|
||||||
|
BIND(&detached);
|
||||||
|
{
|
||||||
|
ThrowTypeError(context, MessageTemplate::kDetachedOperation,
|
||||||
|
"Atomics.exchange");
|
||||||
|
}
|
||||||
#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
|
#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,12 +497,15 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
TNode<Object> new_value = CAST(Parameter(Descriptor::kNewValue));
|
TNode<Object> new_value = CAST(Parameter(Descriptor::kNewValue));
|
||||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||||
|
|
||||||
|
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray).
|
||||||
|
Label detached(this);
|
||||||
TNode<Int32T> elements_kind;
|
TNode<Int32T> elements_kind;
|
||||||
TNode<RawPtrT> backing_store;
|
TNode<RawPtrT> backing_store;
|
||||||
ValidateSharedTypedArray(maybe_array, context, &elements_kind,
|
TNode<JSArrayBuffer> array_buffer = ValidateIntegerTypedArray(
|
||||||
&backing_store);
|
maybe_array, context, &elements_kind, &backing_store, &detached);
|
||||||
TNode<JSTypedArray> array = CAST(maybe_array);
|
TNode<JSTypedArray> array = CAST(maybe_array);
|
||||||
|
|
||||||
|
// 2. Let i be ? ValidateAtomicAccess(typedArray, index).
|
||||||
TNode<UintPtrT> index_word = ValidateAtomicAccess(array, index, context);
|
TNode<UintPtrT> index_word = ValidateAtomicAccess(array, index, context);
|
||||||
|
|
||||||
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \
|
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \
|
||||||
@ -415,13 +516,28 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
#else
|
#else
|
||||||
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
|
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
|
||||||
i64(this), u64(this), big(this), other(this);
|
i64(this), u64(this), big(this), other(this);
|
||||||
|
|
||||||
|
// 3. Let arrayTypeName be typedArray.[[TypedArrayName]].
|
||||||
|
// 4. If typedArray.[[ContentType]] is BigInt, then
|
||||||
|
// a. Let expected be ? ToBigInt(expectedValue).
|
||||||
|
// b. Let replacement be ? ToBigInt(replacementValue).
|
||||||
STATIC_ASSERT(BIGINT64_ELEMENTS > INT32_ELEMENTS);
|
STATIC_ASSERT(BIGINT64_ELEMENTS > INT32_ELEMENTS);
|
||||||
STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS);
|
STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS);
|
||||||
GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &big);
|
GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &big);
|
||||||
|
|
||||||
|
// 5. Else,
|
||||||
|
// a. Let expected be ? ToInteger(expectedValue).
|
||||||
|
// b. Let replacement be ? ToInteger(replacementValue).
|
||||||
TNode<Number> old_value_integer = ToInteger_Inline(context, old_value);
|
TNode<Number> old_value_integer = ToInteger_Inline(context, old_value);
|
||||||
TNode<Number> new_value_integer = ToInteger_Inline(context, new_value);
|
TNode<Number> new_value_integer = ToInteger_Inline(context, new_value);
|
||||||
|
|
||||||
|
// 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||||
|
// 7. NOTE: The above check is not redundant with the check in
|
||||||
|
// ValidateIntegerTypedArray because the call to ToBigInt or ToInteger on the
|
||||||
|
// preceding lines can have arbitrary side effects, which could cause the
|
||||||
|
// buffer to become detached.
|
||||||
|
GotoIf(IsDetachedBuffer(array_buffer), &detached);
|
||||||
|
|
||||||
DebugSanityCheckAtomicIndex(array, index_word);
|
DebugSanityCheckAtomicIndex(array, index_word);
|
||||||
|
|
||||||
TNode<Word32T> old_value_word32 =
|
TNode<Word32T> old_value_word32 =
|
||||||
@ -429,6 +545,9 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
TNode<Word32T> new_value_word32 =
|
TNode<Word32T> new_value_word32 =
|
||||||
TruncateTaggedToWord32(context, new_value_integer);
|
TruncateTaggedToWord32(context, new_value_integer);
|
||||||
|
|
||||||
|
// Steps 8-14.
|
||||||
|
//
|
||||||
|
// (Not copied from ecma262 due to the axiomatic nature of the memory model.)
|
||||||
int32_t case_values[] = {
|
int32_t case_values[] = {
|
||||||
INT8_ELEMENTS, UINT8_ELEMENTS, INT16_ELEMENTS,
|
INT8_ELEMENTS, UINT8_ELEMENTS, INT16_ELEMENTS,
|
||||||
UINT16_ELEMENTS, INT32_ELEMENTS, UINT32_ELEMENTS,
|
UINT16_ELEMENTS, INT32_ELEMENTS, UINT32_ELEMENTS,
|
||||||
@ -470,9 +589,15 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
old_value_word32, new_value_word32)));
|
old_value_word32, new_value_word32)));
|
||||||
|
|
||||||
BIND(&big);
|
BIND(&big);
|
||||||
|
// 4. If typedArray.[[ContentType]] is BigInt, then
|
||||||
|
// a. Let expected be ? ToBigInt(expectedValue).
|
||||||
|
// b. Let replacement be ? ToBigInt(replacementValue).
|
||||||
TNode<BigInt> old_value_bigint = ToBigInt(context, old_value);
|
TNode<BigInt> old_value_bigint = ToBigInt(context, old_value);
|
||||||
TNode<BigInt> new_value_bigint = ToBigInt(context, new_value);
|
TNode<BigInt> new_value_bigint = ToBigInt(context, new_value);
|
||||||
|
|
||||||
|
// 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||||
|
GotoIf(IsDetachedBuffer(array_buffer), &detached);
|
||||||
|
|
||||||
DebugSanityCheckAtomicIndex(array, index_word);
|
DebugSanityCheckAtomicIndex(array, index_word);
|
||||||
|
|
||||||
TVARIABLE(UintPtrT, var_old_low);
|
TVARIABLE(UintPtrT, var_old_low);
|
||||||
@ -503,11 +628,17 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
// This shouldn't happen, we've already validated the type.
|
// This shouldn't happen, we've already validated the type.
|
||||||
BIND(&other);
|
BIND(&other);
|
||||||
Unreachable();
|
Unreachable();
|
||||||
|
|
||||||
|
BIND(&detached);
|
||||||
|
{
|
||||||
|
ThrowTypeError(context, MessageTemplate::kDetachedOperation,
|
||||||
|
"Atomics.store");
|
||||||
|
}
|
||||||
#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64
|
#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64
|
||||||
// || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X
|
// || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BINOP_BUILTIN(op) \
|
#define BINOP_BUILTIN(op, method_name) \
|
||||||
TF_BUILTIN(Atomics##op, SharedArrayBufferBuiltinsAssembler) { \
|
TF_BUILTIN(Atomics##op, SharedArrayBufferBuiltinsAssembler) { \
|
||||||
TNode<Object> array = CAST(Parameter(Descriptor::kArray)); \
|
TNode<Object> array = CAST(Parameter(Descriptor::kArray)); \
|
||||||
TNode<Object> index = CAST(Parameter(Descriptor::kIndex)); \
|
TNode<Object> index = CAST(Parameter(Descriptor::kIndex)); \
|
||||||
@ -515,31 +646,34 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) {
|
|||||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext)); \
|
TNode<Context> context = CAST(Parameter(Descriptor::kContext)); \
|
||||||
AtomicBinopBuiltinCommon(array, index, value, context, \
|
AtomicBinopBuiltinCommon(array, index, value, context, \
|
||||||
&CodeAssembler::Atomic##op, \
|
&CodeAssembler::Atomic##op, \
|
||||||
Runtime::kAtomics##op); \
|
Runtime::kAtomics##op, method_name); \
|
||||||
}
|
}
|
||||||
// https://tc39.es/ecma262/#sec-atomics.add
|
// https://tc39.es/ecma262/#sec-atomics.add
|
||||||
BINOP_BUILTIN(Add)
|
BINOP_BUILTIN(Add, "Atomics.add")
|
||||||
// https://tc39.es/ecma262/#sec-atomics.sub
|
// https://tc39.es/ecma262/#sec-atomics.sub
|
||||||
BINOP_BUILTIN(Sub)
|
BINOP_BUILTIN(Sub, "Atomics.sub")
|
||||||
// https://tc39.es/ecma262/#sec-atomics.and
|
// https://tc39.es/ecma262/#sec-atomics.and
|
||||||
BINOP_BUILTIN(And)
|
BINOP_BUILTIN(And, "Atomics.and")
|
||||||
// https://tc39.es/ecma262/#sec-atomics.or
|
// https://tc39.es/ecma262/#sec-atomics.or
|
||||||
BINOP_BUILTIN(Or)
|
BINOP_BUILTIN(Or, "Atomics.or")
|
||||||
// https://tc39.es/ecma262/#sec-atomics.xor
|
// https://tc39.es/ecma262/#sec-atomics.xor
|
||||||
BINOP_BUILTIN(Xor)
|
BINOP_BUILTIN(Xor, "Atomics.xor")
|
||||||
#undef BINOP_BUILTIN
|
#undef BINOP_BUILTIN
|
||||||
|
|
||||||
// https://tc39.es/ecma262/#sec-atomicreadmodifywrite
|
// https://tc39.es/ecma262/#sec-atomicreadmodifywrite
|
||||||
void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon(
|
void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon(
|
||||||
TNode<Object> maybe_array, TNode<Object> index, TNode<Object> value,
|
TNode<Object> maybe_array, TNode<Object> index, TNode<Object> value,
|
||||||
TNode<Context> context, AssemblerFunction function,
|
TNode<Context> context, AssemblerFunction function,
|
||||||
Runtime::FunctionId runtime_function) {
|
Runtime::FunctionId runtime_function, const char* method_name) {
|
||||||
|
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray).
|
||||||
|
Label detached(this);
|
||||||
TNode<Int32T> elements_kind;
|
TNode<Int32T> elements_kind;
|
||||||
TNode<RawPtrT> backing_store;
|
TNode<RawPtrT> backing_store;
|
||||||
ValidateSharedTypedArray(maybe_array, context, &elements_kind,
|
TNode<JSArrayBuffer> array_buffer = ValidateIntegerTypedArray(
|
||||||
&backing_store);
|
maybe_array, context, &elements_kind, &backing_store, &detached);
|
||||||
TNode<JSTypedArray> array = CAST(maybe_array);
|
TNode<JSTypedArray> array = CAST(maybe_array);
|
||||||
|
|
||||||
|
// 2. Let i be ? ValidateAtomicAccess(typedArray, index).
|
||||||
TNode<UintPtrT> index_word = ValidateAtomicAccess(array, index, context);
|
TNode<UintPtrT> index_word = ValidateAtomicAccess(array, index, context);
|
||||||
|
|
||||||
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \
|
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \
|
||||||
@ -550,16 +684,29 @@ void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon(
|
|||||||
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
|
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
|
||||||
i64(this), u64(this), big(this), other(this);
|
i64(this), u64(this), big(this), other(this);
|
||||||
|
|
||||||
|
// 3. Let arrayTypeName be typedArray.[[TypedArrayName]].
|
||||||
|
// 4. If typedArray.[[ContentType]] is BigInt, let v be ? ToBigInt(value).
|
||||||
STATIC_ASSERT(BIGINT64_ELEMENTS > INT32_ELEMENTS);
|
STATIC_ASSERT(BIGINT64_ELEMENTS > INT32_ELEMENTS);
|
||||||
STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS);
|
STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS);
|
||||||
GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &big);
|
GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &big);
|
||||||
|
|
||||||
|
// 5. Otherwise, let v be ? ToInteger(value).
|
||||||
TNode<Number> value_integer = ToInteger_Inline(context, value);
|
TNode<Number> value_integer = ToInteger_Inline(context, value);
|
||||||
|
|
||||||
|
// 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||||
|
// 7. NOTE: The above check is not redundant with the check in
|
||||||
|
// ValidateIntegerTypedArray because the call to ToBigInt or ToInteger on the
|
||||||
|
// preceding lines can have arbitrary side effects, which could cause the
|
||||||
|
// buffer to become detached.
|
||||||
|
GotoIf(IsDetachedBuffer(array_buffer), &detached);
|
||||||
|
|
||||||
DebugSanityCheckAtomicIndex(array, index_word);
|
DebugSanityCheckAtomicIndex(array, index_word);
|
||||||
|
|
||||||
TNode<Word32T> value_word32 = TruncateTaggedToWord32(context, value_integer);
|
TNode<Word32T> value_word32 = TruncateTaggedToWord32(context, value_integer);
|
||||||
|
|
||||||
|
// Steps 8-12.
|
||||||
|
//
|
||||||
|
// (Not copied from ecma262 due to the axiomatic nature of the memory model.)
|
||||||
int32_t case_values[] = {
|
int32_t case_values[] = {
|
||||||
INT8_ELEMENTS, UINT8_ELEMENTS, INT16_ELEMENTS,
|
INT8_ELEMENTS, UINT8_ELEMENTS, INT16_ELEMENTS,
|
||||||
UINT16_ELEMENTS, INT32_ELEMENTS, UINT32_ELEMENTS,
|
UINT16_ELEMENTS, INT32_ELEMENTS, UINT32_ELEMENTS,
|
||||||
@ -599,8 +746,12 @@ void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon(
|
|||||||
WordShl(index_word, 2), value_word32, nullptr)));
|
WordShl(index_word, 2), value_word32, nullptr)));
|
||||||
|
|
||||||
BIND(&big);
|
BIND(&big);
|
||||||
|
// 4. If typedArray.[[ContentType]] is BigInt, let v be ? ToBigInt(value).
|
||||||
TNode<BigInt> value_bigint = ToBigInt(context, value);
|
TNode<BigInt> value_bigint = ToBigInt(context, value);
|
||||||
|
|
||||||
|
// 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||||
|
GotoIf(IsDetachedBuffer(array_buffer), &detached);
|
||||||
|
|
||||||
DebugSanityCheckAtomicIndex(array, index_word);
|
DebugSanityCheckAtomicIndex(array, index_word);
|
||||||
|
|
||||||
TVARIABLE(UintPtrT, var_low);
|
TVARIABLE(UintPtrT, var_low);
|
||||||
@ -627,6 +778,9 @@ void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon(
|
|||||||
// This shouldn't happen, we've already validated the type.
|
// This shouldn't happen, we've already validated the type.
|
||||||
BIND(&other);
|
BIND(&other);
|
||||||
Unreachable();
|
Unreachable();
|
||||||
|
|
||||||
|
BIND(&detached);
|
||||||
|
ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
|
||||||
#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64
|
#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64
|
||||||
// || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X
|
// || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,9 @@ namespace v8 {
|
|||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
// See builtins-arraybuffer.cc for implementations of
|
// See builtins-arraybuffer.cc for implementations of
|
||||||
// SharedArrayBuffer.prototye.byteLength and SharedArrayBuffer.prototype.slice
|
// SharedArrayBuffer.prototype.byteLength and SharedArrayBuffer.prototype.slice
|
||||||
|
|
||||||
// #sec-atomics.islockfree
|
// https://tc39.es/ecma262/#sec-atomics.islockfree
|
||||||
inline bool AtomicIsLockFree(double size) {
|
inline bool AtomicIsLockFree(double size) {
|
||||||
// According to the standard, 1, 2, and 4 byte atomics are supposed to be
|
// According to the standard, 1, 2, and 4 byte atomics are supposed to be
|
||||||
// 'lock free' on every platform. 'Lock free' means that all possible uses of
|
// 'lock free' on every platform. 'Lock free' means that all possible uses of
|
||||||
@ -39,7 +39,7 @@ inline bool AtomicIsLockFree(double size) {
|
|||||||
return size == 1 || size == 2 || size == 4 || size == 8;
|
return size == 1 || size == 2 || size == 4 || size == 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES #sec-atomics.islockfree
|
// https://tc39.es/ecma262/#sec-atomics.islockfree
|
||||||
BUILTIN(AtomicsIsLockFree) {
|
BUILTIN(AtomicsIsLockFree) {
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
Handle<Object> size = args.atOrUndefined(isolate, 1);
|
Handle<Object> size = args.atOrUndefined(isolate, 1);
|
||||||
@ -48,37 +48,45 @@ BUILTIN(AtomicsIsLockFree) {
|
|||||||
return *isolate->factory()->ToBoolean(AtomicIsLockFree(size->Number()));
|
return *isolate->factory()->ToBoolean(AtomicIsLockFree(size->Number()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES #sec-validatesharedintegertypedarray
|
// https://tc39.es/ecma262/#sec-validatesharedintegertypedarray
|
||||||
V8_WARN_UNUSED_RESULT MaybeHandle<JSTypedArray> ValidateSharedIntegerTypedArray(
|
V8_WARN_UNUSED_RESULT MaybeHandle<JSTypedArray> ValidateIntegerTypedArray(
|
||||||
Isolate* isolate, Handle<Object> object,
|
Isolate* isolate, Handle<Object> object, const char* method_name,
|
||||||
bool only_int32_and_big_int64 = false) {
|
bool only_int32_and_big_int64 = false) {
|
||||||
if (object->IsJSTypedArray()) {
|
if (object->IsJSTypedArray()) {
|
||||||
Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object);
|
Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object);
|
||||||
if (typed_array->GetBuffer()->is_shared()) {
|
|
||||||
if (only_int32_and_big_int64) {
|
if (typed_array->WasDetached()) {
|
||||||
if (typed_array->type() == kExternalInt32Array ||
|
THROW_NEW_ERROR(
|
||||||
typed_array->type() == kExternalBigInt64Array) {
|
isolate,
|
||||||
return typed_array;
|
NewTypeError(
|
||||||
}
|
MessageTemplate::kDetachedOperation,
|
||||||
} else {
|
isolate->factory()->NewStringFromAsciiChecked(method_name)),
|
||||||
if (typed_array->type() != kExternalFloat32Array &&
|
JSTypedArray);
|
||||||
typed_array->type() != kExternalFloat64Array &&
|
}
|
||||||
typed_array->type() != kExternalUint8ClampedArray)
|
|
||||||
return typed_array;
|
if (only_int32_and_big_int64) {
|
||||||
|
if (typed_array->type() == kExternalInt32Array ||
|
||||||
|
typed_array->type() == kExternalBigInt64Array) {
|
||||||
|
return typed_array;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (typed_array->type() != kExternalFloat32Array &&
|
||||||
|
typed_array->type() != kExternalFloat64Array &&
|
||||||
|
typed_array->type() != kExternalUint8ClampedArray)
|
||||||
|
return typed_array;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
THROW_NEW_ERROR(
|
THROW_NEW_ERROR(
|
||||||
isolate,
|
isolate,
|
||||||
NewTypeError(only_int32_and_big_int64
|
NewTypeError(only_int32_and_big_int64
|
||||||
? MessageTemplate::kNotInt32OrBigInt64SharedTypedArray
|
? MessageTemplate::kNotInt32OrBigInt64TypedArray
|
||||||
: MessageTemplate::kNotIntegerSharedTypedArray,
|
: MessageTemplate::kNotIntegerTypedArray,
|
||||||
object),
|
object),
|
||||||
JSTypedArray);
|
JSTypedArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES #sec-validateatomicaccess
|
// https://tc39.es/ecma262/#sec-validateatomicaccess
|
||||||
// ValidateAtomicAccess( typedArray, requestIndex )
|
// ValidateAtomicAccess( typedArray, requestIndex )
|
||||||
V8_WARN_UNUSED_RESULT Maybe<size_t> ValidateAtomicAccess(
|
V8_WARN_UNUSED_RESULT Maybe<size_t> ValidateAtomicAccess(
|
||||||
Isolate* isolate, Handle<JSTypedArray> typed_array,
|
Isolate* isolate, Handle<JSTypedArray> typed_array,
|
||||||
@ -91,8 +99,9 @@ V8_WARN_UNUSED_RESULT Maybe<size_t> ValidateAtomicAccess(
|
|||||||
Nothing<size_t>());
|
Nothing<size_t>());
|
||||||
|
|
||||||
size_t access_index;
|
size_t access_index;
|
||||||
|
size_t typed_array_length = typed_array->length();
|
||||||
if (!TryNumberToSize(*access_index_obj, &access_index) ||
|
if (!TryNumberToSize(*access_index_obj, &access_index) ||
|
||||||
typed_array->WasDetached() || access_index >= typed_array->length()) {
|
access_index >= typed_array_length) {
|
||||||
isolate->Throw(*isolate->factory()->NewRangeError(
|
isolate->Throw(*isolate->factory()->NewRangeError(
|
||||||
MessageTemplate::kInvalidAtomicAccessIndex));
|
MessageTemplate::kInvalidAtomicAccessIndex));
|
||||||
return Nothing<size_t>();
|
return Nothing<size_t>();
|
||||||
@ -122,12 +131,18 @@ BUILTIN(AtomicsNotify) {
|
|||||||
|
|
||||||
Handle<JSTypedArray> sta;
|
Handle<JSTypedArray> sta;
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||||
isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true));
|
isolate, sta,
|
||||||
|
ValidateIntegerTypedArray(isolate, array, "Atomics.notify", true));
|
||||||
|
|
||||||
|
// 2. Let i be ? ValidateAtomicAccess(typedArray, index).
|
||||||
Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
|
Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
|
||||||
if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
|
if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
|
||||||
size_t i = maybe_index.FromJust();
|
size_t i = maybe_index.FromJust();
|
||||||
|
|
||||||
|
// 3. If count is undefined, let c be +∞.
|
||||||
|
// 4. Else,
|
||||||
|
// a. Let intCount be ? ToInteger(count).
|
||||||
|
// b. Let c be max(intCount, 0).
|
||||||
uint32_t c;
|
uint32_t c;
|
||||||
if (count->IsUndefined(isolate)) {
|
if (count->IsUndefined(isolate)) {
|
||||||
c = kMaxUInt32;
|
c = kMaxUInt32;
|
||||||
@ -143,9 +158,17 @@ BUILTIN(AtomicsNotify) {
|
|||||||
c = static_cast<uint32_t>(count_double);
|
c = static_cast<uint32_t>(count_double);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Steps 5-9 performed in FutexEmulation::Wake.
|
||||||
|
|
||||||
|
// 10. If IsSharedArrayBuffer(buffer) is false, return 0.
|
||||||
Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
|
Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
|
||||||
size_t wake_addr;
|
size_t wake_addr;
|
||||||
|
|
||||||
|
if (V8_UNLIKELY(!sta->GetBuffer()->is_shared())) {
|
||||||
|
return Smi::FromInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 11-17 performed in FutexEmulation::Wake.
|
||||||
if (sta->type() == kExternalBigInt64Array) {
|
if (sta->type() == kExternalBigInt64Array) {
|
||||||
wake_addr = GetAddress64(i, sta->byte_offset());
|
wake_addr = GetAddress64(i, sta->byte_offset());
|
||||||
} else {
|
} else {
|
||||||
@ -158,19 +181,26 @@ BUILTIN(AtomicsNotify) {
|
|||||||
Object DoWait(Isolate* isolate, FutexEmulation::WaitMode mode,
|
Object DoWait(Isolate* isolate, FutexEmulation::WaitMode mode,
|
||||||
Handle<Object> array, Handle<Object> index, Handle<Object> value,
|
Handle<Object> array, Handle<Object> index, Handle<Object> value,
|
||||||
Handle<Object> timeout) {
|
Handle<Object> timeout) {
|
||||||
// 1. Let buffer be ? ValidateSharedIntegerTypedArray(typedArray, true).
|
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray, true).
|
||||||
Handle<JSTypedArray> sta;
|
Handle<JSTypedArray> sta;
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||||
isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true));
|
isolate, sta,
|
||||||
|
ValidateIntegerTypedArray(isolate, array, "Atomics.wait", true));
|
||||||
|
|
||||||
// 2. Let i be ? ValidateAtomicAccess(typedArray, index).
|
// 2. If IsSharedArrayBuffer(buffer) is false, throw a TypeError exception.
|
||||||
|
if (V8_UNLIKELY(!sta->GetBuffer()->is_shared())) {
|
||||||
|
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||||
|
isolate, NewTypeError(MessageTemplate::kNotSharedTypedArray, array));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Let i be ? ValidateAtomicAccess(typedArray, index).
|
||||||
Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
|
Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
|
||||||
if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
|
if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
|
||||||
size_t i = maybe_index.FromJust();
|
size_t i = maybe_index.FromJust();
|
||||||
|
|
||||||
// 3. Let arrayTypeName be typedArray.[[TypedArrayName]].
|
// 4. Let arrayTypeName be typedArray.[[TypedArrayName]].
|
||||||
// 4. If arrayTypeName is "BigInt64Array", let v be ? ToBigInt64(value).
|
// 5. If arrayTypeName is "BigInt64Array", let v be ? ToBigInt64(value).
|
||||||
// 5. Otherwise, let v be ? ToInt32(value).
|
// 6. Otherwise, let v be ? ToInt32(value).
|
||||||
if (sta->type() == kExternalBigInt64Array) {
|
if (sta->type() == kExternalBigInt64Array) {
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
|
||||||
BigInt::FromObject(isolate, value));
|
BigInt::FromObject(isolate, value));
|
||||||
@ -180,8 +210,8 @@ Object DoWait(Isolate* isolate, FutexEmulation::WaitMode mode,
|
|||||||
Object::ToInt32(isolate, value));
|
Object::ToInt32(isolate, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Let q be ? ToNumber(timeout).
|
// 7. Let q be ? ToNumber(timeout).
|
||||||
// 7. If q is NaN, let t be +∞, else let t be max(q, 0).
|
// 8. If q is NaN, let t be +∞, else let t be max(q, 0).
|
||||||
double timeout_number;
|
double timeout_number;
|
||||||
if (timeout->IsUndefined(isolate)) {
|
if (timeout->IsUndefined(isolate)) {
|
||||||
timeout_number = ReadOnlyRoots(isolate).infinity_value().Number();
|
timeout_number = ReadOnlyRoots(isolate).infinity_value().Number();
|
||||||
@ -195,7 +225,7 @@ Object DoWait(Isolate* isolate, FutexEmulation::WaitMode mode,
|
|||||||
timeout_number = 0;
|
timeout_number = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8. If mode is sync, then
|
// 9. If mode is sync, then
|
||||||
// a. Let B be AgentCanSuspend().
|
// a. Let B be AgentCanSuspend().
|
||||||
// b. If B is false, throw a TypeError exception.
|
// b. If B is false, throw a TypeError exception.
|
||||||
if (mode == FutexEmulation::WaitMode::kSync &&
|
if (mode == FutexEmulation::WaitMode::kSync &&
|
||||||
@ -218,7 +248,7 @@ Object DoWait(Isolate* isolate, FutexEmulation::WaitMode mode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES #sec-atomics.wait
|
// https://tc39.es/ecma262/#sec-atomics.wait
|
||||||
// Atomics.wait( typedArray, index, value, timeout )
|
// Atomics.wait( typedArray, index, value, timeout )
|
||||||
BUILTIN(AtomicsWait) {
|
BUILTIN(AtomicsWait) {
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
|
@ -231,28 +231,6 @@ TNode<JSFunction> TypedArrayBuiltinsAssembler::GetDefaultConstructor(
|
|||||||
LoadContextElement(LoadNativeContext(context), context_slot.value()));
|
LoadContextElement(LoadNativeContext(context), context_slot.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::GetBuffer(
|
|
||||||
TNode<Context> context, TNode<JSTypedArray> array) {
|
|
||||||
Label call_runtime(this), done(this);
|
|
||||||
TVARIABLE(Object, var_result);
|
|
||||||
|
|
||||||
TNode<JSArrayBuffer> buffer = LoadJSArrayBufferViewBuffer(array);
|
|
||||||
GotoIf(IsDetachedBuffer(buffer), &call_runtime);
|
|
||||||
TNode<RawPtrT> backing_store = LoadJSArrayBufferBackingStorePtr(buffer);
|
|
||||||
GotoIf(WordEqual(backing_store, IntPtrConstant(0)), &call_runtime);
|
|
||||||
var_result = buffer;
|
|
||||||
Goto(&done);
|
|
||||||
|
|
||||||
BIND(&call_runtime);
|
|
||||||
{
|
|
||||||
var_result = CallRuntime(Runtime::kTypedArrayGetBuffer, context, array);
|
|
||||||
Goto(&done);
|
|
||||||
}
|
|
||||||
|
|
||||||
BIND(&done);
|
|
||||||
return CAST(var_result.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
TNode<JSTypedArray> TypedArrayBuiltinsAssembler::ValidateTypedArray(
|
TNode<JSTypedArray> TypedArrayBuiltinsAssembler::ValidateTypedArray(
|
||||||
TNode<Context> context, TNode<Object> obj, const char* method_name) {
|
TNode<Context> context, TNode<Object> obj, const char* method_name) {
|
||||||
// If it is not a typed array, throw
|
// If it is not a typed array, throw
|
||||||
|
@ -45,9 +45,6 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
|
|||||||
TNode<JSFunction> GetDefaultConstructor(TNode<Context> context,
|
TNode<JSFunction> GetDefaultConstructor(TNode<Context> context,
|
||||||
TNode<JSTypedArray> exemplar);
|
TNode<JSTypedArray> exemplar);
|
||||||
|
|
||||||
TNode<JSArrayBuffer> GetBuffer(TNode<Context> context,
|
|
||||||
TNode<JSTypedArray> array);
|
|
||||||
|
|
||||||
TNode<JSTypedArray> ValidateTypedArray(TNode<Context> context,
|
TNode<JSTypedArray> ValidateTypedArray(TNode<Context> context,
|
||||||
TNode<Object> obj,
|
TNode<Object> obj,
|
||||||
const char* method_name);
|
const char* method_name);
|
||||||
|
@ -17,7 +17,7 @@ transitioning javascript builtin TypedArrayPrototypeSubArray(
|
|||||||
MessageTemplate::kIncompatibleMethodReceiver, methodName);
|
MessageTemplate::kIncompatibleMethodReceiver, methodName);
|
||||||
|
|
||||||
// 5. Let buffer be O.[[ViewedArrayBuffer]].
|
// 5. Let buffer be O.[[ViewedArrayBuffer]].
|
||||||
const buffer = typed_array::GetBuffer(source);
|
const buffer = typed_array::GetTypedArrayBuffer(source);
|
||||||
|
|
||||||
// 6. Let srcLength be O.[[ArrayLength]].
|
// 6. Let srcLength be O.[[ArrayLength]].
|
||||||
const srcLength: uintptr = source.length;
|
const srcLength: uintptr = source.length;
|
||||||
|
@ -63,8 +63,8 @@ extern macro TypedArrayBuiltinsAssembler::CallCMemmove(
|
|||||||
RawPtr, RawPtr, uintptr): void;
|
RawPtr, RawPtr, uintptr): void;
|
||||||
extern macro TypedArrayBuiltinsAssembler::CallCMemset(
|
extern macro TypedArrayBuiltinsAssembler::CallCMemset(
|
||||||
RawPtr, intptr, uintptr): void;
|
RawPtr, intptr, uintptr): void;
|
||||||
extern macro TypedArrayBuiltinsAssembler::GetBuffer(implicit context: Context)(
|
extern macro GetTypedArrayBuffer(implicit context: Context)(JSTypedArray):
|
||||||
JSTypedArray): JSArrayBuffer;
|
JSArrayBuffer;
|
||||||
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
|
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
|
||||||
JSTypedArray): TypedArrayElementsInfo;
|
JSTypedArray): TypedArrayElementsInfo;
|
||||||
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(Map):
|
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(Map):
|
||||||
|
@ -12528,6 +12528,28 @@ TNode<UintPtrT> CodeStubAssembler::LoadJSTypedArrayLength(
|
|||||||
return LoadObjectField<UintPtrT>(typed_array, JSTypedArray::kLengthOffset);
|
return LoadObjectField<UintPtrT>(typed_array, JSTypedArray::kLengthOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TNode<JSArrayBuffer> CodeStubAssembler::GetTypedArrayBuffer(
|
||||||
|
TNode<Context> context, TNode<JSTypedArray> array) {
|
||||||
|
Label call_runtime(this), done(this);
|
||||||
|
TVARIABLE(Object, var_result);
|
||||||
|
|
||||||
|
TNode<JSArrayBuffer> buffer = LoadJSArrayBufferViewBuffer(array);
|
||||||
|
GotoIf(IsDetachedBuffer(buffer), &call_runtime);
|
||||||
|
TNode<RawPtrT> backing_store = LoadJSArrayBufferBackingStorePtr(buffer);
|
||||||
|
GotoIf(WordEqual(backing_store, IntPtrConstant(0)), &call_runtime);
|
||||||
|
var_result = buffer;
|
||||||
|
Goto(&done);
|
||||||
|
|
||||||
|
BIND(&call_runtime);
|
||||||
|
{
|
||||||
|
var_result = CallRuntime(Runtime::kTypedArrayGetBuffer, context, array);
|
||||||
|
Goto(&done);
|
||||||
|
}
|
||||||
|
|
||||||
|
BIND(&done);
|
||||||
|
return CAST(var_result.value());
|
||||||
|
}
|
||||||
|
|
||||||
CodeStubArguments::CodeStubArguments(CodeStubAssembler* assembler,
|
CodeStubArguments::CodeStubArguments(CodeStubAssembler* assembler,
|
||||||
TNode<IntPtrT> argc, TNode<RawPtrT> fp)
|
TNode<IntPtrT> argc, TNode<RawPtrT> fp)
|
||||||
: assembler_(assembler),
|
: assembler_(assembler),
|
||||||
|
@ -3442,6 +3442,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
|||||||
// JSTypedArray helpers
|
// JSTypedArray helpers
|
||||||
TNode<UintPtrT> LoadJSTypedArrayLength(TNode<JSTypedArray> typed_array);
|
TNode<UintPtrT> LoadJSTypedArrayLength(TNode<JSTypedArray> typed_array);
|
||||||
TNode<RawPtrT> LoadJSTypedArrayDataPtr(TNode<JSTypedArray> typed_array);
|
TNode<RawPtrT> LoadJSTypedArrayDataPtr(TNode<JSTypedArray> typed_array);
|
||||||
|
TNode<JSArrayBuffer> GetTypedArrayBuffer(TNode<Context> context,
|
||||||
|
TNode<JSTypedArray> array);
|
||||||
|
|
||||||
template <typename TIndex>
|
template <typename TIndex>
|
||||||
TNode<IntPtrT> ElementOffsetFromIndex(TNode<TIndex> index, ElementsKind kind,
|
TNode<IntPtrT> ElementOffsetFromIndex(TNode<TIndex> index, ElementsKind kind,
|
||||||
|
@ -144,9 +144,10 @@ namespace internal {
|
|||||||
T(NotSuperConstructor, "Super constructor % of % is not a constructor") \
|
T(NotSuperConstructor, "Super constructor % of % is not a constructor") \
|
||||||
T(NotSuperConstructorAnonymousClass, \
|
T(NotSuperConstructorAnonymousClass, \
|
||||||
"Super constructor % of anonymous class is not a constructor") \
|
"Super constructor % of anonymous class is not a constructor") \
|
||||||
T(NotIntegerSharedTypedArray, "% is not an integer shared typed array.") \
|
T(NotIntegerTypedArray, "% is not an integer typed array.") \
|
||||||
T(NotInt32OrBigInt64SharedTypedArray, \
|
T(NotInt32OrBigInt64TypedArray, \
|
||||||
"% is not an int32 or BigInt64 shared typed array.") \
|
"% is not an int32 or BigInt64 typed array.") \
|
||||||
|
T(NotSharedTypedArray, "% is not a shared typed array.") \
|
||||||
T(ObjectGetterExpectingFunction, \
|
T(ObjectGetterExpectingFunction, \
|
||||||
"Object.prototype.__defineGetter__: Expecting function") \
|
"Object.prototype.__defineGetter__: Expecting function") \
|
||||||
T(ObjectGetterCallable, "Getter must be a function: %") \
|
T(ObjectGetterCallable, "Getter must be a function: %") \
|
||||||
|
@ -11,9 +11,8 @@
|
|||||||
#include "src/objects/js-array-buffer-inl.h"
|
#include "src/objects/js-array-buffer-inl.h"
|
||||||
#include "src/runtime/runtime-utils.h"
|
#include "src/runtime/runtime-utils.h"
|
||||||
|
|
||||||
// Implement Atomic accesses to SharedArrayBuffers as defined in the
|
// Implement Atomic accesses to ArrayBuffers and SharedArrayBuffers.
|
||||||
// SharedArrayBuffer draft spec, found here
|
// https://tc39.es/ecma262/#sec-atomics
|
||||||
// https://github.com/tc39/ecmascript_sharedmem
|
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
@ -341,17 +340,27 @@ struct Xor {
|
|||||||
V(Uint32, uint32, UINT32, uint32_t) \
|
V(Uint32, uint32, UINT32, uint32_t) \
|
||||||
V(Int32, int32, INT32, int32_t)
|
V(Int32, int32, INT32, int32_t)
|
||||||
|
|
||||||
|
#define THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta, method_name) \
|
||||||
|
do { \
|
||||||
|
if (V8_UNLIKELY(sta->WasDetached())) { \
|
||||||
|
THROW_NEW_ERROR_RETURN_FAILURE( \
|
||||||
|
isolate, NewTypeError(MessageTemplate::kDetachedOperation, \
|
||||||
|
isolate->factory()->NewStringFromAsciiChecked( \
|
||||||
|
method_name))); \
|
||||||
|
} \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
// This is https://tc39.github.io/ecma262/#sec-getmodifysetvalueinbuffer
|
// This is https://tc39.github.io/ecma262/#sec-getmodifysetvalueinbuffer
|
||||||
// but also includes the ToInteger/ToBigInt conversion that's part of
|
// but also includes the ToInteger/ToBigInt conversion that's part of
|
||||||
// https://tc39.github.io/ecma262/#sec-atomicreadmodifywrite
|
// https://tc39.github.io/ecma262/#sec-atomicreadmodifywrite
|
||||||
template <template <typename> class Op>
|
template <template <typename> class Op>
|
||||||
Object GetModifySetValueInBuffer(RuntimeArguments args, Isolate* isolate) {
|
Object GetModifySetValueInBuffer(RuntimeArguments args, Isolate* isolate,
|
||||||
|
const char* method_name) {
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
DCHECK_EQ(3, args.length());
|
DCHECK_EQ(3, args.length());
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
|
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
|
||||||
CONVERT_SIZE_ARG_CHECKED(index, 1);
|
CONVERT_SIZE_ARG_CHECKED(index, 1);
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, value_obj, 2);
|
CONVERT_ARG_HANDLE_CHECKED(Object, value_obj, 2);
|
||||||
CHECK(sta->GetBuffer()->is_shared());
|
|
||||||
|
|
||||||
uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
|
uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
|
||||||
sta->byte_offset();
|
sta->byte_offset();
|
||||||
@ -360,7 +369,9 @@ Object GetModifySetValueInBuffer(RuntimeArguments args, Isolate* isolate) {
|
|||||||
Handle<BigInt> bigint;
|
Handle<BigInt> bigint;
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, bigint,
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, bigint,
|
||||||
BigInt::FromObject(isolate, value_obj));
|
BigInt::FromObject(isolate, value_obj));
|
||||||
// SharedArrayBuffers are not detachable.
|
|
||||||
|
THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta, method_name);
|
||||||
|
|
||||||
CHECK_LT(index, sta->length());
|
CHECK_LT(index, sta->length());
|
||||||
if (sta->type() == kExternalBigInt64Array) {
|
if (sta->type() == kExternalBigInt64Array) {
|
||||||
return Op<int64_t>::Do(isolate, source, index, bigint);
|
return Op<int64_t>::Do(isolate, source, index, bigint);
|
||||||
@ -372,7 +383,9 @@ Object GetModifySetValueInBuffer(RuntimeArguments args, Isolate* isolate) {
|
|||||||
Handle<Object> value;
|
Handle<Object> value;
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
|
||||||
Object::ToInteger(isolate, value_obj));
|
Object::ToInteger(isolate, value_obj));
|
||||||
// SharedArrayBuffers are not detachable.
|
|
||||||
|
THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta, method_name);
|
||||||
|
|
||||||
CHECK_LT(index, sta->length());
|
CHECK_LT(index, sta->length());
|
||||||
|
|
||||||
switch (sta->type()) {
|
switch (sta->type()) {
|
||||||
@ -395,14 +408,13 @@ RUNTIME_FUNCTION(Runtime_AtomicsLoad64) {
|
|||||||
DCHECK_EQ(2, args.length());
|
DCHECK_EQ(2, args.length());
|
||||||
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
|
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
|
||||||
CONVERT_SIZE_ARG_CHECKED(index, 1);
|
CONVERT_SIZE_ARG_CHECKED(index, 1);
|
||||||
CHECK(sta->GetBuffer()->is_shared());
|
|
||||||
|
|
||||||
uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
|
uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
|
||||||
sta->byte_offset();
|
sta->byte_offset();
|
||||||
|
|
||||||
DCHECK(sta->type() == kExternalBigInt64Array ||
|
DCHECK(sta->type() == kExternalBigInt64Array ||
|
||||||
sta->type() == kExternalBigUint64Array);
|
sta->type() == kExternalBigUint64Array);
|
||||||
// SharedArrayBuffers are not detachable.
|
DCHECK(!sta->WasDetached());
|
||||||
CHECK_LT(index, sta->length());
|
CHECK_LT(index, sta->length());
|
||||||
if (sta->type() == kExternalBigInt64Array) {
|
if (sta->type() == kExternalBigInt64Array) {
|
||||||
return Load<int64_t>::Do(isolate, source, index);
|
return Load<int64_t>::Do(isolate, source, index);
|
||||||
@ -417,7 +429,6 @@ RUNTIME_FUNCTION(Runtime_AtomicsStore64) {
|
|||||||
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
|
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
|
||||||
CONVERT_SIZE_ARG_CHECKED(index, 1);
|
CONVERT_SIZE_ARG_CHECKED(index, 1);
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, value_obj, 2);
|
CONVERT_ARG_HANDLE_CHECKED(Object, value_obj, 2);
|
||||||
CHECK(sta->GetBuffer()->is_shared());
|
|
||||||
|
|
||||||
uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
|
uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
|
||||||
sta->byte_offset();
|
sta->byte_offset();
|
||||||
@ -428,7 +439,7 @@ RUNTIME_FUNCTION(Runtime_AtomicsStore64) {
|
|||||||
|
|
||||||
DCHECK(sta->type() == kExternalBigInt64Array ||
|
DCHECK(sta->type() == kExternalBigInt64Array ||
|
||||||
sta->type() == kExternalBigUint64Array);
|
sta->type() == kExternalBigUint64Array);
|
||||||
// SharedArrayBuffers are not detachable.
|
DCHECK(!sta->WasDetached());
|
||||||
CHECK_LT(index, sta->length());
|
CHECK_LT(index, sta->length());
|
||||||
if (sta->type() == kExternalBigInt64Array) {
|
if (sta->type() == kExternalBigInt64Array) {
|
||||||
Store<int64_t>::Do(isolate, source, index, bigint);
|
Store<int64_t>::Do(isolate, source, index, bigint);
|
||||||
@ -440,7 +451,7 @@ RUNTIME_FUNCTION(Runtime_AtomicsStore64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_AtomicsExchange) {
|
RUNTIME_FUNCTION(Runtime_AtomicsExchange) {
|
||||||
return GetModifySetValueInBuffer<Exchange>(args, isolate);
|
return GetModifySetValueInBuffer<Exchange>(args, isolate, "Atomics.exchange");
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
|
RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
|
||||||
@ -450,7 +461,6 @@ RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
|
|||||||
CONVERT_SIZE_ARG_CHECKED(index, 1);
|
CONVERT_SIZE_ARG_CHECKED(index, 1);
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, old_value_obj, 2);
|
CONVERT_ARG_HANDLE_CHECKED(Object, old_value_obj, 2);
|
||||||
CONVERT_ARG_HANDLE_CHECKED(Object, new_value_obj, 3);
|
CONVERT_ARG_HANDLE_CHECKED(Object, new_value_obj, 3);
|
||||||
CHECK(sta->GetBuffer()->is_shared());
|
|
||||||
CHECK_LT(index, sta->length());
|
CHECK_LT(index, sta->length());
|
||||||
|
|
||||||
uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
|
uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
|
||||||
@ -463,7 +473,10 @@ RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
|
|||||||
isolate, old_bigint, BigInt::FromObject(isolate, old_value_obj));
|
isolate, old_bigint, BigInt::FromObject(isolate, old_value_obj));
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||||
isolate, new_bigint, BigInt::FromObject(isolate, new_value_obj));
|
isolate, new_bigint, BigInt::FromObject(isolate, new_value_obj));
|
||||||
// SharedArrayBuffers are not detachable.
|
|
||||||
|
THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta,
|
||||||
|
"Atomics.compareExchange");
|
||||||
|
|
||||||
CHECK_LT(index, sta->length());
|
CHECK_LT(index, sta->length());
|
||||||
if (sta->type() == kExternalBigInt64Array) {
|
if (sta->type() == kExternalBigInt64Array) {
|
||||||
return DoCompareExchange<int64_t>(isolate, source, index, old_bigint,
|
return DoCompareExchange<int64_t>(isolate, source, index, old_bigint,
|
||||||
@ -480,8 +493,9 @@ RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
|
|||||||
Object::ToInteger(isolate, old_value_obj));
|
Object::ToInteger(isolate, old_value_obj));
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, new_value,
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, new_value,
|
||||||
Object::ToInteger(isolate, new_value_obj));
|
Object::ToInteger(isolate, new_value_obj));
|
||||||
// SharedArrayBuffers are not detachable.
|
|
||||||
CHECK_LT(index, sta->length());
|
THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta,
|
||||||
|
"Atomics.compareExchange");
|
||||||
|
|
||||||
switch (sta->type()) {
|
switch (sta->type()) {
|
||||||
#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype) \
|
#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype) \
|
||||||
@ -502,31 +516,31 @@ RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
|
|||||||
// ES #sec-atomics.add
|
// ES #sec-atomics.add
|
||||||
// Atomics.add( typedArray, index, value )
|
// Atomics.add( typedArray, index, value )
|
||||||
RUNTIME_FUNCTION(Runtime_AtomicsAdd) {
|
RUNTIME_FUNCTION(Runtime_AtomicsAdd) {
|
||||||
return GetModifySetValueInBuffer<Add>(args, isolate);
|
return GetModifySetValueInBuffer<Add>(args, isolate, "Atomics.add");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES #sec-atomics.sub
|
// ES #sec-atomics.sub
|
||||||
// Atomics.sub( typedArray, index, value )
|
// Atomics.sub( typedArray, index, value )
|
||||||
RUNTIME_FUNCTION(Runtime_AtomicsSub) {
|
RUNTIME_FUNCTION(Runtime_AtomicsSub) {
|
||||||
return GetModifySetValueInBuffer<Sub>(args, isolate);
|
return GetModifySetValueInBuffer<Sub>(args, isolate, "Atomics.sub");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES #sec-atomics.and
|
// ES #sec-atomics.and
|
||||||
// Atomics.and( typedArray, index, value )
|
// Atomics.and( typedArray, index, value )
|
||||||
RUNTIME_FUNCTION(Runtime_AtomicsAnd) {
|
RUNTIME_FUNCTION(Runtime_AtomicsAnd) {
|
||||||
return GetModifySetValueInBuffer<And>(args, isolate);
|
return GetModifySetValueInBuffer<And>(args, isolate, "Atomics.and");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES #sec-atomics.or
|
// ES #sec-atomics.or
|
||||||
// Atomics.or( typedArray, index, value )
|
// Atomics.or( typedArray, index, value )
|
||||||
RUNTIME_FUNCTION(Runtime_AtomicsOr) {
|
RUNTIME_FUNCTION(Runtime_AtomicsOr) {
|
||||||
return GetModifySetValueInBuffer<Or>(args, isolate);
|
return GetModifySetValueInBuffer<Or>(args, isolate, "Atomics.or");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ES #sec-atomics.xor
|
// ES #sec-atomics.xor
|
||||||
// Atomics.xor( typedArray, index, value )
|
// Atomics.xor( typedArray, index, value )
|
||||||
RUNTIME_FUNCTION(Runtime_AtomicsXor) {
|
RUNTIME_FUNCTION(Runtime_AtomicsXor) {
|
||||||
return GetModifySetValueInBuffer<Xor>(args, isolate);
|
return GetModifySetValueInBuffer<Xor>(args, isolate, "Atomics.xor");
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef INTEGER_TYPED_ARRAYS
|
#undef INTEGER_TYPED_ARRAYS
|
||||||
|
@ -84,7 +84,7 @@ bytecodes: [
|
|||||||
B(Mov), R(this), R(0),
|
B(Mov), R(this), R(0),
|
||||||
B(Mov), R(context), R(2),
|
B(Mov), R(context), R(2),
|
||||||
/* 48 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
|
/* 48 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
|
||||||
/* 53 S> */ B(Wide), B(LdaSmi), I16(265),
|
/* 53 S> */ B(Wide), B(LdaSmi), I16(266),
|
||||||
B(Star), R(3),
|
B(Star), R(3),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(4),
|
B(Star), R(4),
|
||||||
@ -115,7 +115,7 @@ bytecodes: [
|
|||||||
B(Mov), R(this), R(0),
|
B(Mov), R(this), R(0),
|
||||||
B(Mov), R(context), R(2),
|
B(Mov), R(context), R(2),
|
||||||
/* 41 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
|
/* 41 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
|
||||||
/* 46 S> */ B(Wide), B(LdaSmi), I16(264),
|
/* 46 S> */ B(Wide), B(LdaSmi), I16(265),
|
||||||
B(Star), R(3),
|
B(Star), R(3),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(4),
|
B(Star), R(4),
|
||||||
@ -146,7 +146,7 @@ bytecodes: [
|
|||||||
B(Mov), R(this), R(0),
|
B(Mov), R(this), R(0),
|
||||||
B(Mov), R(context), R(2),
|
B(Mov), R(context), R(2),
|
||||||
/* 48 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
|
/* 48 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
|
||||||
/* 53 S> */ B(Wide), B(LdaSmi), I16(265),
|
/* 53 S> */ B(Wide), B(LdaSmi), I16(266),
|
||||||
B(Star), R(3),
|
B(Star), R(3),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(4),
|
B(Star), R(4),
|
||||||
@ -177,7 +177,7 @@ bytecodes: [
|
|||||||
B(Mov), R(this), R(0),
|
B(Mov), R(this), R(0),
|
||||||
B(Mov), R(context), R(2),
|
B(Mov), R(context), R(2),
|
||||||
/* 41 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
|
/* 41 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
|
||||||
/* 46 S> */ B(Wide), B(LdaSmi), I16(264),
|
/* 46 S> */ B(Wide), B(LdaSmi), I16(265),
|
||||||
B(Star), R(4),
|
B(Star), R(4),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(5),
|
B(Star), R(5),
|
||||||
|
@ -57,7 +57,7 @@ bytecodes: [
|
|||||||
B(Mov), R(this), R(0),
|
B(Mov), R(this), R(0),
|
||||||
B(Mov), R(context), R(2),
|
B(Mov), R(context), R(2),
|
||||||
/* 44 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
|
/* 44 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
|
||||||
/* 49 S> */ B(Wide), B(LdaSmi), I16(263),
|
/* 49 S> */ B(Wide), B(LdaSmi), I16(264),
|
||||||
B(Star), R(3),
|
B(Star), R(3),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(4),
|
B(Star), R(4),
|
||||||
@ -89,7 +89,7 @@ bytecodes: [
|
|||||||
B(Mov), R(this), R(0),
|
B(Mov), R(this), R(0),
|
||||||
B(Mov), R(context), R(2),
|
B(Mov), R(context), R(2),
|
||||||
/* 44 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
|
/* 44 E> */ B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(0), U8(3),
|
||||||
/* 49 S> */ B(Wide), B(LdaSmi), I16(263),
|
/* 49 S> */ B(Wide), B(LdaSmi), I16(264),
|
||||||
B(Star), R(3),
|
B(Star), R(3),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(4),
|
B(Star), R(4),
|
||||||
|
@ -25,7 +25,7 @@ bytecodes: [
|
|||||||
B(TestReferenceEqual), R(this),
|
B(TestReferenceEqual), R(this),
|
||||||
B(Mov), R(this), R(1),
|
B(Mov), R(this), R(1),
|
||||||
B(JumpIfTrue), U8(18),
|
B(JumpIfTrue), U8(18),
|
||||||
B(Wide), B(LdaSmi), I16(261),
|
B(Wide), B(LdaSmi), I16(262),
|
||||||
B(Star), R(2),
|
B(Star), R(2),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(3),
|
B(Star), R(3),
|
||||||
@ -56,7 +56,7 @@ frame size: 2
|
|||||||
parameter count: 1
|
parameter count: 1
|
||||||
bytecode array length: 16
|
bytecode array length: 16
|
||||||
bytecodes: [
|
bytecodes: [
|
||||||
/* 56 S> */ B(Wide), B(LdaSmi), I16(263),
|
/* 56 S> */ B(Wide), B(LdaSmi), I16(264),
|
||||||
B(Star), R(0),
|
B(Star), R(0),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(1),
|
B(Star), R(1),
|
||||||
@ -83,7 +83,7 @@ frame size: 2
|
|||||||
parameter count: 1
|
parameter count: 1
|
||||||
bytecode array length: 16
|
bytecode array length: 16
|
||||||
bytecodes: [
|
bytecodes: [
|
||||||
/* 56 S> */ B(Wide), B(LdaSmi), I16(263),
|
/* 56 S> */ B(Wide), B(LdaSmi), I16(264),
|
||||||
B(Star), R(0),
|
B(Star), R(0),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(1),
|
B(Star), R(1),
|
||||||
@ -122,7 +122,7 @@ bytecodes: [
|
|||||||
/* 94 E> */ B(TestReferenceEqual), R(this),
|
/* 94 E> */ B(TestReferenceEqual), R(this),
|
||||||
B(Mov), R(this), R(0),
|
B(Mov), R(this), R(0),
|
||||||
B(JumpIfTrue), U8(18),
|
B(JumpIfTrue), U8(18),
|
||||||
B(Wide), B(LdaSmi), I16(261),
|
B(Wide), B(LdaSmi), I16(262),
|
||||||
B(Star), R(2),
|
B(Star), R(2),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(3),
|
B(Star), R(3),
|
||||||
@ -144,7 +144,7 @@ bytecodes: [
|
|||||||
/* 109 E> */ B(TestReferenceEqual), R(this),
|
/* 109 E> */ B(TestReferenceEqual), R(this),
|
||||||
B(Mov), R(this), R(1),
|
B(Mov), R(this), R(1),
|
||||||
B(JumpIfTrue), U8(18),
|
B(JumpIfTrue), U8(18),
|
||||||
B(Wide), B(LdaSmi), I16(262),
|
B(Wide), B(LdaSmi), I16(263),
|
||||||
B(Star), R(3),
|
B(Star), R(3),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(4),
|
B(Star), R(4),
|
||||||
@ -159,7 +159,7 @@ bytecodes: [
|
|||||||
/* 133 E> */ B(TestReferenceEqual), R(this),
|
/* 133 E> */ B(TestReferenceEqual), R(this),
|
||||||
B(Mov), R(this), R(0),
|
B(Mov), R(this), R(0),
|
||||||
B(JumpIfTrue), U8(18),
|
B(JumpIfTrue), U8(18),
|
||||||
B(Wide), B(LdaSmi), I16(261),
|
B(Wide), B(LdaSmi), I16(262),
|
||||||
B(Star), R(2),
|
B(Star), R(2),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(3),
|
B(Star), R(3),
|
||||||
@ -189,7 +189,7 @@ frame size: 2
|
|||||||
parameter count: 1
|
parameter count: 1
|
||||||
bytecode array length: 16
|
bytecode array length: 16
|
||||||
bytecodes: [
|
bytecodes: [
|
||||||
/* 60 S> */ B(Wide), B(LdaSmi), I16(265),
|
/* 60 S> */ B(Wide), B(LdaSmi), I16(266),
|
||||||
B(Star), R(0),
|
B(Star), R(0),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(1),
|
B(Star), R(1),
|
||||||
@ -215,7 +215,7 @@ frame size: 2
|
|||||||
parameter count: 1
|
parameter count: 1
|
||||||
bytecode array length: 16
|
bytecode array length: 16
|
||||||
bytecodes: [
|
bytecodes: [
|
||||||
/* 53 S> */ B(Wide), B(LdaSmi), I16(264),
|
/* 53 S> */ B(Wide), B(LdaSmi), I16(265),
|
||||||
B(Star), R(0),
|
B(Star), R(0),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(1),
|
B(Star), R(1),
|
||||||
@ -241,7 +241,7 @@ frame size: 2
|
|||||||
parameter count: 1
|
parameter count: 1
|
||||||
bytecode array length: 16
|
bytecode array length: 16
|
||||||
bytecodes: [
|
bytecodes: [
|
||||||
/* 60 S> */ B(Wide), B(LdaSmi), I16(265),
|
/* 60 S> */ B(Wide), B(LdaSmi), I16(266),
|
||||||
B(Star), R(0),
|
B(Star), R(0),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(1),
|
B(Star), R(1),
|
||||||
@ -267,7 +267,7 @@ frame size: 3
|
|||||||
parameter count: 1
|
parameter count: 1
|
||||||
bytecode array length: 16
|
bytecode array length: 16
|
||||||
bytecodes: [
|
bytecodes: [
|
||||||
/* 46 S> */ B(Wide), B(LdaSmi), I16(264),
|
/* 46 S> */ B(Wide), B(LdaSmi), I16(265),
|
||||||
B(Star), R(1),
|
B(Star), R(1),
|
||||||
B(LdaConstant), U8(0),
|
B(LdaConstant), U8(0),
|
||||||
B(Star), R(2),
|
B(Star), R(2),
|
||||||
|
99
test/mjsunit/harmony/atomics-on-arraybuffer-detach.js
Normal file
99
test/mjsunit/harmony/atomics-on-arraybuffer-detach.js
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// 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: --harmony-sharedarraybuffer --allow-natives-syntax
|
||||||
|
|
||||||
|
// Test for the buffer becoming detached in surprising places. Test262 covers
|
||||||
|
// the case where the buffer starts off detached.
|
||||||
|
|
||||||
|
function makePoison(arr, val) {
|
||||||
|
return { valueOf() { %ArrayBufferDetach(arr.buffer); return val; } };
|
||||||
|
}
|
||||||
|
|
||||||
|
function forEachIntegerTypedArray(cb) {
|
||||||
|
for (let C of [Int8Array, Uint8Array, Uint8ClampedArray,
|
||||||
|
Int16Array, Uint16Array,
|
||||||
|
Int32Array, Uint32Array,
|
||||||
|
BigInt64Array, BigUint64Array]) {
|
||||||
|
let arr = new C(32);
|
||||||
|
let zero, valuePoison;
|
||||||
|
if (C === BigInt64Array || C === BigUint64Array) {
|
||||||
|
zero = 0n;
|
||||||
|
valuePoison = makePoison(arr, 0n);
|
||||||
|
} else {
|
||||||
|
zero = 0;
|
||||||
|
valuePoison = makePoison(arr, 0);
|
||||||
|
}
|
||||||
|
cb(arr, makePoison(arr, 0), valuePoison, zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.add(arr, indexPoison, zero), TypeError);
|
||||||
|
});
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.add(arr, 0, valuePoison), TypeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.and(arr, indexPoison, zero), TypeError);
|
||||||
|
});
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.and(arr, 0, valuePoison), TypeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.compareExchange(arr, indexPoison, zero, zero),
|
||||||
|
TypeError);
|
||||||
|
});
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.compareExchange(arr, 0, valuePoison, zero),
|
||||||
|
TypeError);
|
||||||
|
});
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.compareExchange(arr, 0, zero, valuePoison),
|
||||||
|
TypeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.exchange(arr, indexPoison, zero), TypeError);
|
||||||
|
});
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.exchange(arr, 0, valuePoison), TypeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.load(arr, indexPoison), TypeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.or(arr, indexPoison, zero), TypeError);
|
||||||
|
});
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.or(arr, 0, valuePoison), TypeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.store(arr, indexPoison, 0n), TypeError);
|
||||||
|
});
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.store(arr, 0, valuePoison), TypeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.sub(arr, indexPoison, zero), TypeError);
|
||||||
|
});
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.sub(arr, 0, valuePoison), TypeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.xor(arr, indexPoison, zero), TypeError);
|
||||||
|
});
|
||||||
|
forEachIntegerTypedArray((arr, indexPoison, valuePoison, zero) => {
|
||||||
|
assertThrows(() => Atomics.xor(arr, 0, valuePoison), TypeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Atomics.wait always throws on non-SABs.
|
||||||
|
// Atomics.notify always returns 0 on non-SABs.
|
@ -53,15 +53,14 @@ var IntegerTypedArrayConstructors = [
|
|||||||
|
|
||||||
(function TestBadArray() {
|
(function TestBadArray() {
|
||||||
var ab = new ArrayBuffer(16);
|
var ab = new ArrayBuffer(16);
|
||||||
var u32a = new Uint32Array(16);
|
|
||||||
var sab = new SharedArrayBuffer(128);
|
var sab = new SharedArrayBuffer(128);
|
||||||
var sf32a = new Float32Array(sab);
|
var sf32a = new Float32Array(sab);
|
||||||
var sf64a = new Float64Array(sab);
|
var sf64a = new Float64Array(sab);
|
||||||
var u8ca = new Uint8ClampedArray(sab);
|
var u8ca = new Uint8ClampedArray(sab);
|
||||||
|
|
||||||
// Atomic ops required integer shared typed arrays
|
// Atomic ops required integer typed arrays
|
||||||
var badArrayTypes = [
|
var badArrayTypes = [
|
||||||
undefined, 1, 'hi', 3.4, ab, u32a, sab, sf32a, sf64a, u8ca
|
undefined, 1, 'hi', 3.4, ab, sab, sf32a, sf64a, u8ca
|
||||||
];
|
];
|
||||||
badArrayTypes.forEach(function(o) {
|
badArrayTypes.forEach(function(o) {
|
||||||
assertThrows(function() { Atomics.compareExchange(o, 0, 0, 0); },
|
assertThrows(function() { Atomics.compareExchange(o, 0, 0, 0); },
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer
|
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer
|
||||||
|
|
||||||
(function TestFailsWithNonSharedArray() {
|
(function TestNonSharedArrayBehavior() {
|
||||||
var ab = new ArrayBuffer(16);
|
var ab = new ArrayBuffer(16);
|
||||||
|
|
||||||
var i8a = new Int8Array(ab);
|
var i8a = new Int8Array(ab);
|
||||||
@ -18,9 +18,13 @@
|
|||||||
var f64a = new Float64Array(ab);
|
var f64a = new Float64Array(ab);
|
||||||
|
|
||||||
[i8a, i16a, i32a, ui8a, ui8ca, ui16a, ui32a, f32a, f64a].forEach(function(
|
[i8a, i16a, i32a, ui8a, ui8ca, ui16a, ui32a, f32a, f64a].forEach(function(
|
||||||
ta) {
|
ta) {
|
||||||
assertThrows(function() { Atomics.wait(ta, 0, 0); });
|
assertThrows(function() { Atomics.wait(ta, 0, 0); });
|
||||||
assertThrows(function() { Atomics.notify(ta, 0, 1); });
|
if (ta === i32a) {
|
||||||
|
assertEquals(0, Atomics.notify(ta, 0, 1));
|
||||||
|
} else {
|
||||||
|
assertThrows(function() { Atomics.notify(ta, 0, 1); });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -525,32 +525,6 @@
|
|||||||
# https://bugs.chromium.org/p/v8/issues/detail?id=10383
|
# https://bugs.chromium.org/p/v8/issues/detail?id=10383
|
||||||
'built-ins/RegExp/prototype/Symbol.replace/fn-invoke-args-empty-result': [FAIL],
|
'built-ins/RegExp/prototype/Symbol.replace/fn-invoke-args-empty-result': [FAIL],
|
||||||
|
|
||||||
# https://crbug.com/v8/10687
|
|
||||||
'built-ins/Atomics/add/bigint/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/add/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/and/bigint/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/and/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/compareExchange/bigint/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/compareExchange/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/exchange/bigint/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/exchange/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/load/bigint/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/load/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/notify/bigint/non-shared-bufferdata-count-evaluation-throws': [FAIL],
|
|
||||||
'built-ins/Atomics/notify/bigint/non-shared-bufferdata-index-evaluation-throws': [FAIL],
|
|
||||||
'built-ins/Atomics/notify/bigint/non-shared-bufferdata-returns-0': [FAIL],
|
|
||||||
'built-ins/Atomics/notify/non-shared-bufferdata-count-evaluation-throws': [FAIL],
|
|
||||||
'built-ins/Atomics/notify/non-shared-bufferdata-index-evaluation-throws': [FAIL],
|
|
||||||
'built-ins/Atomics/notify/non-shared-bufferdata-returns-0': [FAIL],
|
|
||||||
'built-ins/Atomics/or/bigint/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/or/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/store/bigint/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/store/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/sub/bigint/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/sub/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/xor/bigint/non-shared-bufferdata': [FAIL],
|
|
||||||
'built-ins/Atomics/xor/non-shared-bufferdata': [FAIL],
|
|
||||||
|
|
||||||
# https://crbug.com/v8/10789
|
# https://crbug.com/v8/10789
|
||||||
'built-ins/Function/prototype/toString/built-in-function-object': [FAIL],
|
'built-ins/Function/prototype/toString/built-in-function-object': [FAIL],
|
||||||
|
|
||||||
|
@ -444,27 +444,27 @@ KNOWN_OBJECTS = {
|
|||||||
("old_space", 0x02a61): "StringSplitCache",
|
("old_space", 0x02a61): "StringSplitCache",
|
||||||
("old_space", 0x02e69): "RegExpMultipleCache",
|
("old_space", 0x02e69): "RegExpMultipleCache",
|
||||||
("old_space", 0x03271): "BuiltinsConstantsTable",
|
("old_space", 0x03271): "BuiltinsConstantsTable",
|
||||||
("old_space", 0x03625): "AsyncFunctionAwaitRejectSharedFun",
|
("old_space", 0x03645): "AsyncFunctionAwaitRejectSharedFun",
|
||||||
("old_space", 0x0364d): "AsyncFunctionAwaitResolveSharedFun",
|
("old_space", 0x0366d): "AsyncFunctionAwaitResolveSharedFun",
|
||||||
("old_space", 0x03675): "AsyncGeneratorAwaitRejectSharedFun",
|
("old_space", 0x03695): "AsyncGeneratorAwaitRejectSharedFun",
|
||||||
("old_space", 0x0369d): "AsyncGeneratorAwaitResolveSharedFun",
|
("old_space", 0x036bd): "AsyncGeneratorAwaitResolveSharedFun",
|
||||||
("old_space", 0x036c5): "AsyncGeneratorYieldResolveSharedFun",
|
("old_space", 0x036e5): "AsyncGeneratorYieldResolveSharedFun",
|
||||||
("old_space", 0x036ed): "AsyncGeneratorReturnResolveSharedFun",
|
("old_space", 0x0370d): "AsyncGeneratorReturnResolveSharedFun",
|
||||||
("old_space", 0x03715): "AsyncGeneratorReturnClosedRejectSharedFun",
|
("old_space", 0x03735): "AsyncGeneratorReturnClosedRejectSharedFun",
|
||||||
("old_space", 0x0373d): "AsyncGeneratorReturnClosedResolveSharedFun",
|
("old_space", 0x0375d): "AsyncGeneratorReturnClosedResolveSharedFun",
|
||||||
("old_space", 0x03765): "AsyncIteratorValueUnwrapSharedFun",
|
("old_space", 0x03785): "AsyncIteratorValueUnwrapSharedFun",
|
||||||
("old_space", 0x0378d): "PromiseAllResolveElementSharedFun",
|
("old_space", 0x037ad): "PromiseAllResolveElementSharedFun",
|
||||||
("old_space", 0x037b5): "PromiseAllSettledResolveElementSharedFun",
|
("old_space", 0x037d5): "PromiseAllSettledResolveElementSharedFun",
|
||||||
("old_space", 0x037dd): "PromiseAllSettledRejectElementSharedFun",
|
("old_space", 0x037fd): "PromiseAllSettledRejectElementSharedFun",
|
||||||
("old_space", 0x03805): "PromiseAnyRejectElementSharedFun",
|
("old_space", 0x03825): "PromiseAnyRejectElementSharedFun",
|
||||||
("old_space", 0x0382d): "PromiseCapabilityDefaultRejectSharedFun",
|
("old_space", 0x0384d): "PromiseCapabilityDefaultRejectSharedFun",
|
||||||
("old_space", 0x03855): "PromiseCapabilityDefaultResolveSharedFun",
|
("old_space", 0x03875): "PromiseCapabilityDefaultResolveSharedFun",
|
||||||
("old_space", 0x0387d): "PromiseCatchFinallySharedFun",
|
("old_space", 0x0389d): "PromiseCatchFinallySharedFun",
|
||||||
("old_space", 0x038a5): "PromiseGetCapabilitiesExecutorSharedFun",
|
("old_space", 0x038c5): "PromiseGetCapabilitiesExecutorSharedFun",
|
||||||
("old_space", 0x038cd): "PromiseThenFinallySharedFun",
|
("old_space", 0x038ed): "PromiseThenFinallySharedFun",
|
||||||
("old_space", 0x038f5): "PromiseThrowerFinallySharedFun",
|
("old_space", 0x03915): "PromiseThrowerFinallySharedFun",
|
||||||
("old_space", 0x0391d): "PromiseValueThunkFinallySharedFun",
|
("old_space", 0x0393d): "PromiseValueThunkFinallySharedFun",
|
||||||
("old_space", 0x03945): "ProxyRevokeSharedFun",
|
("old_space", 0x03965): "ProxyRevokeSharedFun",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Lower 32 bits of first page addresses for various heap spaces.
|
# Lower 32 bits of first page addresses for various heap spaces.
|
||||||
|
Loading…
Reference in New Issue
Block a user