diff options
Diffstat (limited to 'deps/v8/src/runtime/runtime-atomics.cc')
-rw-r--r-- | deps/v8/src/runtime/runtime-atomics.cc | 401 |
1 files changed, 249 insertions, 152 deletions
diff --git a/deps/v8/src/runtime/runtime-atomics.cc b/deps/v8/src/runtime/runtime-atomics.cc index 972e48bae6..3fd07af255 100644 --- a/deps/v8/src/runtime/runtime-atomics.cc +++ b/deps/v8/src/runtime/runtime-atomics.cc @@ -17,10 +17,32 @@ namespace v8 { namespace internal { +// Other platforms have CSA support, see builtins-sharedarraybuffer-gen.h. +#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \ + V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X + namespace { #if V8_CC_GNU +// GCC/Clang helpfully warn us that using 64-bit atomics on 32-bit platforms +// can be slow. Good to know, but we don't have a choice. +#ifdef V8_TARGET_ARCH_32_BIT +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Watomic-alignment" +#endif // V8_TARGET_ARCH_32_BIT + +template <typename T> +inline T LoadSeqCst(T* p) { + return __atomic_load_n(p, __ATOMIC_SEQ_CST); +} + +template <typename T> +inline void StoreSeqCst(T* p, T value) { + __atomic_store_n(p, value, __ATOMIC_SEQ_CST); +} + template <typename T> inline T ExchangeSeqCst(T* p, T value) { return __atomic_exchange_n(p, value, __ATOMIC_SEQ_CST); @@ -58,6 +80,10 @@ inline T XorSeqCst(T* p, T value) { return __atomic_fetch_xor(p, value, __ATOMIC_SEQ_CST); } +#ifdef V8_TARGET_ARCH_32_BIT +#pragma GCC diagnostic pop +#endif // V8_TARGET_ARCH_32_BIT + #elif V8_CC_MSVC #define InterlockedExchange32 _InterlockedExchange @@ -67,6 +93,7 @@ inline T XorSeqCst(T* p, T value) { #define InterlockedExchangeAdd16 _InterlockedExchangeAdd16 #define InterlockedExchangeAdd8 _InterlockedExchangeAdd8 #define InterlockedAnd32 _InterlockedAnd +#define InterlockedOr64 _InterlockedOr64 #define InterlockedOr32 _InterlockedOr #define InterlockedXor32 _InterlockedXor @@ -107,6 +134,18 @@ ATOMIC_OPS(int16_t, 16, short) /* NOLINT(runtime/int) */ ATOMIC_OPS(uint16_t, 16, short) /* NOLINT(runtime/int) */ ATOMIC_OPS(int32_t, 32, long) /* NOLINT(runtime/int) */ ATOMIC_OPS(uint32_t, 32, long) /* NOLINT(runtime/int) */ +ATOMIC_OPS(int64_t, 64, __int64) +ATOMIC_OPS(uint64_t, 64, __int64) + +template <typename T> +inline T LoadSeqCst(T* p) { + UNREACHABLE(); +} + +template <typename T> +inline void StoreSeqCst(T* p, T value) { + UNREACHABLE(); +} #undef ATOMIC_OPS @@ -117,6 +156,7 @@ ATOMIC_OPS(uint32_t, 32, long) /* NOLINT(runtime/int) */ #undef InterlockedExchangeAdd16 #undef InterlockedExchangeAdd8 #undef InterlockedAnd32 +#undef InterlockedOr64 #undef InterlockedOr32 #undef InterlockedXor32 @@ -159,6 +199,15 @@ inline int32_t FromObject<int32_t>(Handle<Object> number) { return NumberToInt32(*number); } +template <> +inline uint64_t FromObject<uint64_t>(Handle<Object> bigint) { + return Handle<BigInt>::cast(bigint)->AsUint64(); +} + +template <> +inline int64_t FromObject<int64_t>(Handle<Object> bigint) { + return Handle<BigInt>::cast(bigint)->AsInt64(); +} inline Object* ToObject(Isolate* isolate, int8_t t) { return Smi::FromInt(t); } @@ -178,15 +227,42 @@ inline Object* ToObject(Isolate* isolate, uint32_t t) { return *isolate->factory()->NewNumber(t); } -template <typename T> -inline Object* DoExchange(Isolate* isolate, void* buffer, size_t index, - Handle<Object> obj) { - T value = FromObject<T>(obj); - T result = ExchangeSeqCst(static_cast<T*>(buffer) + index, value); - return ToObject(isolate, result); +inline Object* ToObject(Isolate* isolate, int64_t t) { + return *BigInt::FromInt64(isolate, t); +} + +inline Object* ToObject(Isolate* isolate, uint64_t t) { + return *BigInt::FromUint64(isolate, t); } template <typename T> +struct Load { + static inline Object* Do(Isolate* isolate, void* buffer, size_t index) { + T result = LoadSeqCst(static_cast<T*>(buffer) + index); + return ToObject(isolate, result); + } +}; + +template <typename T> +struct Store { + static inline void Do(Isolate* isolate, void* buffer, size_t index, + Handle<Object> obj) { + T value = FromObject<T>(obj); + StoreSeqCst(static_cast<T*>(buffer) + index, value); + } +}; + +template <typename T> +struct Exchange { + static inline Object* Do(Isolate* isolate, void* buffer, size_t index, + Handle<Object> obj) { + T value = FromObject<T>(obj); + T result = ExchangeSeqCst(static_cast<T*>(buffer) + index, value); + return ToObject(isolate, result); + } +}; + +template <typename T> inline Object* DoCompareExchange(Isolate* isolate, void* buffer, size_t index, Handle<Object> oldobj, Handle<Object> newobj) { T oldval = FromObject<T>(oldobj); @@ -197,44 +273,54 @@ inline Object* DoCompareExchange(Isolate* isolate, void* buffer, size_t index, } template <typename T> -inline Object* DoAdd(Isolate* isolate, void* buffer, size_t index, - Handle<Object> obj) { - T value = FromObject<T>(obj); - T result = AddSeqCst(static_cast<T*>(buffer) + index, value); - return ToObject(isolate, result); -} +struct Add { + static inline Object* Do(Isolate* isolate, void* buffer, size_t index, + Handle<Object> obj) { + T value = FromObject<T>(obj); + T result = AddSeqCst(static_cast<T*>(buffer) + index, value); + return ToObject(isolate, result); + } +}; template <typename T> -inline Object* DoSub(Isolate* isolate, void* buffer, size_t index, - Handle<Object> obj) { - T value = FromObject<T>(obj); - T result = SubSeqCst(static_cast<T*>(buffer) + index, value); - return ToObject(isolate, result); -} +struct Sub { + static inline Object* Do(Isolate* isolate, void* buffer, size_t index, + Handle<Object> obj) { + T value = FromObject<T>(obj); + T result = SubSeqCst(static_cast<T*>(buffer) + index, value); + return ToObject(isolate, result); + } +}; template <typename T> -inline Object* DoAnd(Isolate* isolate, void* buffer, size_t index, - Handle<Object> obj) { - T value = FromObject<T>(obj); - T result = AndSeqCst(static_cast<T*>(buffer) + index, value); - return ToObject(isolate, result); -} +struct And { + static inline Object* Do(Isolate* isolate, void* buffer, size_t index, + Handle<Object> obj) { + T value = FromObject<T>(obj); + T result = AndSeqCst(static_cast<T*>(buffer) + index, value); + return ToObject(isolate, result); + } +}; template <typename T> -inline Object* DoOr(Isolate* isolate, void* buffer, size_t index, - Handle<Object> obj) { - T value = FromObject<T>(obj); - T result = OrSeqCst(static_cast<T*>(buffer) + index, value); - return ToObject(isolate, result); -} +struct Or { + static inline Object* Do(Isolate* isolate, void* buffer, size_t index, + Handle<Object> obj) { + T value = FromObject<T>(obj); + T result = OrSeqCst(static_cast<T*>(buffer) + index, value); + return ToObject(isolate, result); + } +}; template <typename T> -inline Object* DoXor(Isolate* isolate, void* buffer, size_t index, - Handle<Object> obj) { - T value = FromObject<T>(obj); - T result = XorSeqCst(static_cast<T*>(buffer) + index, value); - return ToObject(isolate, result); -} +struct Xor { + static inline Object* Do(Isolate* isolate, void* buffer, size_t index, + Handle<Object> obj) { + T value = FromObject<T>(obj); + T result = XorSeqCst(static_cast<T*>(buffer) + index, value); + return ToObject(isolate, result); + } +}; } // anonymous namespace @@ -248,22 +334,44 @@ inline Object* DoXor(Isolate* isolate, void* buffer, size_t index, V(Uint32, uint32, UINT32, uint32_t) \ V(Int32, int32, INT32, int32_t) -RUNTIME_FUNCTION(Runtime_AtomicsExchange) { +// 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(Arguments args, Isolate* isolate) { HandleScope scope(isolate); DCHECK_EQ(3, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); CONVERT_SIZE_ARG_CHECKED(index, 1); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); + CONVERT_ARG_HANDLE_CHECKED(Object, value_obj, 2); CHECK(sta->GetBuffer()->is_shared()); - CHECK_LT(index, NumberToSize(sta->length())); uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + - NumberToSize(sta->byte_offset()); + sta->byte_offset(); + + if (sta->type() >= kExternalBigInt64Array) { + Handle<BigInt> bigint; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, bigint, + BigInt::FromObject(isolate, value_obj)); + // SharedArrayBuffers are not neuterable. + CHECK_LT(index, NumberToSize(sta->length())); + if (sta->type() == kExternalBigInt64Array) { + return Op<int64_t>::Do(isolate, source, index, bigint); + } + DCHECK(sta->type() == kExternalBigUint64Array); + return Op<uint64_t>::Do(isolate, source, index, bigint); + } + + Handle<Object> value; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, + Object::ToInteger(isolate, value_obj)); + // SharedArrayBuffers are not neuterable. + CHECK_LT(index, NumberToSize(sta->length())); switch (sta->type()) { #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype) \ case kExternal##Type##Array: \ - return DoExchange<ctype>(isolate, source, index, value); + return Op<ctype>::Do(isolate, source, index, value); INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE @@ -275,81 +383,104 @@ RUNTIME_FUNCTION(Runtime_AtomicsExchange) { UNREACHABLE(); } -RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) { +RUNTIME_FUNCTION(Runtime_AtomicsLoad64) { HandleScope scope(isolate); - DCHECK_EQ(4, args.length()); + DCHECK_EQ(2, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); CONVERT_SIZE_ARG_CHECKED(index, 1); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(oldobj, 2); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(newobj, 3); CHECK(sta->GetBuffer()->is_shared()); - CHECK_LT(index, NumberToSize(sta->length())); uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + - NumberToSize(sta->byte_offset()); + sta->byte_offset(); - switch (sta->type()) { -#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype) \ - case kExternal##Type##Array: \ - return DoCompareExchange<ctype>(isolate, source, index, oldobj, newobj); - - INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) -#undef TYPED_ARRAY_CASE - - default: - break; + DCHECK(sta->type() == kExternalBigInt64Array || + sta->type() == kExternalBigUint64Array); + // SharedArrayBuffers are not neuterable. + CHECK_LT(index, NumberToSize(sta->length())); + if (sta->type() == kExternalBigInt64Array) { + return Load<int64_t>::Do(isolate, source, index); } - - UNREACHABLE(); + DCHECK(sta->type() == kExternalBigUint64Array); + return Load<uint64_t>::Do(isolate, source, index); } -// ES #sec-atomics.add -// Atomics.add( typedArray, index, value ) -RUNTIME_FUNCTION(Runtime_AtomicsAdd) { +RUNTIME_FUNCTION(Runtime_AtomicsStore64) { HandleScope scope(isolate); DCHECK_EQ(3, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); CONVERT_SIZE_ARG_CHECKED(index, 1); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); + CONVERT_ARG_HANDLE_CHECKED(Object, value_obj, 2); CHECK(sta->GetBuffer()->is_shared()); - CHECK_LT(index, NumberToSize(sta->length())); uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + - NumberToSize(sta->byte_offset()); + sta->byte_offset(); - switch (sta->type()) { -#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype) \ - case kExternal##Type##Array: \ - return DoAdd<ctype>(isolate, source, index, value); + Handle<BigInt> bigint; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, bigint, + BigInt::FromObject(isolate, value_obj)); - INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) -#undef TYPED_ARRAY_CASE - - default: - break; + DCHECK(sta->type() == kExternalBigInt64Array || + sta->type() == kExternalBigUint64Array); + // SharedArrayBuffers are not neuterable. + CHECK_LT(index, NumberToSize(sta->length())); + if (sta->type() == kExternalBigInt64Array) { + Store<int64_t>::Do(isolate, source, index, bigint); + return *bigint; } + DCHECK(sta->type() == kExternalBigUint64Array); + Store<uint64_t>::Do(isolate, source, index, bigint); + return *bigint; +} - UNREACHABLE(); +RUNTIME_FUNCTION(Runtime_AtomicsExchange) { + return GetModifySetValueInBuffer<Exchange>(args, isolate); } -// ES #sec-atomics.sub -// Atomics.sub( typedArray, index, value ) -RUNTIME_FUNCTION(Runtime_AtomicsSub) { +RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) { HandleScope scope(isolate); - DCHECK_EQ(3, args.length()); + DCHECK_EQ(4, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); CONVERT_SIZE_ARG_CHECKED(index, 1); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); + 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, NumberToSize(sta->length())); uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + - NumberToSize(sta->byte_offset()); + sta->byte_offset(); + + if (sta->type() >= kExternalBigInt64Array) { + Handle<BigInt> old_bigint; + Handle<BigInt> new_bigint; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + 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 neuterable. + CHECK_LT(index, NumberToSize(sta->length())); + if (sta->type() == kExternalBigInt64Array) { + return DoCompareExchange<int64_t>(isolate, source, index, old_bigint, + new_bigint); + } + DCHECK(sta->type() == kExternalBigUint64Array); + return DoCompareExchange<uint64_t>(isolate, source, index, old_bigint, + new_bigint); + } + + Handle<Object> old_value; + Handle<Object> new_value; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, old_value, + Object::ToInteger(isolate, old_value_obj)); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, new_value, + Object::ToInteger(isolate, new_value_obj)); + // SharedArrayBuffers are not neuterable. + CHECK_LT(index, NumberToSize(sta->length())); switch (sta->type()) { -#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype) \ - case kExternal##Type##Array: \ - return DoSub<ctype>(isolate, source, index, value); +#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype) \ + case kExternal##Type##Array: \ + return DoCompareExchange<ctype>(isolate, source, index, old_value, \ + new_value); INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE @@ -361,94 +492,60 @@ RUNTIME_FUNCTION(Runtime_AtomicsSub) { UNREACHABLE(); } +// ES #sec-atomics.add +// Atomics.add( typedArray, index, value ) +RUNTIME_FUNCTION(Runtime_AtomicsAdd) { + return GetModifySetValueInBuffer<Add>(args, isolate); +} + +// ES #sec-atomics.sub +// Atomics.sub( typedArray, index, value ) +RUNTIME_FUNCTION(Runtime_AtomicsSub) { + return GetModifySetValueInBuffer<Sub>(args, isolate); +} + // ES #sec-atomics.and // Atomics.and( typedArray, index, value ) RUNTIME_FUNCTION(Runtime_AtomicsAnd) { - HandleScope scope(isolate); - DCHECK_EQ(3, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); - CONVERT_SIZE_ARG_CHECKED(index, 1); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); - CHECK(sta->GetBuffer()->is_shared()); - CHECK_LT(index, NumberToSize(sta->length())); - - uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + - NumberToSize(sta->byte_offset()); - - switch (sta->type()) { -#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype) \ - case kExternal##Type##Array: \ - return DoAnd<ctype>(isolate, source, index, value); - - INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) -#undef TYPED_ARRAY_CASE - - default: - break; - } - - UNREACHABLE(); + return GetModifySetValueInBuffer<And>(args, isolate); } // ES #sec-atomics.or // Atomics.or( typedArray, index, value ) RUNTIME_FUNCTION(Runtime_AtomicsOr) { - HandleScope scope(isolate); - DCHECK_EQ(3, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); - CONVERT_SIZE_ARG_CHECKED(index, 1); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); - CHECK(sta->GetBuffer()->is_shared()); - CHECK_LT(index, NumberToSize(sta->length())); + return GetModifySetValueInBuffer<Or>(args, isolate); +} - uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + - NumberToSize(sta->byte_offset()); +// ES #sec-atomics.xor +// Atomics.xor( typedArray, index, value ) +RUNTIME_FUNCTION(Runtime_AtomicsXor) { + return GetModifySetValueInBuffer<Xor>(args, isolate); +} - switch (sta->type()) { -#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype) \ - case kExternal##Type##Array: \ - return DoOr<ctype>(isolate, source, index, value); +#undef INTEGER_TYPED_ARRAYS - INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) -#undef TYPED_ARRAY_CASE +#else - default: - break; - } +RUNTIME_FUNCTION(Runtime_AtomicsLoad64) { UNREACHABLE(); } - UNREACHABLE(); -} +RUNTIME_FUNCTION(Runtime_AtomicsStore64) { UNREACHABLE(); } -// ES #sec-atomics.xor -// Atomics.xor( typedArray, index, value ) -RUNTIME_FUNCTION(Runtime_AtomicsXor) { - HandleScope scope(isolate); - DCHECK_EQ(3, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); - CONVERT_SIZE_ARG_CHECKED(index, 1); - CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); - CHECK(sta->GetBuffer()->is_shared()); - CHECK_LT(index, NumberToSize(sta->length())); +RUNTIME_FUNCTION(Runtime_AtomicsExchange) { UNREACHABLE(); } - uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + - NumberToSize(sta->byte_offset()); +RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) { UNREACHABLE(); } - switch (sta->type()) { -#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype) \ - case kExternal##Type##Array: \ - return DoXor<ctype>(isolate, source, index, value); +RUNTIME_FUNCTION(Runtime_AtomicsAdd) { UNREACHABLE(); } - INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) -#undef TYPED_ARRAY_CASE +RUNTIME_FUNCTION(Runtime_AtomicsSub) { UNREACHABLE(); } - default: - break; - } +RUNTIME_FUNCTION(Runtime_AtomicsAnd) { UNREACHABLE(); } - UNREACHABLE(); -} +RUNTIME_FUNCTION(Runtime_AtomicsOr) { UNREACHABLE(); } -#undef INTEGER_TYPED_ARRAYS +RUNTIME_FUNCTION(Runtime_AtomicsXor) { UNREACHABLE(); } + +#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 } // namespace internal } // namespace v8 |