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

[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: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69392}
parent c5722641
......@@ -20,9 +20,9 @@ namespace v8 {
namespace internal {
// 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) {
// 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
......@@ -39,7 +39,7 @@ inline bool AtomicIsLockFree(double size) {
return size == 1 || size == 2 || size == 4 || size == 8;
}
// ES #sec-atomics.islockfree
// https://tc39.es/ecma262/#sec-atomics.islockfree
BUILTIN(AtomicsIsLockFree) {
HandleScope scope(isolate);
Handle<Object> size = args.atOrUndefined(isolate, 1);
......@@ -48,37 +48,45 @@ BUILTIN(AtomicsIsLockFree) {
return *isolate->factory()->ToBoolean(AtomicIsLockFree(size->Number()));
}
// ES #sec-validatesharedintegertypedarray
V8_WARN_UNUSED_RESULT MaybeHandle<JSTypedArray> ValidateSharedIntegerTypedArray(
Isolate* isolate, Handle<Object> object,
// https://tc39.es/ecma262/#sec-validatesharedintegertypedarray
V8_WARN_UNUSED_RESULT MaybeHandle<JSTypedArray> ValidateIntegerTypedArray(
Isolate* isolate, Handle<Object> object, const char* method_name,
bool only_int32_and_big_int64 = false) {
if (object->IsJSTypedArray()) {
Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object);
if (typed_array->GetBuffer()->is_shared()) {
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;
if (typed_array->WasDetached()) {
THROW_NEW_ERROR(
isolate,
NewTypeError(
MessageTemplate::kDetachedOperation,
isolate->factory()->NewStringFromAsciiChecked(method_name)),
JSTypedArray);
}
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(
isolate,
NewTypeError(only_int32_and_big_int64
? MessageTemplate::kNotInt32OrBigInt64SharedTypedArray
: MessageTemplate::kNotIntegerSharedTypedArray,
? MessageTemplate::kNotInt32OrBigInt64TypedArray
: MessageTemplate::kNotIntegerTypedArray,
object),
JSTypedArray);
}
// ES #sec-validateatomicaccess
// https://tc39.es/ecma262/#sec-validateatomicaccess
// ValidateAtomicAccess( typedArray, requestIndex )
V8_WARN_UNUSED_RESULT Maybe<size_t> ValidateAtomicAccess(
Isolate* isolate, Handle<JSTypedArray> typed_array,
......@@ -91,8 +99,9 @@ V8_WARN_UNUSED_RESULT Maybe<size_t> ValidateAtomicAccess(
Nothing<size_t>());
size_t access_index;
size_t typed_array_length = typed_array->length();
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(
MessageTemplate::kInvalidAtomicAccessIndex));
return Nothing<size_t>();
......@@ -122,12 +131,18 @@ BUILTIN(AtomicsNotify) {
Handle<JSTypedArray> sta;
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);
if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
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;
if (count->IsUndefined(isolate)) {
c = kMaxUInt32;
......@@ -143,9 +158,17 @@ BUILTIN(AtomicsNotify) {
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();
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) {
wake_addr = GetAddress64(i, sta->byte_offset());
} else {
......@@ -158,19 +181,26 @@ BUILTIN(AtomicsNotify) {
Object DoWait(Isolate* isolate, FutexEmulation::WaitMode mode,
Handle<Object> array, Handle<Object> index, Handle<Object> value,
Handle<Object> timeout) {
// 1. Let buffer be ? ValidateSharedIntegerTypedArray(typedArray, true).
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray, true).
Handle<JSTypedArray> sta;
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);
if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
size_t i = maybe_index.FromJust();
// 3. Let arrayTypeName be typedArray.[[TypedArrayName]].
// 4. If arrayTypeName is "BigInt64Array", let v be ? ToBigInt64(value).
// 5. Otherwise, let v be ? ToInt32(value).
// 4. Let arrayTypeName be typedArray.[[TypedArrayName]].
// 5. If arrayTypeName is "BigInt64Array", let v be ? ToBigInt64(value).
// 6. Otherwise, let v be ? ToInt32(value).
if (sta->type() == kExternalBigInt64Array) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
BigInt::FromObject(isolate, value));
......@@ -180,8 +210,8 @@ Object DoWait(Isolate* isolate, FutexEmulation::WaitMode mode,
Object::ToInt32(isolate, value));
}
// 6. Let q be ? ToNumber(timeout).
// 7. If q is NaN, let t be +∞, else let t be max(q, 0).
// 7. Let q be ? ToNumber(timeout).
// 8. If q is NaN, let t be +∞, else let t be max(q, 0).
double timeout_number;
if (timeout->IsUndefined(isolate)) {
timeout_number = ReadOnlyRoots(isolate).infinity_value().Number();
......@@ -195,7 +225,7 @@ Object DoWait(Isolate* isolate, FutexEmulation::WaitMode mode,
timeout_number = 0;
}
// 8. If mode is sync, then
// 9. If mode is sync, then
// a. Let B be AgentCanSuspend().
// b. If B is false, throw a TypeError exception.
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 )
BUILTIN(AtomicsWait) {
HandleScope scope(isolate);
......
......@@ -231,28 +231,6 @@ TNode<JSFunction> TypedArrayBuiltinsAssembler::GetDefaultConstructor(
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<Context> context, TNode<Object> obj, const char* method_name) {
// If it is not a typed array, throw
......
......@@ -45,9 +45,6 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
TNode<JSFunction> GetDefaultConstructor(TNode<Context> context,
TNode<JSTypedArray> exemplar);
TNode<JSArrayBuffer> GetBuffer(TNode<Context> context,
TNode<JSTypedArray> array);
TNode<JSTypedArray> ValidateTypedArray(TNode<Context> context,
TNode<Object> obj,
const char* method_name);
......
......@@ -17,7 +17,7 @@ transitioning javascript builtin TypedArrayPrototypeSubArray(
MessageTemplate::kIncompatibleMethodReceiver, methodName);
// 5. Let buffer be O.[[ViewedArrayBuffer]].
const buffer = typed_array::GetBuffer(source);
const buffer = typed_array::GetTypedArrayBuffer(source);
// 6. Let srcLength be O.[[ArrayLength]].
const srcLength: uintptr = source.length;
......
......@@ -63,8 +63,8 @@ extern macro TypedArrayBuiltinsAssembler::CallCMemmove(
RawPtr, RawPtr, uintptr): void;
extern macro TypedArrayBuiltinsAssembler::CallCMemset(
RawPtr, intptr, uintptr): void;
extern macro TypedArrayBuiltinsAssembler::GetBuffer(implicit context: Context)(
JSTypedArray): JSArrayBuffer;
extern macro GetTypedArrayBuffer(implicit context: Context)(JSTypedArray):
JSArrayBuffer;
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
JSTypedArray): TypedArrayElementsInfo;
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(Map):
......
......@@ -12528,6 +12528,28 @@ TNode<UintPtrT> CodeStubAssembler::LoadJSTypedArrayLength(
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,
TNode<IntPtrT> argc, TNode<RawPtrT> fp)
: assembler_(assembler),
......
......@@ -3442,6 +3442,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// JSTypedArray helpers
TNode<UintPtrT> LoadJSTypedArrayLength(TNode<JSTypedArray> typed_array);
TNode<RawPtrT> LoadJSTypedArrayDataPtr(TNode<JSTypedArray> typed_array);
TNode<JSArrayBuffer> GetTypedArrayBuffer(TNode<Context> context,
TNode<JSTypedArray> array);
template <typename TIndex>
TNode<IntPtrT> ElementOffsetFromIndex(TNode<TIndex> index, ElementsKind kind,
......
......@@ -144,9 +144,10 @@ namespace internal {
T(NotSuperConstructor, "Super constructor % of % is not a constructor") \
T(NotSuperConstructorAnonymousClass, \
"Super constructor % of anonymous class is not a constructor") \
T(NotIntegerSharedTypedArray, "% is not an integer shared typed array.") \
T(NotInt32OrBigInt64SharedTypedArray, \
"% is not an int32 or BigInt64 shared typed array.") \
T(NotIntegerTypedArray, "% is not an integer typed array.") \
T(NotInt32OrBigInt64TypedArray, \
"% is not an int32 or BigInt64 typed array.") \
T(NotSharedTypedArray, "% is not a shared typed array.") \
T(ObjectGetterExpectingFunction, \
"Object.prototype.__defineGetter__: Expecting function") \
T(ObjectGetterCallable, "Getter must be a function: %") \
......
......@@ -11,9 +11,8 @@
#include "src/objects/js-array-buffer-inl.h"
#include "src/runtime/runtime-utils.h"
// Implement Atomic accesses to SharedArrayBuffers as defined in the
// SharedArrayBuffer draft spec, found here
// https://github.com/tc39/ecmascript_sharedmem
// Implement Atomic accesses to ArrayBuffers and SharedArrayBuffers.
// https://tc39.es/ecma262/#sec-atomics
namespace v8 {
namespace internal {
......@@ -341,17 +340,27 @@ 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) \
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
// but also includes the ToInteger/ToBigInt conversion that's part of
// https://tc39.github.io/ecma262/#sec-atomicreadmodifywrite
template <template <typename> class Op>
Object GetModifySetValueInBuffer(RuntimeArguments args, Isolate* isolate) {
Object GetModifySetValueInBuffer(RuntimeArguments args, Isolate* isolate,
const char* method_name) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
CONVERT_SIZE_ARG_CHECKED(index, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, value_obj, 2);
CHECK(sta->GetBuffer()->is_shared());
uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
sta->byte_offset();
......@@ -360,7 +369,9 @@ Object GetModifySetValueInBuffer(RuntimeArguments args, Isolate* isolate) {
Handle<BigInt> bigint;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, bigint,
BigInt::FromObject(isolate, value_obj));
// SharedArrayBuffers are not detachable.
THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta, method_name);
CHECK_LT(index, sta->length());
if (sta->type() == kExternalBigInt64Array) {
return Op<int64_t>::Do(isolate, source, index, bigint);
......@@ -372,7 +383,9 @@ Object GetModifySetValueInBuffer(RuntimeArguments args, Isolate* isolate) {
Handle<Object> value;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
Object::ToInteger(isolate, value_obj));
// SharedArrayBuffers are not detachable.
THROW_ERROR_RETURN_FAILURE_ON_DETACHED(isolate, sta, method_name);
CHECK_LT(index, sta->length());
switch (sta->type()) {
......@@ -395,14 +408,13 @@ RUNTIME_FUNCTION(Runtime_AtomicsLoad64) {
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
CONVERT_SIZE_ARG_CHECKED(index, 1);
CHECK(sta->GetBuffer()->is_shared());
uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
sta->byte_offset();
DCHECK(sta->type() == kExternalBigInt64Array ||
sta->type() == kExternalBigUint64Array);
// SharedArrayBuffers are not detachable.
DCHECK(!sta->WasDetached());
CHECK_LT(index, sta->length());
if (sta->type() == kExternalBigInt64Array) {
return Load<int64_t>::Do(isolate, source, index);
......@@ -417,7 +429,6 @@ RUNTIME_FUNCTION(Runtime_AtomicsStore64) {
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
CONVERT_SIZE_ARG_CHECKED(index, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, value_obj, 2);
CHECK(sta->GetBuffer()->is_shared());
uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
sta->byte_offset();
......@@ -428,7 +439,7 @@ RUNTIME_FUNCTION(Runtime_AtomicsStore64) {
DCHECK(sta->type() == kExternalBigInt64Array ||
sta->type() == kExternalBigUint64Array);
// SharedArrayBuffers are not detachable.
DCHECK(!sta->WasDetached());
CHECK_LT(index, sta->length());
if (sta->type() == kExternalBigInt64Array) {
Store<int64_t>::Do(isolate, source, index, bigint);
......@@ -440,7 +451,7 @@ RUNTIME_FUNCTION(Runtime_AtomicsStore64) {
}
RUNTIME_FUNCTION(Runtime_AtomicsExchange) {
return GetModifySetValueInBuffer<Exchange>(args, isolate);
return GetModifySetValueInBuffer<Exchange>(args, isolate, "Atomics.exchange");
}
RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
......@@ -450,7 +461,6 @@ RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
CONVERT_SIZE_ARG_CHECKED(index, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, old_value_obj, 2);
CONVERT_ARG_HANDLE_CHECKED(Object, new_value_obj, 3);
CHECK(sta->GetBuffer()->is_shared());
CHECK_LT(index, sta->length());
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));
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
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());
if (sta->type() == kExternalBigInt64Array) {
return DoCompareExchange<int64_t>(isolate, source, index, old_bigint,
......@@ -480,8 +493,9 @@ RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
Object::ToInteger(isolate, old_value_obj));
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, new_value,
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()) {
#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype) \
......@@ -502,31 +516,31 @@ RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
// ES #sec-atomics.add
// Atomics.add( typedArray, index, value )
RUNTIME_FUNCTION(Runtime_AtomicsAdd) {
return GetModifySetValueInBuffer<Add>(args, isolate);
return GetModifySetValueInBuffer<Add>(args, isolate, "Atomics.add");
}
// ES #sec-atomics.sub
// Atomics.sub( typedArray, index, value )
RUNTIME_FUNCTION(Runtime_AtomicsSub) {
return GetModifySetValueInBuffer<Sub>(args, isolate);
return GetModifySetValueInBuffer<Sub>(args, isolate, "Atomics.sub");
}
// ES #sec-atomics.and
// Atomics.and( typedArray, index, value )
RUNTIME_FUNCTION(Runtime_AtomicsAnd) {
return GetModifySetValueInBuffer<And>(args, isolate);
return GetModifySetValueInBuffer<And>(args, isolate, "Atomics.and");
}
// ES #sec-atomics.or
// Atomics.or( typedArray, index, value )
RUNTIME_FUNCTION(Runtime_AtomicsOr) {
return GetModifySetValueInBuffer<Or>(args, isolate);
return GetModifySetValueInBuffer<Or>(args, isolate, "Atomics.or");
}
// ES #sec-atomics.xor
// Atomics.xor( typedArray, index, value )
RUNTIME_FUNCTION(Runtime_AtomicsXor) {
return GetModifySetValueInBuffer<Xor>(args, isolate);
return GetModifySetValueInBuffer<Xor>(args, isolate, "Atomics.xor");
}
#undef INTEGER_TYPED_ARRAYS
......
......@@ -84,7 +84,7 @@ bytecodes: [
B(Mov), R(this), R(0),
B(Mov), R(context), R(2),
/* 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(LdaConstant), U8(0),
B(Star), R(4),
......@@ -115,7 +115,7 @@ bytecodes: [
B(Mov), R(this), R(0),
B(Mov), R(context), R(2),
/* 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(LdaConstant), U8(0),
B(Star), R(4),
......@@ -146,7 +146,7 @@ bytecodes: [
B(Mov), R(this), R(0),
B(Mov), R(context), R(2),
/* 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(LdaConstant), U8(0),
B(Star), R(4),
......@@ -177,7 +177,7 @@ bytecodes: [
B(Mov), R(this), R(0),
B(Mov), R(context), R(2),
/* 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(LdaConstant), U8(0),
B(Star), R(5),
......
......@@ -57,7 +57,7 @@ bytecodes: [
B(Mov), R(this), R(0),
B(Mov), R(context), R(2),
/* 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(LdaConstant), U8(0),
B(Star), R(4),
......@@ -89,7 +89,7 @@ bytecodes: [
B(Mov), R(this), R(0),
B(Mov), R(context), R(2),
/* 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(LdaConstant), U8(0),
B(Star), R(4),
......
......@@ -25,7 +25,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(1),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(261),
B(Wide), B(LdaSmi), I16(262),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
......@@ -56,7 +56,7 @@ frame size: 2
parameter count: 1
bytecode array length: 16
bytecodes: [
/* 56 S> */ B(Wide), B(LdaSmi), I16(263),
/* 56 S> */ B(Wide), B(LdaSmi), I16(264),
B(Star), R(0),
B(LdaConstant), U8(0),
B(Star), R(1),
......@@ -83,7 +83,7 @@ frame size: 2
parameter count: 1
bytecode array length: 16
bytecodes: [
/* 56 S> */ B(Wide), B(LdaSmi), I16(263),
/* 56 S> */ B(Wide), B(LdaSmi), I16(264),
B(Star), R(0),
B(LdaConstant), U8(0),
B(Star), R(1),
......@@ -122,7 +122,7 @@ bytecodes: [
/* 94 E> */ B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(261),
B(Wide), B(LdaSmi), I16(262),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
......@@ -144,7 +144,7 @@ bytecodes: [
/* 109 E> */ B(TestReferenceEqual), R(this),
B(Mov), R(this), R(1),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(262),
B(Wide), B(LdaSmi), I16(263),
B(Star), R(3),
B(LdaConstant), U8(0),
B(Star), R(4),
......@@ -159,7 +159,7 @@ bytecodes: [
/* 133 E> */ B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(18),
B(Wide), B(LdaSmi), I16(261),
B(Wide), B(LdaSmi), I16(262),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
......@@ -189,7 +189,7 @@ frame size: 2
parameter count: 1
bytecode array length: 16
bytecodes: [
/* 60 S> */ B(Wide), B(LdaSmi), I16(265),
/* 60 S> */ B(Wide), B(LdaSmi), I16(266),
B(Star), R(0),
B(LdaConstant), U8(0),
B(Star), R(1),
......@@ -215,7 +215,7 @@ frame size: 2
parameter count: 1
bytecode array length: 16
bytecodes: [
/* 53 S> */ B(Wide), B(LdaSmi), I16(264),
/* 53 S> */ B(Wide), B(LdaSmi), I16(265),
B(Star), R(0),
B(LdaConstant), U8(0),
B(Star), R(1),
......@@ -241,7 +241,7 @@ frame size: 2
parameter count: 1
bytecode array length: 16
bytecodes: [
/* 60 S> */ B(Wide), B(LdaSmi), I16(265),
/* 60 S> */ B(Wide), B(LdaSmi), I16(266),
B(Star), R(0),
B(LdaConstant), U8(0),
B(Star), R(1),
......@@ -267,7 +267,7 @@ frame size: 3
parameter count: 1
bytecode array length: 16
bytecodes: [
/* 46 S> */ B(Wide), B(LdaSmi), I16(264),
/* 46 S> */ B(Wide), B(LdaSmi), I16(265),
B(Star), R(1),
B(LdaConstant), U8(0),
B(Star), R(2),
......
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --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() {
var ab = new ArrayBuffer(16);
var u32a = new Uint32Array(16);
var sab = new SharedArrayBuffer(128);
var sf32a = new Float32Array(sab);
var sf64a = new Float64Array(sab);
var u8ca = new Uint8ClampedArray(sab);
// Atomic ops required integer shared typed arrays
// Atomic ops required integer typed arrays
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) {
assertThrows(function() { Atomics.compareExchange(o, 0, 0, 0); },
......
......@@ -4,7 +4,7 @@
// Flags: --allow-natives-syntax --harmony-sharedarraybuffer
(function TestFailsWithNonSharedArray() {
(function TestNonSharedArrayBehavior() {
var ab = new ArrayBuffer(16);
var i8a = new Int8Array(ab);
......@@ -18,9 +18,13 @@
var f64a = new Float64Array(ab);
[i8a, i16a, i32a, ui8a, ui8ca, ui16a, ui32a, f32a, f64a].forEach(function(
ta) {
ta) {
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
'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
'built-ins/Function/prototype/toString/built-in-function-object': [FAIL],
......
......@@ -444,27 +444,27 @@ KNOWN_OBJECTS = {
("old_space", 0x02a61): "StringSplitCache",
("old_space", 0x02e69): "RegExpMultipleCache",
("old_space", 0x03271): "BuiltinsConstantsTable",
("old_space", 0x03625): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x0364d): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x03675): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x0369d): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x036c5): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x036ed): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x03715): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x0373d): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x03765): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x0378d): "PromiseAllResolveElementSharedFun",
("old_space", 0x037b5): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x037dd): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x03805): "PromiseAnyRejectElementSharedFun",
("old_space", 0x0382d): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x03855): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x0387d): "PromiseCatchFinallySharedFun",
("old_space", 0x038a5): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x038cd): "PromiseThenFinallySharedFun",
("old_space", 0x038f5): "PromiseThrowerFinallySharedFun",
("old_space", 0x0391d): "PromiseValueThunkFinallySharedFun",
("old_space", 0x03945): "ProxyRevokeSharedFun",
("old_space", 0x03645): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x0366d): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x03695): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x036bd): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x036e5): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x0370d): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x03735): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x0375d): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x03785): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x037ad): "PromiseAllResolveElementSharedFun",
("old_space", 0x037d5): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x037fd): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x03825): "PromiseAnyRejectElementSharedFun",
("old_space", 0x0384d): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x03875): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x0389d): "PromiseCatchFinallySharedFun",
("old_space", 0x038c5): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x038ed): "PromiseThenFinallySharedFun",
("old_space", 0x03915): "PromiseThrowerFinallySharedFun",
("old_space", 0x0393d): "PromiseValueThunkFinallySharedFun",
("old_space", 0x03965): "ProxyRevokeSharedFun",
}
# Lower 32 bits of first page addresses for various heap spaces.
......
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