"src/messages.h",
"src/proxy.js",
"src/generator.js",
+ "src/harmony-atomics.js",
"src/harmony-array.js",
"src/harmony-array-includes.js",
"src/harmony-typedarray.js",
"src/runtime-profiler.cc",
"src/runtime-profiler.h",
"src/runtime/runtime-array.cc",
+ "src/runtime/runtime-atomics.cc",
"src/runtime/runtime-classes.cc",
"src/runtime/runtime-collections.cc",
"src/runtime/runtime-compiler.cc",
bool InstallExperimentalNatives();
bool InstallExtraNatives();
void InstallBuiltinFunctionIds();
+ void InstallExperimentalBuiltinFunctionIds();
void InstallJSFunctionResultCaches();
void InitializeNormalizedMapCaches();
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_object)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_spread_arrays)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_sharedarraybuffer)
+EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_atomics)
void Genesis::InstallNativeFunctions_harmony_proxies() {
}
}
+
#undef INSTALL_NATIVE
#define EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(id) \
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_destructuring)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_object)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_spread_arrays)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_atomics)
void Genesis::InitializeGlobal_harmony_regexps() {
Handle<JSObject> builtins(native_context()->builtins());
static const char* harmony_spread_arrays_natives[] = {nullptr};
static const char* harmony_sharedarraybuffer_natives[] = {
"native harmony-sharedarraybuffer.js", NULL};
+ static const char* harmony_atomics_natives[] = {"native harmony-atomics.js",
+ nullptr};
for (int i = ExperimentalNatives::GetDebuggerCount();
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
CallUtilsFunction(isolate(), "PostExperimentals");
InstallExperimentalNativeFunctions();
+ InstallExperimentalBuiltinFunctionIds();
return true;
}
}
+#define INSTALL_BUILTIN_ID(holder_expr, fun_name, name) \
+ { #holder_expr, #fun_name, k##name } \
+ ,
+
+
void Genesis::InstallBuiltinFunctionIds() {
HandleScope scope(isolate());
struct BuiltinFunctionIds {
BuiltinFunctionId id;
};
-#define INSTALL_BUILTIN_ID(holder_expr, fun_name, name) \
- { #holder_expr, #fun_name, k##name } \
- ,
const BuiltinFunctionIds builtins[] = {
FUNCTIONS_WITH_ID_LIST(INSTALL_BUILTIN_ID)};
-#undef INSTALL_BUILTIN_ID
for (const BuiltinFunctionIds& builtin : builtins) {
Handle<JSObject> holder =
}
+void Genesis::InstallExperimentalBuiltinFunctionIds() {
+ if (FLAG_harmony_atomics) {
+ struct BuiltinFunctionIds {
+ const char* holder_expr;
+ const char* fun_name;
+ BuiltinFunctionId id;
+ };
+
+ const BuiltinFunctionIds atomic_builtins[] = {
+ ATOMIC_FUNCTIONS_WITH_ID_LIST(INSTALL_BUILTIN_ID)};
+
+ for (const BuiltinFunctionIds& builtin : atomic_builtins) {
+ Handle<JSObject> holder =
+ ResolveBuiltinIdHolder(native_context(), builtin.holder_expr);
+ InstallBuiltinFunctionId(holder, builtin.fun_name, builtin.id);
+ }
+ }
+}
+
+
+#undef INSTALL_BUILTIN_ID
+
+
// Do not forget to update macros.py with named constant
// of cache id.
#define JSFUNCTION_RESULT_CACHE_LIST(F) \
V(harmony_unicode_regexps, "harmony unicode regexps") \
V(harmony_reflect, "harmony Reflect API") \
V(harmony_destructuring, "harmony destructuring") \
- V(harmony_sharedarraybuffer, "harmony sharedarraybuffer")
+ V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
+ V(harmony_atomics, "harmony atomics")
// Features that are complete (but still behind --harmony/es-staging flag).
#define HARMONY_STAGED(V) \
--- /dev/null
+// 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.
+
+(function(global, utils) {
+
+"use strict";
+
+%CheckIsBootstrapping();
+
+// -------------------------------------------------------------------
+// Imports
+
+var GlobalObject = global.Object;
+
+// -------------------------------------------------------------------
+
+
+function CheckSharedTypedArray(sta) {
+ if (!%_IsSharedTypedArray(sta)) {
+ throw MakeTypeError(kNotSharedTypedArray, sta);
+ }
+}
+
+function CheckSharedIntegerTypedArray(ia) {
+ if (!%_IsSharedIntegerTypedArray(ia)) {
+ throw MakeTypeError(kNotIntegerSharedTypedArray, ia);
+ }
+}
+
+//-------------------------------------------------------------------
+
+function AtomicsCompareExchangeJS(sta, index, oldValue, newValue) {
+ CheckSharedTypedArray(sta);
+ index = $toInteger(index);
+ if (index < 0 || index >= sta.length) {
+ return UNDEFINED;
+ }
+ return %_AtomicsCompareExchange(sta, index, oldValue, newValue);
+}
+
+function AtomicsLoadJS(sta, index) {
+ CheckSharedTypedArray(sta);
+ index = $toInteger(index);
+ if (index < 0 || index >= sta.length) {
+ return UNDEFINED;
+ }
+ return %_AtomicsLoad(sta, index);
+}
+
+function AtomicsStoreJS(sta, index, value) {
+ CheckSharedTypedArray(sta);
+ index = $toInteger(index);
+ if (index < 0 || index >= sta.length) {
+ return UNDEFINED;
+ }
+ return %_AtomicsStore(sta, index, value);
+}
+
+function AtomicsAddJS(ia, index, value) {
+ CheckSharedIntegerTypedArray(ia);
+ index = $toInteger(index);
+ if (index < 0 || index >= ia.length) {
+ return UNDEFINED;
+ }
+ return %_AtomicsAdd(ia, index, value);
+}
+
+function AtomicsSubJS(ia, index, value) {
+ CheckSharedIntegerTypedArray(ia);
+ index = $toInteger(index);
+ if (index < 0 || index >= ia.length) {
+ return UNDEFINED;
+ }
+ return %_AtomicsSub(ia, index, value);
+}
+
+function AtomicsAndJS(ia, index, value) {
+ CheckSharedIntegerTypedArray(ia);
+ index = $toInteger(index);
+ if (index < 0 || index >= ia.length) {
+ return UNDEFINED;
+ }
+ return %_AtomicsAnd(ia, index, value);
+}
+
+function AtomicsOrJS(ia, index, value) {
+ CheckSharedIntegerTypedArray(ia);
+ index = $toInteger(index);
+ if (index < 0 || index >= ia.length) {
+ return UNDEFINED;
+ }
+ return %_AtomicsOr(ia, index, value);
+}
+
+function AtomicsXorJS(ia, index, value) {
+ CheckSharedIntegerTypedArray(ia);
+ index = $toInteger(index);
+ if (index < 0 || index >= ia.length) {
+ return UNDEFINED;
+ }
+ return %_AtomicsXor(ia, index, value);
+}
+
+function AtomicsExchangeJS(ia, index, value) {
+ CheckSharedIntegerTypedArray(ia);
+ index = $toInteger(index);
+ if (index < 0 || index >= ia.length) {
+ return UNDEFINED;
+ }
+ return %_AtomicsExchange(ia, index, value);
+}
+
+function AtomicsIsLockFreeJS(size) {
+ return %_AtomicsIsLockFree(size);
+}
+
+// -------------------------------------------------------------------
+
+function AtomicsConstructor() {}
+
+var Atomics = new AtomicsConstructor();
+
+%InternalSetPrototype(Atomics, GlobalObject.prototype);
+%AddNamedProperty(global, "Atomics", Atomics, DONT_ENUM);
+%FunctionSetInstanceClassName(AtomicsConstructor, 'Atomics');
+
+%AddNamedProperty(Atomics, symbolToStringTag, "Atomics", READ_ONLY | DONT_ENUM);
+
+utils.InstallFunctions(Atomics, DONT_ENUM, [
+ "compareExchange", AtomicsCompareExchangeJS,
+ "load", AtomicsLoadJS,
+ "store", AtomicsStoreJS,
+ "add", AtomicsAddJS,
+ "sub", AtomicsSubJS,
+ "and", AtomicsAndJS,
+ "or", AtomicsOrJS,
+ "xor", AtomicsXorJS,
+ "exchange", AtomicsExchangeJS,
+ "isLockFree", AtomicsIsLockFreeJS,
+]);
+
+})
T(NotGeneric, "% is not generic") \
T(NotIterable, "% is not iterable") \
T(NotTypedArray, "this is not a typed array.") \
+ T(NotSharedTypedArray, "% is not a shared typed array.") \
+ T(NotIntegerSharedTypedArray, "% is not an integer shared typed array.") \
T(ObjectGetterExpectingFunction, \
"Object.prototype.__defineGetter__: Expecting function") \
T(ObjectGetterCallable, "Getter must be a function: %") \
V(Math, clz32, MathClz32) \
V(Math, fround, MathFround)
+#define ATOMIC_FUNCTIONS_WITH_ID_LIST(V) \
+ V(Atomics, load, AtomicsLoad) \
+ V(Atomics, store, AtomicsStore)
+
enum BuiltinFunctionId {
kArrayCode,
#define DECLARE_FUNCTION_ID(ignored1, ignore2, name) \
k##name,
FUNCTIONS_WITH_ID_LIST(DECLARE_FUNCTION_ID)
+ ATOMIC_FUNCTIONS_WITH_ID_LIST(DECLARE_FUNCTION_ID)
#undef DECLARE_FUNCTION_ID
// Fake id for a special case of Math.pow. Note, it continues the
// list of math functions.
--- /dev/null
+// 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/v8.h"
+
+#include "src/arguments.h"
+#include "src/base/macros.h"
+#include "src/base/platform/mutex.h"
+#include "src/conversions.h"
+#include "src/runtime/runtime-utils.h"
+
+// Implement Atomic accesses to SharedArrayBuffers as defined in the
+// SharedArrayBuffer draft spec, found here
+// https://docs.google.com/document/d/1NDGA_gZJ7M7w1Bh8S0AoDyEqwDdRh4uSoTPSNn77PFk
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+#if V8_CC_GNU
+
+template <typename T>
+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 <typename T>
+inline T LoadSeqCst(T* p) {
+ T result;
+ __atomic_load(p, &result, __ATOMIC_SEQ_CST);
+ return result;
+}
+
+template <typename T>
+inline void StoreSeqCst(T* p, T value) {
+ __atomic_store_n(p, value, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T AddSeqCst(T* p, T value) {
+ return __atomic_fetch_add(p, value, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T SubSeqCst(T* p, T value) {
+ return __atomic_fetch_sub(p, value, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T AndSeqCst(T* p, T value) {
+ return __atomic_fetch_and(p, value, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T OrSeqCst(T* p, T value) {
+ return __atomic_fetch_or(p, value, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T XorSeqCst(T* p, T value) {
+ return __atomic_fetch_xor(p, value, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T ExchangeSeqCst(T* p, T value) {
+ return __atomic_exchange_n(p, value, __ATOMIC_SEQ_CST);
+}
+
+#if ATOMICS_REQUIRE_LOCK_64_BIT
+
+// We only need to implement the following functions, because the rest of the
+// atomic operations only work on integer types, and the only 64-bit type is
+// float64. Similarly, because the values are being bit_cast from double ->
+// uint64_t, we don't need to implement these functions for int64_t either.
+
+static base::LazyMutex atomic_mutex = LAZY_MUTEX_INITIALIZER;
+
+inline uint64_t CompareExchangeSeqCst(uint64_t* p, uint64_t oldval,
+ uint64_t newval) {
+ base::LockGuard<base::Mutex> lock_guard(atomic_mutex.Pointer());
+ uint64_t result = *p;
+ if (result == oldval) *p = newval;
+ return result;
+}
+
+
+inline uint64_t LoadSeqCst(uint64_t* p) {
+ base::LockGuard<base::Mutex> lock_guard(atomic_mutex.Pointer());
+ return *p;
+}
+
+
+inline void StoreSeqCst(uint64_t* p, uint64_t value) {
+ base::LockGuard<base::Mutex> lock_guard(atomic_mutex.Pointer());
+ *p = value;
+}
+
+#endif // ATOMICS_REQUIRE_LOCK_64_BIT
+
+#elif V8_CC_MSVC
+
+#define _InterlockedCompareExchange32 _InterlockedCompareExchange
+#define _InterlockedExchange32 _InterlockedExchange
+#define _InterlockedExchangeAdd32 _InterlockedExchangeAdd
+#define _InterlockedAnd32 _InterlockedAnd
+#define _InterlockedOr32 _InterlockedOr
+#define _InterlockedXor32 _InterlockedXor
+
+#define INTEGER_TYPES(V) \
+ V(int8_t, 8, char) \
+ V(uint8_t, 8, char) \
+ V(int16_t, 16, short) /* NOLINT(runtime/int) */ \
+ V(uint16_t, 16, short) /* NOLINT(runtime/int) */ \
+ V(int32_t, 32, long) /* NOLINT(runtime/int) */ \
+ V(uint32_t, 32, long) /* NOLINT(runtime/int) */ \
+ V(int64_t, 64, LONGLONG) \
+ V(uint64_t, 64, LONGLONG)
+
+#define ATOMIC_OPS(type, suffix, vctype) \
+ inline type CompareExchangeSeqCst(volatile type* p, type oldval, \
+ type newval) { \
+ return _InterlockedCompareExchange##suffix( \
+ reinterpret_cast<volatile vctype*>(p), bit_cast<vctype>(newval), \
+ bit_cast<vctype>(oldval)); \
+ } \
+ inline type LoadSeqCst(volatile type* p) { return *p; } \
+ inline void StoreSeqCst(volatile type* p, type value) { \
+ _InterlockedExchange##suffix(reinterpret_cast<volatile vctype*>(p), \
+ bit_cast<vctype>(value)); \
+ } \
+ inline type AddSeqCst(volatile type* p, type value) { \
+ return _InterlockedExchangeAdd##suffix( \
+ reinterpret_cast<volatile vctype*>(p), bit_cast<vctype>(value)); \
+ } \
+ inline type SubSeqCst(volatile type* p, type value) { \
+ return _InterlockedExchangeAdd##suffix( \
+ reinterpret_cast<volatile vctype*>(p), -bit_cast<vctype>(value)); \
+ } \
+ inline type AndSeqCst(volatile type* p, type value) { \
+ return _InterlockedAnd##suffix(reinterpret_cast<volatile vctype*>(p), \
+ bit_cast<vctype>(value)); \
+ } \
+ inline type OrSeqCst(volatile type* p, type value) { \
+ return _InterlockedOr##suffix(reinterpret_cast<volatile vctype*>(p), \
+ bit_cast<vctype>(value)); \
+ } \
+ inline type XorSeqCst(volatile type* p, type value) { \
+ return _InterlockedXor##suffix(reinterpret_cast<volatile vctype*>(p), \
+ bit_cast<vctype>(value)); \
+ } \
+ inline type ExchangeSeqCst(volatile type* p, type value) { \
+ return _InterlockedExchange##suffix(reinterpret_cast<volatile vctype*>(p), \
+ bit_cast<vctype>(value)); \
+ }
+INTEGER_TYPES(ATOMIC_OPS)
+#undef ATOMIC_OPS
+
+#undef INTEGER_TYPES
+#undef _InterlockedCompareExchange32
+#undef _InterlockedExchange32
+#undef _InterlockedExchangeAdd32
+#undef _InterlockedAnd32
+#undef _InterlockedOr32
+#undef _InterlockedXor32
+
+#else
+
+#error Unsupported platform!
+
+#endif
+
+template <typename T>
+T FromObject(Handle<Object> number);
+
+template <>
+inline uint32_t FromObject<uint32_t>(Handle<Object> number) {
+ return NumberToUint32(*number);
+}
+
+template <>
+inline int32_t FromObject<int32_t>(Handle<Object> number) {
+ return NumberToInt32(*number);
+}
+
+template <>
+inline float FromObject<float>(Handle<Object> number) {
+ return static_cast<float>(number->Number());
+}
+
+template <>
+inline double FromObject<double>(Handle<Object> number) {
+ return number->Number();
+}
+
+template <typename T, typename F>
+inline T ToAtomic(F from) {
+ return static_cast<T>(from);
+}
+
+template <>
+inline uint32_t ToAtomic<uint32_t, float>(float from) {
+ return bit_cast<uint32_t, float>(from);
+}
+
+template <>
+inline uint64_t ToAtomic<uint64_t, double>(double from) {
+ return bit_cast<uint64_t, double>(from);
+}
+
+template <typename T, typename F>
+inline T FromAtomic(F from) {
+ return static_cast<T>(from);
+}
+
+template <>
+inline float FromAtomic<float, uint32_t>(uint32_t from) {
+ return bit_cast<float, uint32_t>(from);
+}
+
+template <>
+inline double FromAtomic<double, uint64_t>(uint64_t from) {
+ return bit_cast<double, uint64_t>(from);
+}
+
+template <typename T>
+inline Object* ToObject(Isolate* isolate, T t);
+
+template <>
+inline Object* ToObject<int8_t>(Isolate* isolate, int8_t t) {
+ return Smi::FromInt(t);
+}
+
+template <>
+inline Object* ToObject<uint8_t>(Isolate* isolate, uint8_t t) {
+ return Smi::FromInt(t);
+}
+
+template <>
+inline Object* ToObject<int16_t>(Isolate* isolate, int16_t t) {
+ return Smi::FromInt(t);
+}
+
+template <>
+inline Object* ToObject<uint16_t>(Isolate* isolate, uint16_t t) {
+ return Smi::FromInt(t);
+}
+
+template <>
+inline Object* ToObject<int32_t>(Isolate* isolate, int32_t t) {
+ return *isolate->factory()->NewNumber(t);
+}
+
+template <>
+inline Object* ToObject<uint32_t>(Isolate* isolate, uint32_t t) {
+ return *isolate->factory()->NewNumber(t);
+}
+
+template <>
+inline Object* ToObject<float>(Isolate* isolate, float t) {
+ return *isolate->factory()->NewNumber(t);
+}
+
+template <>
+inline Object* ToObject<double>(Isolate* isolate, double t) {
+ return *isolate->factory()->NewNumber(t);
+}
+
+template <typename T>
+struct FromObjectTraits {};
+
+template <>
+struct FromObjectTraits<int8_t> {
+ typedef int32_t convert_type;
+ typedef int8_t atomic_type;
+};
+
+template <>
+struct FromObjectTraits<uint8_t> {
+ typedef uint32_t convert_type;
+ typedef uint8_t atomic_type;
+};
+
+template <>
+struct FromObjectTraits<int16_t> {
+ typedef int32_t convert_type;
+ typedef int16_t atomic_type;
+};
+
+template <>
+struct FromObjectTraits<uint16_t> {
+ typedef uint32_t convert_type;
+ typedef uint16_t atomic_type;
+};
+
+template <>
+struct FromObjectTraits<int32_t> {
+ typedef int32_t convert_type;
+ typedef int32_t atomic_type;
+};
+
+template <>
+struct FromObjectTraits<uint32_t> {
+ typedef uint32_t convert_type;
+ typedef uint32_t atomic_type;
+};
+
+template <>
+struct FromObjectTraits<float> {
+ typedef float convert_type;
+ typedef uint32_t atomic_type;
+};
+
+template <>
+struct FromObjectTraits<double> {
+ typedef double convert_type;
+ typedef uint64_t atomic_type;
+};
+
+
+template <typename T>
+inline Object* DoCompareExchange(Isolate* isolate, void* buffer, size_t index,
+ Handle<Object> oldobj, Handle<Object> newobj) {
+ typedef typename FromObjectTraits<T>::atomic_type atomic_type;
+ typedef typename FromObjectTraits<T>::convert_type convert_type;
+ atomic_type oldval = ToAtomic<atomic_type>(FromObject<convert_type>(oldobj));
+ atomic_type newval = ToAtomic<atomic_type>(FromObject<convert_type>(newobj));
+ atomic_type result = CompareExchangeSeqCst(
+ static_cast<atomic_type*>(buffer) + index, oldval, newval);
+ return ToObject<T>(isolate, FromAtomic<T>(result));
+}
+
+
+template <typename T>
+inline Object* DoLoad(Isolate* isolate, void* buffer, size_t index) {
+ typedef typename FromObjectTraits<T>::atomic_type atomic_type;
+ atomic_type result = LoadSeqCst(static_cast<atomic_type*>(buffer) + index);
+ return ToObject<T>(isolate, FromAtomic<T>(result));
+}
+
+
+template <typename T>
+inline Object* DoStore(Isolate* isolate, void* buffer, size_t index,
+ Handle<Object> obj) {
+ typedef typename FromObjectTraits<T>::atomic_type atomic_type;
+ typedef typename FromObjectTraits<T>::convert_type convert_type;
+ atomic_type value = ToAtomic<atomic_type>(FromObject<convert_type>(obj));
+ StoreSeqCst(static_cast<atomic_type*>(buffer) + index, value);
+ return *obj;
+}
+
+
+template <typename T>
+inline Object* DoAdd(Isolate* isolate, void* buffer, size_t index,
+ Handle<Object> obj) {
+ typedef typename FromObjectTraits<T>::atomic_type atomic_type;
+ typedef typename FromObjectTraits<T>::convert_type convert_type;
+ atomic_type value = ToAtomic<atomic_type>(FromObject<convert_type>(obj));
+ atomic_type result =
+ AddSeqCst(static_cast<atomic_type*>(buffer) + index, value);
+ return ToObject<T>(isolate, FromAtomic<T>(result));
+}
+
+
+template <typename T>
+inline Object* DoSub(Isolate* isolate, void* buffer, size_t index,
+ Handle<Object> obj) {
+ typedef typename FromObjectTraits<T>::atomic_type atomic_type;
+ typedef typename FromObjectTraits<T>::convert_type convert_type;
+ atomic_type value = ToAtomic<atomic_type>(FromObject<convert_type>(obj));
+ atomic_type result =
+ SubSeqCst(static_cast<atomic_type*>(buffer) + index, value);
+ return ToObject<T>(isolate, FromAtomic<T>(result));
+}
+
+
+template <typename T>
+inline Object* DoAnd(Isolate* isolate, void* buffer, size_t index,
+ Handle<Object> obj) {
+ typedef typename FromObjectTraits<T>::atomic_type atomic_type;
+ typedef typename FromObjectTraits<T>::convert_type convert_type;
+ atomic_type value = ToAtomic<atomic_type>(FromObject<convert_type>(obj));
+ atomic_type result =
+ AndSeqCst(static_cast<atomic_type*>(buffer) + index, value);
+ return ToObject<T>(isolate, FromAtomic<T>(result));
+}
+
+
+template <typename T>
+inline Object* DoOr(Isolate* isolate, void* buffer, size_t index,
+ Handle<Object> obj) {
+ typedef typename FromObjectTraits<T>::atomic_type atomic_type;
+ typedef typename FromObjectTraits<T>::convert_type convert_type;
+ atomic_type value = ToAtomic<atomic_type>(FromObject<convert_type>(obj));
+ atomic_type result =
+ OrSeqCst(static_cast<atomic_type*>(buffer) + index, value);
+ return ToObject<T>(isolate, FromAtomic<T>(result));
+}
+
+
+template <typename T>
+inline Object* DoXor(Isolate* isolate, void* buffer, size_t index,
+ Handle<Object> obj) {
+ typedef typename FromObjectTraits<T>::atomic_type atomic_type;
+ typedef typename FromObjectTraits<T>::convert_type convert_type;
+ atomic_type value = ToAtomic<atomic_type>(FromObject<convert_type>(obj));
+ atomic_type result =
+ XorSeqCst(static_cast<atomic_type*>(buffer) + index, value);
+ return ToObject<T>(isolate, FromAtomic<T>(result));
+}
+
+
+template <typename T>
+inline Object* DoExchange(Isolate* isolate, void* buffer, size_t index,
+ Handle<Object> obj) {
+ typedef typename FromObjectTraits<T>::atomic_type atomic_type;
+ typedef typename FromObjectTraits<T>::convert_type convert_type;
+ atomic_type value = ToAtomic<atomic_type>(FromObject<convert_type>(obj));
+ atomic_type result =
+ ExchangeSeqCst(static_cast<atomic_type*>(buffer) + index, value);
+ return ToObject<T>(isolate, FromAtomic<T>(result));
+}
+
+} // anonymous namespace
+
+// Duplicated from objects.h
+// V has parameters (Type, type, TYPE, C type, element_size)
+#define INTEGER_TYPED_ARRAYS(V) \
+ V(Uint8, uint8, UINT8, uint8_t, 1) \
+ V(Int8, int8, INT8, int8_t, 1) \
+ V(Uint16, uint16, UINT16, uint16_t, 2) \
+ V(Int16, int16, INT16, int16_t, 2) \
+ V(Uint32, uint32, UINT32, uint32_t, 4) \
+ V(Int32, int32, INT32, int32_t, 4) \
+ V(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t, 1)
+
+
+RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 4);
+ 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);
+ DCHECK(sta->GetBuffer()->is_shared());
+ DCHECK(index < NumberToSize(isolate, sta->length()));
+
+ void* buffer = sta->GetBuffer()->backing_store();
+
+ switch (sta->type()) {
+#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return DoCompareExchange<ctype>(isolate, buffer, index, oldobj, newobj);
+
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ default:
+ break;
+ }
+
+ UNREACHABLE();
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_AtomicsLoad) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
+ CONVERT_SIZE_ARG_CHECKED(index, 1);
+ DCHECK(sta->GetBuffer()->is_shared());
+ DCHECK(index < NumberToSize(isolate, sta->length()));
+
+ void* buffer = sta->GetBuffer()->backing_store();
+
+ switch (sta->type()) {
+#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return DoLoad<ctype>(isolate, buffer, index);
+
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ default:
+ break;
+ }
+
+ UNREACHABLE();
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_AtomicsStore) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
+ CONVERT_SIZE_ARG_CHECKED(index, 1);
+ CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
+ DCHECK(sta->GetBuffer()->is_shared());
+ DCHECK(index < NumberToSize(isolate, sta->length()));
+
+ void* buffer = sta->GetBuffer()->backing_store();
+
+ switch (sta->type()) {
+#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return DoStore<ctype>(isolate, buffer, index, value);
+
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ default:
+ break;
+ }
+
+ UNREACHABLE();
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_AtomicsAdd) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
+ CONVERT_SIZE_ARG_CHECKED(index, 1);
+ CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
+ DCHECK(sta->GetBuffer()->is_shared());
+ DCHECK(index < NumberToSize(isolate, sta->length()));
+
+ void* buffer = sta->GetBuffer()->backing_store();
+
+ switch (sta->type()) {
+#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return DoAdd<ctype>(isolate, buffer, index, value);
+
+ INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ case kExternalFloat32Array:
+ case kExternalFloat64Array:
+ default:
+ break;
+ }
+
+ UNREACHABLE();
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_AtomicsSub) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
+ CONVERT_SIZE_ARG_CHECKED(index, 1);
+ CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
+ DCHECK(sta->GetBuffer()->is_shared());
+ DCHECK(index < NumberToSize(isolate, sta->length()));
+
+ void* buffer = sta->GetBuffer()->backing_store();
+
+ switch (sta->type()) {
+#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return DoSub<ctype>(isolate, buffer, index, value);
+
+ INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ case kExternalFloat32Array:
+ case kExternalFloat64Array:
+ default:
+ break;
+ }
+
+ UNREACHABLE();
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_AtomicsAnd) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
+ CONVERT_SIZE_ARG_CHECKED(index, 1);
+ CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
+ DCHECK(sta->GetBuffer()->is_shared());
+ DCHECK(index < NumberToSize(isolate, sta->length()));
+
+ void* buffer = sta->GetBuffer()->backing_store();
+
+ switch (sta->type()) {
+#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return DoAnd<ctype>(isolate, buffer, index, value);
+
+ INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ case kExternalFloat32Array:
+ case kExternalFloat64Array:
+ default:
+ break;
+ }
+
+ UNREACHABLE();
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_AtomicsOr) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
+ CONVERT_SIZE_ARG_CHECKED(index, 1);
+ CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
+ DCHECK(sta->GetBuffer()->is_shared());
+ DCHECK(index < NumberToSize(isolate, sta->length()));
+
+ void* buffer = sta->GetBuffer()->backing_store();
+
+ switch (sta->type()) {
+#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return DoOr<ctype>(isolate, buffer, index, value);
+
+ INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ case kExternalFloat32Array:
+ case kExternalFloat64Array:
+ default:
+ break;
+ }
+
+ UNREACHABLE();
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_AtomicsXor) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
+ CONVERT_SIZE_ARG_CHECKED(index, 1);
+ CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
+ DCHECK(sta->GetBuffer()->is_shared());
+ DCHECK(index < NumberToSize(isolate, sta->length()));
+
+ void* buffer = sta->GetBuffer()->backing_store();
+
+ switch (sta->type()) {
+#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return DoXor<ctype>(isolate, buffer, index, value);
+
+ INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ case kExternalFloat32Array:
+ case kExternalFloat64Array:
+ default:
+ break;
+ }
+
+ UNREACHABLE();
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_AtomicsExchange) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
+ CONVERT_SIZE_ARG_CHECKED(index, 1);
+ CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
+ DCHECK(sta->GetBuffer()->is_shared());
+ DCHECK(index < NumberToSize(isolate, sta->length()));
+
+ void* buffer = sta->GetBuffer()->backing_store();
+
+ switch (sta->type()) {
+#define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ return DoExchange<ctype>(isolate, buffer, index, value);
+
+ INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ case kExternalFloat32Array:
+ case kExternalFloat64Array:
+ default:
+ break;
+ }
+
+ UNREACHABLE();
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(Runtime_AtomicsIsLockFree) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_NUMBER_ARG_HANDLE_CHECKED(size, 0);
+ uint32_t usize = NumberToUint32(*size);
+
+ return Runtime::AtomicIsLockFree(usize) ? isolate->heap()->true_value()
+ : isolate->heap()->false_value();
+}
+}
+} // namespace v8::internal
}
+RUNTIME_FUNCTION(Runtime_IsSharedTypedArray) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ return isolate->heap()->ToBoolean(
+ args[0]->IsJSTypedArray() &&
+ JSTypedArray::cast(args[0])->GetBuffer()->is_shared());
+}
+
+
+RUNTIME_FUNCTION(Runtime_IsSharedIntegerTypedArray) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ if (!args[0]->IsJSTypedArray()) {
+ return isolate->heap()->false_value();
+ }
+
+ Handle<JSTypedArray> obj(JSTypedArray::cast(args[0]));
+ return isolate->heap()->ToBoolean(obj->GetBuffer()->is_shared() &&
+ obj->type() != kExternalFloat32Array &&
+ obj->type() != kExternalFloat64Array);
+}
+
+
RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
HandleScope scope(isolate);
DCHECK(args.length() == 4);
RUNTIME_ASSERT(args[index]->IsNumber()); \
double name = args.number_at(index);
+
+// Cast the given argument to a size_t and store its value in a variable with
+// the given name. If the argument is not a size_t call IllegalOperation and
+// return.
+#define CONVERT_SIZE_ARG_CHECKED(name, index) \
+ RUNTIME_ASSERT(args[index]->IsNumber()); \
+ Handle<Object> name##_object = args.at<Object>(index); \
+ size_t name = 0; \
+ RUNTIME_ASSERT(TryNumberToSize(isolate, *name##_object, &name));
+
+
// Call the specified converter on the object *comand store the result in
// a variable of the specified type with the given name. If the
// object is not a Number call IllegalOperation and return.
F(FastOneByteArrayJoin, 2, 1)
+#define FOR_EACH_INTRINSIC_ATOMICS(F) \
+ F(AtomicsCompareExchange, 4, 1) \
+ F(AtomicsLoad, 2, 1) \
+ F(AtomicsStore, 3, 1) \
+ F(AtomicsAdd, 3, 1) \
+ F(AtomicsSub, 3, 1) \
+ F(AtomicsAnd, 3, 1) \
+ F(AtomicsOr, 3, 1) \
+ F(AtomicsXor, 3, 1) \
+ F(AtomicsExchange, 3, 1) \
+ F(AtomicsIsLockFree, 1, 1)
+
+
#define FOR_EACH_INTRINSIC_CLASSES(F) \
F(ThrowNonMethodError, 0, 1) \
F(ThrowUnsupportedSuperError, 0, 1) \
F(TypedArraySetFastCases, 3, 1) \
F(TypedArrayMaxSizeInHeap, 0, 1) \
F(IsTypedArray, 1, 1) \
+ F(IsSharedTypedArray, 1, 1) \
+ F(IsSharedIntegerTypedArray, 1, 1) \
F(DataViewInitialize, 4, 1) \
F(DataViewGetUint8, 3, 1) \
F(DataViewGetInt8, 3, 1) \
#define FOR_EACH_INTRINSIC_RETURN_OBJECT(F) \
FOR_EACH_INTRINSIC_ARRAY(F) \
+ FOR_EACH_INTRINSIC_ATOMICS(F) \
FOR_EACH_INTRINSIC_CLASSES(F) \
FOR_EACH_INTRINSIC_COLLECTIONS(F) \
FOR_EACH_INTRINSIC_COMPILER(F) \
static MaybeHandle<JSArray> GetInternalProperties(Isolate* isolate,
Handle<Object>);
+
+ static bool AtomicIsLockFree(uint32_t size);
};
STATIC_ASSERT(LANGUAGE_END == 3);
class DeclareGlobalsLanguageMode : public BitField<LanguageMode, 2, 2> {};
+//---------------------------------------------------------------------------
+// Inline functions
+
+// Assume that 32-bit architectures don't have 64-bit atomic ops.
+// TODO(binji): can we do better here?
+#if V8_TARGET_ARCH_64_BIT && V8_HOST_ARCH_64_BIT
+
+#define ATOMICS_REQUIRE_LOCK_64_BIT 0
+
+inline bool Runtime::AtomicIsLockFree(uint32_t size) {
+ return size == 1 || size == 2 || size == 4 || size == 8;
+}
+
+#else
+
+#define ATOMICS_REQUIRE_LOCK_64_BIT 1
+
+inline bool Runtime::AtomicIsLockFree(uint32_t size) {
+ return size == 1 || size == 2 || size == 4;
+}
+
+#endif
+
} // namespace internal
} // namespace v8
--- /dev/null
+// 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.
+
+// Flags: --harmony-atomics --harmony-sharedarraybuffer
+
+function Module(stdlib, foreign, heap) {
+ "use asm";
+ var MEM8 = new stdlib.Int8Array(heap);
+ var MEM16 = new stdlib.Int16Array(heap);
+ var MEM32 = new stdlib.Int32Array(heap);
+ var MEMU8 = new stdlib.Uint8Array(heap);
+ var MEMU16 = new stdlib.Uint16Array(heap);
+ var MEMU32 = new stdlib.Uint32Array(heap);
+ var add = stdlib.Atomics.add;
+ var fround = stdlib.Math.fround;
+
+ function addi8(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return add(MEM8, i, x)|0;
+ }
+
+ function addi16(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return add(MEM16, i, x)|0;
+ }
+
+ function addi32(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return add(MEM32, i, x)|0;
+ }
+
+ function addu8(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return add(MEMU8, i, x)>>>0;
+ }
+
+ function addu16(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return add(MEMU16, i, x)>>>0;
+ }
+
+ function addu32(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return add(MEMU32, i, x)>>>0;
+ }
+
+ return {
+ addi8: addi8,
+ addi16: addi16,
+ addi32: addi32,
+ addu8: addu8,
+ addu16: addu16,
+ addu32: addu32,
+ };
+}
+
+var sab = new SharedArrayBuffer(16);
+var m = Module(this, {}, sab);
+
+function clearArray() {
+ var ui8 = new Uint8Array(sab);
+ for (var i = 0; i < sab.byteLength; ++i) {
+ ui8[i] = 0;
+ }
+}
+
+function testElementType(taConstr, f) {
+ clearArray();
+
+ var ta = new taConstr(sab);
+ var name = Object.prototype.toString.call(ta);
+ assertEquals(0, f(0, 10), name);
+ assertEquals(10, ta[0]);
+ assertEquals(10, f(0, 10), name);
+ assertEquals(20, ta[0]);
+ // out of bounds
+ assertEquals(0, f(-1, 0), name);
+ assertEquals(0, f(ta.length, 0), name);
+}
+
+testElementType(Int8Array, m.addi8);
+testElementType(Int16Array, m.addi16);
+testElementType(Int32Array, m.addi32);
+testElementType(Uint8Array, m.addu8);
+testElementType(Uint16Array, m.addu16);
+testElementType(Uint32Array, m.addu32);
--- /dev/null
+// 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.
+
+// Flags: --harmony-atomics --harmony-sharedarraybuffer
+
+function Module(stdlib, foreign, heap) {
+ "use asm";
+ var MEM8 = new stdlib.Int8Array(heap);
+ var MEM16 = new stdlib.Int16Array(heap);
+ var MEM32 = new stdlib.Int32Array(heap);
+ var MEMU8 = new stdlib.Uint8Array(heap);
+ var MEMU16 = new stdlib.Uint16Array(heap);
+ var MEMU32 = new stdlib.Uint32Array(heap);
+ var and = stdlib.Atomics.and;
+ var fround = stdlib.Math.fround;
+
+ function andi8(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return and(MEM8, i, x)|0;
+ }
+
+ function andi16(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return and(MEM16, i, x)|0;
+ }
+
+ function andi32(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return and(MEM32, i, x)|0;
+ }
+
+ function andu8(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return and(MEMU8, i, x)>>>0;
+ }
+
+ function andu16(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return and(MEMU16, i, x)>>>0;
+ }
+
+ function andu32(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return and(MEMU32, i, x)>>>0;
+ }
+
+ return {
+ andi8: andi8,
+ andi16: andi16,
+ andi32: andi32,
+ andu8: andu8,
+ andu16: andu16,
+ andu32: andu32,
+ };
+}
+
+var sab = new SharedArrayBuffer(16);
+var m = Module(this, {}, sab);
+
+function clearArray() {
+ var ui8 = new Uint8Array(sab);
+ for (var i = 0; i < sab.byteLength; ++i) {
+ ui8[i] = 0;
+ }
+}
+
+function testElementType(taConstr, f) {
+ clearArray();
+
+ var ta = new taConstr(sab);
+ var name = Object.prototype.toString.call(ta);
+ ta[0] = 0x7f;
+ assertEquals(0x7f, f(0, 0xf), name);
+ assertEquals(0xf, ta[0]);
+ assertEquals(0xf, f(0, 0x19), name);
+ assertEquals(0x9, ta[0]);
+ // out of bounds
+ assertEquals(0, f(-1, 0), name);
+ assertEquals(0, f(ta.length, 0), name);
+}
+
+testElementType(Int8Array, m.andi8);
+testElementType(Int16Array, m.andi16);
+testElementType(Int32Array, m.andi32);
+testElementType(Uint8Array, m.andu8);
+testElementType(Uint16Array, m.andu16);
+testElementType(Uint32Array, m.andu32);
--- /dev/null
+// 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.
+
+// Flags: --harmony-atomics --harmony-sharedarraybuffer
+
+function Module(stdlib, foreign, heap) {
+ "use asm";
+ var MEM8 = new stdlib.Int8Array(heap);
+ var MEM16 = new stdlib.Int16Array(heap);
+ var MEM32 = new stdlib.Int32Array(heap);
+ var MEMU8 = new stdlib.Uint8Array(heap);
+ var MEMU16 = new stdlib.Uint16Array(heap);
+ var MEMU32 = new stdlib.Uint32Array(heap);
+ var MEMF32 = new stdlib.Float32Array(heap);
+ var MEMF64 = new stdlib.Float64Array(heap);
+ var compareExchange = stdlib.Atomics.compareExchange;
+ var fround = stdlib.Math.fround;
+
+ function compareExchangei8(i, o, n) {
+ i = i | 0;
+ o = o | 0;
+ n = n | 0;
+ return compareExchange(MEM8, i, o, n)|0;
+ }
+
+ function compareExchangei16(i, o, n) {
+ i = i | 0;
+ o = o | 0;
+ n = n | 0;
+ return compareExchange(MEM16, i, o, n)|0;
+ }
+
+ function compareExchangei32(i, o, n) {
+ i = i | 0;
+ o = o | 0;
+ n = n | 0;
+ return compareExchange(MEM32, i, o, n)|0;
+ }
+
+ function compareExchangeu8(i, o, n) {
+ i = i | 0;
+ o = o >>> 0;
+ n = n >>> 0;
+ return compareExchange(MEMU8, i, o, n)>>>0;
+ }
+
+ function compareExchangeu16(i, o, n) {
+ i = i | 0;
+ o = o >>> 0;
+ n = n >>> 0;
+ return compareExchange(MEMU16, i, o, n)>>>0;
+ }
+
+ function compareExchangeu32(i, o, n) {
+ i = i | 0;
+ o = o >>> 0;
+ n = n >>> 0;
+ return compareExchange(MEMU32, i, o, n)>>>0;
+ }
+
+ function compareExchangef32(i, o, n) {
+ i = i | 0;
+ o = fround(o);
+ n = fround(n);
+ return fround(compareExchange(MEMF32, i, o, n));
+ }
+
+ function compareExchangef64(i, o, n) {
+ i = i | 0;
+ o = +o;
+ n = +n;
+ return +compareExchange(MEMF64, i, o, n);
+ }
+
+ return {
+ compareExchangei8: compareExchangei8,
+ compareExchangei16: compareExchangei16,
+ compareExchangei32: compareExchangei32,
+ compareExchangeu8: compareExchangeu8,
+ compareExchangeu16: compareExchangeu16,
+ compareExchangeu32: compareExchangeu32,
+ compareExchangef32: compareExchangef32,
+ compareExchangef64: compareExchangef64
+ };
+}
+
+var sab = new SharedArrayBuffer(16);
+var m = Module(this, {}, sab);
+
+function clearArray() {
+ var ui8 = new Uint8Array(sab);
+ for (var i = 0; i < sab.byteLength; ++i) {
+ ui8[i] = 0;
+ }
+}
+
+function testElementType(taConstr, f, oobValue) {
+ clearArray();
+
+ var ta = new taConstr(sab);
+ var name = Object.prototype.toString.call(ta);
+ assertEquals(0, ta[0]);
+ assertEquals(0, f(0, 0, 50), name);
+ assertEquals(50, ta[0]);
+ // Value is not equal to 0, so compareExchange won't store 100
+ assertEquals(50, f(0, 0, 100), name);
+ assertEquals(50, ta[0]);
+ // out of bounds
+ assertEquals(oobValue, f(-1, 0, 0), name);
+ assertEquals(oobValue, f(ta.length, 0, 0), name);
+}
+
+testElementType(Int8Array, m.compareExchangei8, 0);
+testElementType(Int16Array, m.compareExchangei16, 0);
+testElementType(Int32Array, m.compareExchangei32, 0);
+testElementType(Uint8Array, m.compareExchangeu8, 0);
+testElementType(Uint16Array, m.compareExchangeu16, 0);
+testElementType(Uint32Array, m.compareExchangeu32, 0);
+testElementType(Float32Array, m.compareExchangef32, NaN);
+testElementType(Float64Array, m.compareExchangef64, NaN);
--- /dev/null
+// 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.
+
+// Flags: --harmony-atomics --harmony-sharedarraybuffer
+
+function Module(stdlib, foreign, heap) {
+ "use asm";
+ var MEM8 = new stdlib.Int8Array(heap);
+ var MEM16 = new stdlib.Int16Array(heap);
+ var MEM32 = new stdlib.Int32Array(heap);
+ var MEMU8 = new stdlib.Uint8Array(heap);
+ var MEMU16 = new stdlib.Uint16Array(heap);
+ var MEMU32 = new stdlib.Uint32Array(heap);
+ var exchange = stdlib.Atomics.exchange;
+ var fround = stdlib.Math.fround;
+
+ function exchangei8(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return exchange(MEM8, i, x)|0;
+ }
+
+ function exchangei16(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return exchange(MEM16, i, x)|0;
+ }
+
+ function exchangei32(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return exchange(MEM32, i, x)|0;
+ }
+
+ function exchangeu8(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return exchange(MEMU8, i, x)>>>0;
+ }
+
+ function exchangeu16(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return exchange(MEMU16, i, x)>>>0;
+ }
+
+ function exchangeu32(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return exchange(MEMU32, i, x)>>>0;
+ }
+
+ return {
+ exchangei8: exchangei8,
+ exchangei16: exchangei16,
+ exchangei32: exchangei32,
+ exchangeu8: exchangeu8,
+ exchangeu16: exchangeu16,
+ exchangeu32: exchangeu32,
+ };
+}
+
+var sab = new SharedArrayBuffer(16);
+var m = Module(this, {}, sab);
+
+function clearArray() {
+ var ui8 = new Uint8Array(sab);
+ for (var i = 0; i < sab.byteLength; ++i) {
+ ui8[i] = 0;
+ }
+}
+
+function testElementType(taConstr, f) {
+ clearArray();
+
+ var ta = new taConstr(sab);
+ var name = Object.prototype.toString.call(ta);
+ ta[0] = 0x7f;
+ assertEquals(0x7f, f(0, 0xf), name);
+ assertEquals(0xf, ta[0]);
+ // out of bounds
+ assertEquals(0, f(-1, 0), name);
+ assertEquals(0, f(ta.length, 0), name);
+}
+
+testElementType(Int8Array, m.exchangei8);
+testElementType(Int16Array, m.exchangei16);
+testElementType(Int32Array, m.exchangei32);
+testElementType(Uint8Array, m.exchangeu8);
+testElementType(Uint16Array, m.exchangeu16);
+testElementType(Uint32Array, m.exchangeu32);
--- /dev/null
+// 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.
+
+// Flags: --harmony-atomics --harmony-sharedarraybuffer
+
+function Module(stdlib, foreign, heap) {
+ "use asm";
+ var MEM8 = new stdlib.Int8Array(heap);
+ var MEM16 = new stdlib.Int16Array(heap);
+ var MEM32 = new stdlib.Int32Array(heap);
+ var MEMU8 = new stdlib.Uint8Array(heap);
+ var MEMU16 = new stdlib.Uint16Array(heap);
+ var MEMU32 = new stdlib.Uint32Array(heap);
+ var MEMF32 = new stdlib.Float32Array(heap);
+ var MEMF64 = new stdlib.Float64Array(heap);
+ var load = stdlib.Atomics.load;
+ var fround = stdlib.Math.fround;
+
+ function loadi8(i) {
+ i = i | 0;
+ return load(MEM8, i)|0;
+ }
+
+ function loadi16(i) {
+ i = i | 0;
+ return load(MEM16, i)|0;
+ }
+
+ function loadi32(i) {
+ i = i | 0;
+ return load(MEM32, i)|0;
+ }
+
+ function loadu8(i) {
+ i = i | 0;
+ return load(MEMU8, i)>>>0;
+ }
+
+ function loadu16(i) {
+ i = i | 0;
+ return load(MEMU16, i)>>>0;
+ }
+
+ function loadu32(i) {
+ i = i | 0;
+ return load(MEMU32, i)>>>0;
+ }
+
+ function loadf32(i) {
+ i = i | 0;
+ return fround(load(MEMF32, i));
+ }
+
+ function loadf64(i) {
+ i = i | 0;
+ return +load(MEMF64, i);
+ }
+
+ return {
+ loadi8: loadi8,
+ loadi16: loadi16,
+ loadi32: loadi32,
+ loadu8: loadu8,
+ loadu16: loadu16,
+ loadu32: loadu32,
+ loadf32: loadf32,
+ loadf64: loadf64
+ };
+}
+
+var sab = new SharedArrayBuffer(16);
+var m = Module(this, {}, sab);
+
+function clearArray() {
+ var ui8 = new Uint8Array(sab);
+ for (var i = 0; i < sab.byteLength; ++i) {
+ ui8[i] = 0;
+ }
+}
+
+function testElementType(taConstr, f, oobValue) {
+ clearArray();
+
+ var ta = new taConstr(sab);
+ var name = Object.prototype.toString.call(ta);
+ ta[0] = 10;
+ assertEquals(10, f(0), name);
+ assertEquals(0, f(1), name);
+ // out of bounds
+ assertEquals(oobValue, f(-1), name);
+ assertEquals(oobValue, f(ta.length), name);
+}
+
+testElementType(Int8Array, m.loadi8, 0);
+testElementType(Int16Array, m.loadi16, 0);
+testElementType(Int32Array, m.loadi32, 0);
+testElementType(Uint8Array, m.loadu8, 0);
+testElementType(Uint16Array, m.loadu16, 0);
+testElementType(Uint32Array, m.loadu32, 0);
+testElementType(Float32Array, m.loadf32, NaN);
+testElementType(Float64Array, m.loadf64, NaN);
--- /dev/null
+// 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.
+
+// Flags: --harmony-atomics --harmony-sharedarraybuffer
+
+function Module(stdlib, foreign, heap) {
+ "use asm";
+ var MEM8 = new stdlib.Int8Array(heap);
+ var MEM16 = new stdlib.Int16Array(heap);
+ var MEM32 = new stdlib.Int32Array(heap);
+ var MEMU8 = new stdlib.Uint8Array(heap);
+ var MEMU16 = new stdlib.Uint16Array(heap);
+ var MEMU32 = new stdlib.Uint32Array(heap);
+ var or = stdlib.Atomics.or;
+ var fround = stdlib.Math.fround;
+
+ function ori8(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return or(MEM8, i, x)|0;
+ }
+
+ function ori16(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return or(MEM16, i, x)|0;
+ }
+
+ function ori32(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return or(MEM32, i, x)|0;
+ }
+
+ function oru8(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return or(MEMU8, i, x)>>>0;
+ }
+
+ function oru16(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return or(MEMU16, i, x)>>>0;
+ }
+
+ function oru32(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return or(MEMU32, i, x)>>>0;
+ }
+
+ return {
+ ori8: ori8,
+ ori16: ori16,
+ ori32: ori32,
+ oru8: oru8,
+ oru16: oru16,
+ oru32: oru32,
+ };
+}
+
+var sab = new SharedArrayBuffer(16);
+var m = Module(this, {}, sab);
+
+function clearArray() {
+ var ui8 = new Uint8Array(sab);
+ for (var i = 0; i < sab.byteLength; ++i) {
+ ui8[i] = 0;
+ }
+}
+
+function testElementType(taConstr, f) {
+ clearArray();
+
+ var ta = new taConstr(sab);
+ var name = Object.prototype.toString.call(ta);
+ assertEquals(0, f(0, 0xf), name);
+ assertEquals(0xf, ta[0]);
+ assertEquals(0xf, f(0, 0x11), name);
+ assertEquals(0x1f, ta[0]);
+ // out of bounds
+ assertEquals(0, f(-1, 0), name);
+ assertEquals(0, f(ta.length, 0), name);
+}
+
+testElementType(Int8Array, m.ori8);
+testElementType(Int16Array, m.ori16);
+testElementType(Int32Array, m.ori32);
+testElementType(Uint8Array, m.oru8);
+testElementType(Uint16Array, m.oru16);
+testElementType(Uint32Array, m.oru32);
--- /dev/null
+// 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.
+
+// Flags: --harmony-atomics --harmony-sharedarraybuffer
+
+function Module(stdlib, foreign, heap) {
+ "use asm";
+ var MEM8 = new stdlib.Int8Array(heap);
+ var MEM16 = new stdlib.Int16Array(heap);
+ var MEM32 = new stdlib.Int32Array(heap);
+ var MEMU8 = new stdlib.Uint8Array(heap);
+ var MEMU16 = new stdlib.Uint16Array(heap);
+ var MEMU32 = new stdlib.Uint32Array(heap);
+ var MEMF32 = new stdlib.Float32Array(heap);
+ var MEMF64 = new stdlib.Float64Array(heap);
+ var store = stdlib.Atomics.store;
+ var fround = stdlib.Math.fround;
+
+ function storei8(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return store(MEM8, i, x)|0;
+ }
+
+ function storei16(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return store(MEM16, i, x)|0;
+ }
+
+ function storei32(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return store(MEM32, i, x)|0;
+ }
+
+ function storeu8(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return store(MEMU8, i, x)>>>0;
+ }
+
+ function storeu16(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return store(MEMU16, i, x)>>>0;
+ }
+
+ function storeu32(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return store(MEMU32, i, x)>>>0;
+ }
+
+ function storef32(i, x) {
+ i = i | 0;
+ x = fround(x);
+ return fround(store(MEMF32, i, x));
+ }
+
+ function storef64(i, x) {
+ i = i | 0;
+ x = +x;
+ return +store(MEMF64, i, x);
+ }
+
+ return {
+ storei8: storei8,
+ storei16: storei16,
+ storei32: storei32,
+ storeu8: storeu8,
+ storeu16: storeu16,
+ storeu32: storeu32,
+ storef32: storef32,
+ storef64: storef64
+ };
+}
+
+var sab = new SharedArrayBuffer(16);
+var m = Module(this, {}, sab);
+
+function clearArray() {
+ var ui8 = new Uint8Array(sab);
+ for (var i = 0; i < sab.byteLength; ++i) {
+ ui8[i] = 0;
+ }
+}
+
+function testElementType(taConstr, f, oobValue) {
+ clearArray();
+
+ var ta = new taConstr(sab);
+ var name = Object.prototype.toString.call(ta);
+ assertEquals(10, f(0, 10), name);
+ assertEquals(10, ta[0]);
+ // out of bounds
+ assertEquals(oobValue, f(-1, 0), name);
+ assertEquals(oobValue, f(ta.length, 0), name);
+}
+
+testElementType(Int8Array, m.storei8, 0);
+testElementType(Int16Array, m.storei16, 0);
+testElementType(Int32Array, m.storei32, 0);
+testElementType(Uint8Array, m.storeu8, 0);
+testElementType(Uint16Array, m.storeu16, 0);
+testElementType(Uint32Array, m.storeu32, 0);
+testElementType(Float32Array, m.storef32, NaN);
+testElementType(Float64Array, m.storef64, NaN);
--- /dev/null
+// 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.
+
+// Flags: --harmony-atomics --harmony-sharedarraybuffer
+
+function Module(stdlib, foreign, heap) {
+ "use asm";
+ var MEM8 = new stdlib.Int8Array(heap);
+ var MEM16 = new stdlib.Int16Array(heap);
+ var MEM32 = new stdlib.Int32Array(heap);
+ var MEMU8 = new stdlib.Uint8Array(heap);
+ var MEMU16 = new stdlib.Uint16Array(heap);
+ var MEMU32 = new stdlib.Uint32Array(heap);
+ var sub = stdlib.Atomics.sub;
+ var fround = stdlib.Math.fround;
+
+ function subi8(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return sub(MEM8, i, x)|0;
+ }
+
+ function subi16(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return sub(MEM16, i, x)|0;
+ }
+
+ function subi32(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return sub(MEM32, i, x)|0;
+ }
+
+ function subu8(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return sub(MEMU8, i, x)>>>0;
+ }
+
+ function subu16(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return sub(MEMU16, i, x)>>>0;
+ }
+
+ function subu32(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return sub(MEMU32, i, x)>>>0;
+ }
+
+ return {
+ subi8: subi8,
+ subi16: subi16,
+ subi32: subi32,
+ subu8: subu8,
+ subu16: subu16,
+ subu32: subu32,
+ };
+}
+
+var sab = new SharedArrayBuffer(16);
+var m = Module(this, {}, sab);
+
+function clearArray() {
+ var ui8 = new Uint8Array(sab);
+ for (var i = 0; i < sab.byteLength; ++i) {
+ ui8[i] = 0;
+ }
+}
+
+function testElementType(taConstr, f) {
+ clearArray();
+
+ var ta = new taConstr(sab);
+ var name = Object.prototype.toString.call(ta);
+ ta[0] = 30;
+ assertEquals(30, f(0, 10), name);
+ assertEquals(20, ta[0]);
+ assertEquals(20, f(0, 10), name);
+ assertEquals(10, ta[0]);
+ // out of bounds
+ assertEquals(0, f(-1, 0), name);
+ assertEquals(0, f(ta.length, 0), name);
+}
+
+testElementType(Int8Array, m.subi8);
+testElementType(Int16Array, m.subi16);
+testElementType(Int32Array, m.subi32);
+testElementType(Uint8Array, m.subu8);
+testElementType(Uint16Array, m.subu16);
+testElementType(Uint32Array, m.subu32);
--- /dev/null
+// 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.
+
+// Flags: --harmony-atomics --harmony-sharedarraybuffer
+
+function Module(stdlib, foreign, heap) {
+ "use asm";
+ var MEM8 = new stdlib.Int8Array(heap);
+ var MEM16 = new stdlib.Int16Array(heap);
+ var MEM32 = new stdlib.Int32Array(heap);
+ var MEMU8 = new stdlib.Uint8Array(heap);
+ var MEMU16 = new stdlib.Uint16Array(heap);
+ var MEMU32 = new stdlib.Uint32Array(heap);
+ var xor = stdlib.Atomics.xor;
+ var fround = stdlib.Math.fround;
+
+ function xori8(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return xor(MEM8, i, x)|0;
+ }
+
+ function xori16(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return xor(MEM16, i, x)|0;
+ }
+
+ function xori32(i, x) {
+ i = i | 0;
+ x = x | 0;
+ return xor(MEM32, i, x)|0;
+ }
+
+ function xoru8(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return xor(MEMU8, i, x)>>>0;
+ }
+
+ function xoru16(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return xor(MEMU16, i, x)>>>0;
+ }
+
+ function xoru32(i, x) {
+ i = i | 0;
+ x = x >>> 0;
+ return xor(MEMU32, i, x)>>>0;
+ }
+
+ return {
+ xori8: xori8,
+ xori16: xori16,
+ xori32: xori32,
+ xoru8: xoru8,
+ xoru16: xoru16,
+ xoru32: xoru32,
+ };
+}
+
+var sab = new SharedArrayBuffer(16);
+var m = Module(this, {}, sab);
+
+function clearArray() {
+ var ui8 = new Uint8Array(sab);
+ for (var i = 0; i < sab.byteLength; ++i) {
+ ui8[i] = 0;
+ }
+}
+
+function testElementType(taConstr, f) {
+ clearArray();
+
+ var ta = new taConstr(sab);
+ var name = Object.prototype.toString.call(ta);
+ assertEquals(0, f(0, 0xf), name);
+ assertEquals(0xf, ta[0]);
+ assertEquals(0xf, f(0, 0x11), name);
+ assertEquals(0x1e, ta[0]);
+ // out of bounds
+ assertEquals(0, f(-1, 0), name);
+ assertEquals(0, f(ta.length, 0), name);
+}
+
+testElementType(Int8Array, m.xori8);
+testElementType(Int16Array, m.xori16);
+testElementType(Int32Array, m.xori32);
+testElementType(Uint8Array, m.xoru8);
+testElementType(Uint16Array, m.xoru16);
+testElementType(Uint32Array, m.xoru32);
--- /dev/null
+// Copyright 2014 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-atomics --harmony-sharedarraybuffer
+//
+
+var IntegerTypedArrayConstructors = [
+ {constr: Int8Array, min: -128, max: 127},
+ {constr: Int16Array, min: -32768, max: 32767},
+ {constr: Int32Array, min: -0x80000000, max: 0x7fffffff},
+ {constr: Uint8Array, min: 0, max: 255},
+// TODO(binji): support?
+// {constr: Uint8ClampedArray, min: 0, max: 255},
+ {constr: Uint16Array, min: 0, max: 65535},
+ {constr: Uint32Array, min: 0, max: 0xffffffff},
+];
+
+var TypedArrayConstructors = IntegerTypedArrayConstructors.concat([
+ {constr: Float32Array},
+ {constr: Float64Array},
+]);
+
+(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);
+
+ // Atomic ops required shared typed arrays
+ [undefined, 1, 'hi', 3.4, ab, u32a, sab].forEach(function(o) {
+ assertThrows(function() { Atomics.compareExchange(o, 0, 0, 0); },
+ TypeError);
+ assertThrows(function() { Atomics.load(o, 0); }, TypeError);
+ assertThrows(function() { Atomics.store(o, 0, 0); }, TypeError);
+ assertThrows(function() { Atomics.add(o, 0, 0); }, TypeError);
+ assertThrows(function() { Atomics.sub(o, 0, 0); }, TypeError);
+ assertThrows(function() { Atomics.and(o, 0, 0); }, TypeError);
+ assertThrows(function() { Atomics.or(o, 0, 0); }, TypeError);
+ assertThrows(function() { Atomics.xor(o, 0, 0); }, TypeError);
+ assertThrows(function() { Atomics.exchange(o, 0, 0); }, TypeError);
+ });
+
+ // Arithmetic atomic ops require integer shared arrays
+ [sab, sf32a, sf64a].forEach(function(o) {
+ assertThrows(function() { Atomics.add(o, 0, 0); }, TypeError);
+ assertThrows(function() { Atomics.sub(o, 0, 0); }, TypeError);
+ assertThrows(function() { Atomics.and(o, 0, 0); }, TypeError);
+ assertThrows(function() { Atomics.or(o, 0, 0); }, TypeError);
+ assertThrows(function() { Atomics.xor(o, 0, 0); }, TypeError);
+ assertThrows(function() { Atomics.exchange(o, 0, 0); }, TypeError);
+ });
+})();
+
+function testAtomicOp(op, ia, index, expectedIndex, name) {
+ for (var i = 0; i < ia.length; ++i)
+ ia[i] = 22;
+
+ ia[expectedIndex] = 0;
+ assertEquals(0, op(ia, index, 0, 0), name);
+ assertEquals(0, ia[expectedIndex], name);
+
+ for (var i = 0; i < ia.length; ++i) {
+ if (i == expectedIndex) continue;
+ assertEquals(22, ia[i], name);
+ }
+}
+
+(function TestBadIndex() {
+ var sab = new SharedArrayBuffer(8);
+ var si32a = new Int32Array(sab);
+
+ // Non-integer indexes are converted to an integer first, so they should all
+ // operate on index 0.
+ [undefined, null, false, 'hi', {}].forEach(function(i) {
+ var name = String(i);
+
+ testAtomicOp(Atomics.compareExchange, si32a, i, 0, name);
+ testAtomicOp(Atomics.load, si32a, i, 0, name);
+ testAtomicOp(Atomics.store, si32a, i, 0, name);
+ testAtomicOp(Atomics.add, si32a, i, 0, name);
+ testAtomicOp(Atomics.sub, si32a, i, 0, name);
+ testAtomicOp(Atomics.and, si32a, i, 0, name);
+ testAtomicOp(Atomics.or, si32a, i, 0, name);
+ testAtomicOp(Atomics.xor, si32a, i, 0, name);
+ testAtomicOp(Atomics.exchange, si32a, i, 0, name);
+ });
+
+ // Out-of-bounds indexes should return undefined.
+ // TODO(binji): Should these throw RangeError instead?
+ [-1, 2, 100].forEach(function(i) {
+ var name = String(i);
+ assertEquals(undefined, Atomics.compareExchange(si32a, i, 0, 0), name);
+ assertEquals(undefined, Atomics.load(si32a, i), name);
+ assertEquals(undefined, Atomics.store(si32a, i, 0), name);
+ assertEquals(undefined, Atomics.add(si32a, i, 0), name);
+ assertEquals(undefined, Atomics.sub(si32a, i, 0), name);
+ assertEquals(undefined, Atomics.and(si32a, i, 0), name);
+ assertEquals(undefined, Atomics.or(si32a, i, 0), name);
+ assertEquals(undefined, Atomics.xor(si32a, i, 0), name);
+ assertEquals(undefined, Atomics.exchange(si32a, i, 0), name);
+ });
+})();
+
+(function TestGoodIndex() {
+ var sab = new SharedArrayBuffer(64);
+ var si32a = new Int32Array(sab);
+
+ var valueOf = {valueOf: function(){ return 3;}};
+ var toString = {toString: function(){ return '3';}};
+
+ [3, 3.5, '3', '3.5', valueOf, toString].forEach(function(i) {
+ var name = String(i);
+
+ testAtomicOp(Atomics.compareExchange, si32a, i, 3, name);
+ testAtomicOp(Atomics.load, si32a, i, 3, name);
+ testAtomicOp(Atomics.store, si32a, i, 3, name);
+ testAtomicOp(Atomics.add, si32a, i, 3, name);
+ testAtomicOp(Atomics.sub, si32a, i, 3, name);
+ testAtomicOp(Atomics.and, si32a, i, 3, name);
+ testAtomicOp(Atomics.or, si32a, i, 3, name);
+ testAtomicOp(Atomics.xor, si32a, i, 3, name);
+ testAtomicOp(Atomics.exchange, si32a, i, 3, name);
+ });
+})();
+
+(function TestCompareExchange() {
+ TypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ for (var i = 0; i < 10; ++i) {
+ // sta[i] == 0, CAS will store
+ assertEquals(0, Atomics.compareExchange(sta, i, 0, 50), name);
+ assertEquals(50, sta[i], name);
+
+ // sta[i] == 50, CAS will not store
+ assertEquals(50, Atomics.compareExchange(sta, i, 0, 100), name);
+ assertEquals(50, sta[i], name);
+ }
+ });
+
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ var range = t.max - t.min + 1;
+ var add;
+ var oldVal, oldValWrapped;
+ var newVal, newValWrapped;
+
+ for (add = -range; add <= range; add += range) {
+ sta[0] = oldVal = 0;
+ newVal = t.max + add + 1;
+ newValWrapped = t.min;
+ assertEquals(oldVal,
+ Atomics.compareExchange(sta, 0, oldVal, newVal), name);
+ assertEquals(newValWrapped, sta[0], name);
+
+ oldVal = newVal;
+ oldValWrapped = newValWrapped;
+ newVal = t.min + add - 1;
+ newValWrapped = t.max;
+ assertEquals(oldValWrapped,
+ Atomics.compareExchange(sta, 0, oldVal, newVal), name);
+ assertEquals(newValWrapped, sta[0], name);
+ }
+ });
+
+ // * Exact float values should be OK
+ // * Infinity, -Infinity should be OK (has exact representation)
+ // * NaN is not OK, it has many representations, cannot ensure successful CAS
+ // because it does a bitwise compare
+ [1.5, 4.25, -1e8, -Infinity, Infinity].forEach(function(v) {
+ var sab = new SharedArrayBuffer(10 * Float32Array.BYTES_PER_ELEMENT);
+ var sf32a = new Float32Array(sab);
+ sf32a[0] = 0;
+ assertEquals(0, Atomics.compareExchange(sf32a, 0, 0, v));
+ assertEquals(v, sf32a[0]);
+ assertEquals(v, Atomics.compareExchange(sf32a, 0, v, 0));
+ assertEquals(0, sf32a[0]);
+
+ var sab2 = new SharedArrayBuffer(10 * Float64Array.BYTES_PER_ELEMENT);
+ var sf64a = new Float64Array(sab2);
+ sf64a[0] = 0;
+ assertEquals(0, Atomics.compareExchange(sf64a, 0, 0, v));
+ assertEquals(v, sf64a[0]);
+ assertEquals(v, Atomics.compareExchange(sf64a, 0, v, 0));
+ assertEquals(0, sf64a[0]);
+ });
+})();
+
+(function TestLoad() {
+ TypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ for (var i = 0; i < 10; ++i) {
+ sta[i] = 0;
+ assertEquals(0, Atomics.load(sta, i), name);
+ sta[i] = 50;
+ assertEquals(50, Atomics.load(sta, i), name);
+ }
+ });
+})();
+
+(function TestStore() {
+ TypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ for (var i = 0; i < 10; ++i) {
+ assertEquals(50, Atomics.store(sta, i, 50), name);
+ assertEquals(50, sta[i], name);
+
+ assertEquals(100, Atomics.store(sta, i, 100), name);
+ assertEquals(100, sta[i], name);
+ }
+ });
+
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ var range = t.max - t.min + 1;
+ var add;
+ var val, valWrapped;
+
+ for (add = -range; add <= range; add += range) {
+ sta[0] = 0;
+ val = t.max + add + 1;
+ valWrapped = t.min;
+ assertEquals(val, Atomics.store(sta, 0, val), name);
+ assertEquals(valWrapped, sta[0], name);
+
+ val = t.min + add - 1;
+ valWrapped = t.max;
+ assertEquals(val, Atomics.store(sta, 0, val), name);
+ assertEquals(valWrapped, sta[0], name);
+ }
+ });
+
+ [1.5, 4.25, -1e8, -Infinity, Infinity, NaN].forEach(function(v) {
+ var sab = new SharedArrayBuffer(10 * Float32Array.BYTES_PER_ELEMENT);
+ var sf32a = new Float32Array(sab);
+ sf32a[0] = 0;
+ assertEquals(v, Atomics.store(sf32a, 0, v));
+ assertEquals(v, sf32a[0]);
+
+ var sab2 = new SharedArrayBuffer(10 * Float64Array.BYTES_PER_ELEMENT);
+ var sf64a = new Float64Array(sab2);
+ sf64a[0] = 0;
+ assertEquals(v, Atomics.store(sf64a, 0, v));
+ assertEquals(v, sf64a[0]);
+ });
+})();
+
+(function TestAdd() {
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ for (var i = 0; i < 10; ++i) {
+ assertEquals(0, Atomics.add(sta, i, 50), name);
+ assertEquals(50, sta[i], name);
+
+ assertEquals(50, Atomics.add(sta, i, 70), name);
+ assertEquals(120, sta[i], name);
+ }
+ });
+
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ var range = t.max - t.min + 1;
+ var add;
+
+ for (add = -range; add <= range; add += range) {
+ sta[0] = t.max;
+ valWrapped = t.min;
+ assertEquals(t.max, Atomics.add(sta, 0, add + 1), name);
+ assertEquals(t.min, sta[0], name);
+
+ assertEquals(t.min, Atomics.add(sta, 0, add - 1), name);
+ assertEquals(t.max, sta[0], name);
+ }
+ });
+})();
+
+(function TestSub() {
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ for (var i = 0; i < 10; ++i) {
+ sta[i] = 120;
+ assertEquals(120, Atomics.sub(sta, i, 50), name);
+ assertEquals(70, sta[i], name);
+
+ assertEquals(70, Atomics.sub(sta, i, 70), name);
+ assertEquals(0, sta[i], name);
+ }
+ });
+
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ var range = t.max - t.min + 1;
+ var add;
+
+ for (add = -range; add <= range; add += range) {
+ sta[0] = t.max;
+ valWrapped = t.min;
+ assertEquals(t.max, Atomics.sub(sta, 0, add - 1), name);
+ assertEquals(t.min, sta[0], name);
+
+ assertEquals(t.min, Atomics.sub(sta, 0, add + 1), name);
+ assertEquals(t.max, sta[0], name);
+ }
+ });
+})();
+
+(function TestAnd() {
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ for (var i = 0; i < 10; ++i) {
+ sta[i] = 0x3f;
+ assertEquals(0x3f, Atomics.and(sta, i, 0x30), name);
+ assertEquals(0x30, sta[i], name);
+
+ assertEquals(0x30, Atomics.and(sta, i, 0x20), name);
+ assertEquals(0x20, sta[i], name);
+ }
+ });
+
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ var range = t.max - t.min + 1;
+ var add;
+
+ // There's no way to wrap results with logical operators, just test that
+ // using an out-of-range value is properly masked.
+ for (add = -range; add <= range; add += range) {
+ sta[0] = 0xf;
+ assertEquals(0xf, Atomics.and(sta, 0, 0x3 + add), name);
+ assertEquals(0x3, sta[0], name);
+ }
+ });
+})();
+
+(function TestOr() {
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ for (var i = 0; i < 10; ++i) {
+ sta[i] = 0x30;
+ assertEquals(0x30, Atomics.or(sta, i, 0x1c), name);
+ assertEquals(0x3c, sta[i], name);
+
+ assertEquals(0x3c, Atomics.or(sta, i, 0x09), name);
+ assertEquals(0x3d, sta[i], name);
+ }
+ });
+
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ var range = t.max - t.min + 1;
+ var add;
+
+ // There's no way to wrap results with logical operators, just test that
+ // using an out-of-range value is properly masked.
+ for (add = -range; add <= range; add += range) {
+ sta[0] = 0x12;
+ assertEquals(0x12, Atomics.or(sta, 0, 0x22 + add), name);
+ assertEquals(0x32, sta[0], name);
+ }
+ });
+})();
+
+(function TestXor() {
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ for (var i = 0; i < 10; ++i) {
+ sta[i] = 0x30;
+ assertEquals(0x30, Atomics.xor(sta, i, 0x1c), name);
+ assertEquals(0x2c, sta[i], name);
+
+ assertEquals(0x2c, Atomics.xor(sta, i, 0x09), name);
+ assertEquals(0x25, sta[i], name);
+ }
+ });
+
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ var range = t.max - t.min + 1;
+ var add;
+
+ // There's no way to wrap results with logical operators, just test that
+ // using an out-of-range value is properly masked.
+ for (add = -range; add <= range; add += range) {
+ sta[0] = 0x12;
+ assertEquals(0x12, Atomics.xor(sta, 0, 0x22 + add), name);
+ assertEquals(0x30, sta[0], name);
+ }
+ });
+})();
+
+(function TestExchange() {
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ for (var i = 0; i < 10; ++i) {
+ sta[i] = 0x30;
+ assertEquals(0x30, Atomics.exchange(sta, i, 0x1c), name);
+ assertEquals(0x1c, sta[i], name);
+
+ assertEquals(0x1c, Atomics.exchange(sta, i, 0x09), name);
+ assertEquals(0x09, sta[i], name);
+ }
+ });
+
+ IntegerTypedArrayConstructors.forEach(function(t) {
+ var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
+ var sta = new t.constr(sab);
+ var name = Object.prototype.toString.call(sta);
+ var range = t.max - t.min + 1;
+ var add;
+
+ // There's no way to wrap results with logical operators, just test that
+ // using an out-of-range value is properly masked.
+ for (add = -range; add <= range; add += range) {
+ sta[0] = 0x12;
+ assertEquals(0x12, Atomics.exchange(sta, 0, 0x22 + add), name);
+ assertEquals(0x22, sta[0], name);
+ }
+ });
+})();
+
+(function TestIsLockFree() {
+ // For all platforms we support, 1, 2 and 4 bytes should be lock-free.
+ assertEquals(true, Atomics.isLockFree(1));
+ assertEquals(true, Atomics.isLockFree(2));
+ assertEquals(true, Atomics.isLockFree(4));
+
+ // Sizes that aren't equal to a typedarray BYTES_PER_ELEMENT always return
+ // false.
+ var validSizes = {};
+ TypedArrayConstructors.forEach(function(t) {
+ validSizes[t.constr.BYTES_PER_ELEMENT] = true;
+ });
+
+ for (var i = 0; i < 1000; ++i) {
+ if (!validSizes[i]) {
+ assertEquals(false, Atomics.isLockFree(i));
+ }
+ }
+})();
'../../src/runtime-profiler.cc',
'../../src/runtime-profiler.h',
'../../src/runtime/runtime-array.cc',
+ '../../src/runtime/runtime-atomics.cc',
'../../src/runtime/runtime-classes.cc',
'../../src/runtime/runtime-collections.cc',
'../../src/runtime/runtime-compiler.cc',
'../../src/messages.h',
'../../src/proxy.js',
'../../src/generator.js',
+ '../../src/harmony-atomics.js',
'../../src/harmony-array.js',
'../../src/harmony-array-includes.js',
'../../src/harmony-tostring.js',