// Copyright 2015 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. #include "src/arguments-inl.h" #include "src/base/macros.h" #include "src/base/platform/mutex.h" #include "src/conversions-inl.h" #include "src/heap/factory.h" #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 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 inline T LoadSeqCst(T* p) { return __atomic_load_n(p, __ATOMIC_SEQ_CST); } template inline void StoreSeqCst(T* p, T value) { __atomic_store_n(p, value, __ATOMIC_SEQ_CST); } template inline T ExchangeSeqCst(T* p, T value) { return __atomic_exchange_n(p, value, __ATOMIC_SEQ_CST); } template inline T CompareExchangeSeqCst(T* p, T oldval, T newval) { (void)__atomic_compare_exchange_n(p, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return oldval; } template inline T AddSeqCst(T* p, T value) { return __atomic_fetch_add(p, value, __ATOMIC_SEQ_CST); } template inline T SubSeqCst(T* p, T value) { return __atomic_fetch_sub(p, value, __ATOMIC_SEQ_CST); } template inline T AndSeqCst(T* p, T value) { return __atomic_fetch_and(p, value, __ATOMIC_SEQ_CST); } template inline T OrSeqCst(T* p, T value) { return __atomic_fetch_or(p, value, __ATOMIC_SEQ_CST); } template 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 #define InterlockedCompareExchange32 _InterlockedCompareExchange #define InterlockedCompareExchange8 _InterlockedCompareExchange8 #define InterlockedExchangeAdd32 _InterlockedExchangeAdd #define InterlockedExchangeAdd16 _InterlockedExchangeAdd16 #define InterlockedExchangeAdd8 _InterlockedExchangeAdd8 #define InterlockedAnd32 _InterlockedAnd #define InterlockedOr64 _InterlockedOr64 #define InterlockedOr32 _InterlockedOr #define InterlockedXor32 _InterlockedXor #define ATOMIC_OPS(type, suffix, vctype) \ inline type ExchangeSeqCst(type* p, type value) { \ return InterlockedExchange##suffix(reinterpret_cast(p), \ bit_cast(value)); \ } \ inline type CompareExchangeSeqCst(type* p, type oldval, type newval) { \ return InterlockedCompareExchange##suffix(reinterpret_cast(p), \ bit_cast(newval), \ bit_cast(oldval)); \ } \ inline type AddSeqCst(type* p, type value) { \ return InterlockedExchangeAdd##suffix(reinterpret_cast(p), \ bit_cast(value)); \ } \ inline type SubSeqCst(type* p, type value) { \ return InterlockedExchangeAdd##suffix(reinterpret_cast(p), \ -bit_cast(value)); \ } \ inline type AndSeqCst(type* p, type value) { \ return InterlockedAnd##suffix(reinterpret_cast(p), \ bit_cast(value)); \ } \ inline type OrSeqCst(type* p, type value) { \ return InterlockedOr##suffix(reinterpret_cast(p), \ bit_cast(value)); \ } \ inline type XorSeqCst(type* p, type value) { \ return InterlockedXor##suffix(reinterpret_cast(p), \ bit_cast(value)); \ } ATOMIC_OPS(int8_t, 8, char) ATOMIC_OPS(uint8_t, 8, char) 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 inline T LoadSeqCst(T* p) { UNREACHABLE(); } template inline void StoreSeqCst(T* p, T value) { UNREACHABLE(); } #undef ATOMIC_OPS #undef InterlockedExchange32 #undef InterlockedCompareExchange32 #undef InterlockedCompareExchange8 #undef InterlockedExchangeAdd32 #undef InterlockedExchangeAdd16 #undef InterlockedExchangeAdd8 #undef InterlockedAnd32 #undef InterlockedOr64 #undef InterlockedOr32 #undef InterlockedXor32 #else #error Unsupported platform! #endif template T FromObject(Handle number); template <> inline uint8_t FromObject(Handle number) { return NumberToUint32(*number); } template <> inline int8_t FromObject(Handle number) { return NumberToInt32(*number); } template <> inline uint16_t FromObject(Handle number) { return NumberToUint32(*number); } template <> inline int16_t FromObject(Handle number) { return NumberToInt32(*number); } template <> inline uint32_t FromObject(Handle number) { return NumberToUint32(*number); } template <> inline int32_t FromObject(Handle number) { return NumberToInt32(*number); } template <> inline uint64_t FromObject(Handle bigint) { return Handle::cast(bigint)->AsUint64(); } template <> inline int64_t FromObject(Handle bigint) { return Handle::cast(bigint)->AsInt64(); } inline Object* ToObject(Isolate* isolate, int8_t t) { return Smi::FromInt(t); } inline Object* ToObject(Isolate* isolate, uint8_t t) { return Smi::FromInt(t); } inline Object* ToObject(Isolate* isolate, int16_t t) { return Smi::FromInt(t); } inline Object* ToObject(Isolate* isolate, uint16_t t) { return Smi::FromInt(t); } inline Object* ToObject(Isolate* isolate, int32_t t) { return *isolate->factory()->NewNumber(t); } inline Object* ToObject(Isolate* isolate, uint32_t t) { return *isolate->factory()->NewNumber(t); } 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 struct Load { static inline Object* Do(Isolate* isolate, void* buffer, size_t index) { T result = LoadSeqCst(static_cast(buffer) + index); return ToObject(isolate, result); } }; template struct Store { static inline void Do(Isolate* isolate, void* buffer, size_t index, Handle obj) { T value = FromObject(obj); StoreSeqCst(static_cast(buffer) + index, value); } }; template struct Exchange { static inline Object* Do(Isolate* isolate, void* buffer, size_t index, Handle obj) { T value = FromObject(obj); T result = ExchangeSeqCst(static_cast(buffer) + index, value); return ToObject(isolate, result); } }; template inline Object* DoCompareExchange(Isolate* isolate, void* buffer, size_t index, Handle oldobj, Handle newobj) { T oldval = FromObject(oldobj); T newval = FromObject(newobj); T result = CompareExchangeSeqCst(static_cast(buffer) + index, oldval, newval); return ToObject(isolate, result); } template struct Add { static inline Object* Do(Isolate* isolate, void* buffer, size_t index, Handle obj) { T value = FromObject(obj); T result = AddSeqCst(static_cast(buffer) + index, value); return ToObject(isolate, result); } }; template struct Sub { static inline Object* Do(Isolate* isolate, void* buffer, size_t index, Handle obj) { T value = FromObject(obj); T result = SubSeqCst(static_cast(buffer) + index, value); return ToObject(isolate, result); } }; template struct And { static inline Object* Do(Isolate* isolate, void* buffer, size_t index, Handle obj) { T value = FromObject(obj); T result = AndSeqCst(static_cast(buffer) + index, value); return ToObject(isolate, result); } }; template struct Or { static inline Object* Do(Isolate* isolate, void* buffer, size_t index, Handle obj) { T value = FromObject(obj); T result = OrSeqCst(static_cast(buffer) + index, value); return ToObject(isolate, result); } }; template struct Xor { static inline Object* Do(Isolate* isolate, void* buffer, size_t index, Handle obj) { T value = FromObject(obj); T result = XorSeqCst(static_cast(buffer) + index, value); return ToObject(isolate, result); } }; } // anonymous namespace // Duplicated from objects.h // V has parameters (Type, type, TYPE, C type) #define INTEGER_TYPED_ARRAYS(V) \ V(Uint8, uint8, UINT8, uint8_t) \ V(Int8, int8, INT8, int8_t) \ V(Uint16, uint16, UINT16, uint16_t) \ V(Int16, int16, INT16, int16_t) \ V(Uint32, uint32, UINT32, uint32_t) \ V(Int32, int32, INT32, int32_t) // 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