Implement Atomics API
authorbinji <binji@chromium.org>
Wed, 3 Jun 2015 17:58:29 +0000 (10:58 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 3 Jun 2015 17:58:42 +0000 (17:58 +0000)
This is behind the flag "--harmony-atomics", and it only works on
SharedArrayBuffers. This implementation only includes the runtime functions.
The TurboFan implementation will be next.

The draft spec for Atomics can be found here:
https://docs.google.com/document/d/1NDGA_gZJ7M7w1Bh8S0AoDyEqwDdRh4uSoTPSNn77PFk

BUG=
LOG=n

Review URL: https://codereview.chromium.org/1162503002

Cr-Commit-Position: refs/heads/master@{#28796}

21 files changed:
BUILD.gn
src/bootstrapper.cc
src/flag-definitions.h
src/harmony-atomics.js [new file with mode: 0644]
src/messages.h
src/objects.h
src/runtime/runtime-atomics.cc [new file with mode: 0644]
src/runtime/runtime-typedarray.cc
src/runtime/runtime-utils.h
src/runtime/runtime.h
test/mjsunit/asm/atomics-add.js [new file with mode: 0644]
test/mjsunit/asm/atomics-and.js [new file with mode: 0644]
test/mjsunit/asm/atomics-compareexchange.js [new file with mode: 0644]
test/mjsunit/asm/atomics-exchange.js [new file with mode: 0644]
test/mjsunit/asm/atomics-load.js [new file with mode: 0644]
test/mjsunit/asm/atomics-or.js [new file with mode: 0644]
test/mjsunit/asm/atomics-store.js [new file with mode: 0644]
test/mjsunit/asm/atomics-sub.js [new file with mode: 0644]
test/mjsunit/asm/atomics-xor.js [new file with mode: 0644]
test/mjsunit/harmony/atomics.js [new file with mode: 0644]
tools/gyp/v8.gyp

index 8d56eac..cffd8f0 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -269,6 +269,7 @@ action("js2c_experimental") {
     "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",
@@ -998,6 +999,7 @@ source_set("v8_base") {
     "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",
index 925316e..ae55f2f 100644 (file)
@@ -230,6 +230,7 @@ class Genesis BASE_EMBEDDED {
   bool InstallExperimentalNatives();
   bool InstallExtraNatives();
   void InstallBuiltinFunctionIds();
+  void InstallExperimentalBuiltinFunctionIds();
   void InstallJSFunctionResultCaches();
   void InitializeNormalizedMapCaches();
 
@@ -1766,6 +1767,7 @@ EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_destructuring)
 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() {
@@ -1777,6 +1779,7 @@ void Genesis::InstallNativeFunctions_harmony_proxies() {
   }
 }
 
+
 #undef INSTALL_NATIVE
 
 #define EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(id) \
@@ -1797,6 +1800,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_spreadcalls)
 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());
@@ -2441,6 +2445,8 @@ bool Genesis::InstallExperimentalNatives() {
   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++) {
@@ -2463,6 +2469,7 @@ bool Genesis::InstallExperimentalNatives() {
   CallUtilsFunction(isolate(), "PostExperimentals");
 
   InstallExperimentalNativeFunctions();
+  InstallExperimentalBuiltinFunctionIds();
   return true;
 }
 
@@ -2488,6 +2495,11 @@ static void InstallBuiltinFunctionId(Handle<JSObject> holder,
 }
 
 
+#define INSTALL_BUILTIN_ID(holder_expr, fun_name, name) \
+  { #holder_expr, #fun_name, k##name }                  \
+  ,
+
+
 void Genesis::InstallBuiltinFunctionIds() {
   HandleScope scope(isolate());
   struct BuiltinFunctionIds {
@@ -2496,12 +2508,8 @@ void Genesis::InstallBuiltinFunctionIds() {
     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 =
@@ -2511,6 +2519,29 @@ void Genesis::InstallBuiltinFunctionIds() {
 }
 
 
+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) \
index 3ea476a..d9b264d 100644 (file)
@@ -193,7 +193,8 @@ DEFINE_IMPLICATION(es_staging, harmony)
   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)                               \
diff --git a/src/harmony-atomics.js b/src/harmony-atomics.js
new file mode 100644 (file)
index 0000000..aa81822
--- /dev/null
@@ -0,0 +1,143 @@
+// 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,
+]);
+
+})
index 005b060..985e794 100644 (file)
@@ -161,6 +161,8 @@ class CallSite {
   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: %")                      \
index 4f78eb1..e5f8bcf 100644 (file)
@@ -6866,11 +6866,16 @@ class Script: public Struct {
   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.
diff --git a/src/runtime/runtime-atomics.cc b/src/runtime/runtime-atomics.cc
new file mode 100644 (file)
index 0000000..5a93909
--- /dev/null
@@ -0,0 +1,715 @@
+// 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
index da8c982..217d739 100644 (file)
@@ -476,6 +476,29 @@ RUNTIME_FUNCTION(Runtime_IsTypedArray) {
 }
 
 
+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);
index 3fe3297..4b072b1 100644 (file)
@@ -55,6 +55,17 @@ namespace internal {
   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.
index 0868bc6..76c5288 100644 (file)
@@ -53,6 +53,19 @@ namespace internal {
   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)         \
@@ -655,6 +668,8 @@ namespace internal {
   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)                   \
@@ -687,6 +702,7 @@ namespace internal {
 
 #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)            \
@@ -874,6 +890,8 @@ class Runtime : public AllStatic {
 
   static MaybeHandle<JSArray> GetInternalProperties(Isolate* isolate,
                                                     Handle<Object>);
+
+  static bool AtomicIsLockFree(uint32_t size);
 };
 
 
@@ -890,6 +908,29 @@ class DeclareGlobalsNativeFlag : public BitField<bool, 1, 1> {};
 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
 
diff --git a/test/mjsunit/asm/atomics-add.js b/test/mjsunit/asm/atomics-add.js
new file mode 100644 (file)
index 0000000..69400c8
--- /dev/null
@@ -0,0 +1,93 @@
+// 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);
diff --git a/test/mjsunit/asm/atomics-and.js b/test/mjsunit/asm/atomics-and.js
new file mode 100644 (file)
index 0000000..e60f1f6
--- /dev/null
@@ -0,0 +1,94 @@
+// 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);
diff --git a/test/mjsunit/asm/atomics-compareexchange.js b/test/mjsunit/asm/atomics-compareexchange.js
new file mode 100644 (file)
index 0000000..208a060
--- /dev/null
@@ -0,0 +1,121 @@
+// 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);
diff --git a/test/mjsunit/asm/atomics-exchange.js b/test/mjsunit/asm/atomics-exchange.js
new file mode 100644 (file)
index 0000000..bb70322
--- /dev/null
@@ -0,0 +1,92 @@
+// 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);
diff --git a/test/mjsunit/asm/atomics-load.js b/test/mjsunit/asm/atomics-load.js
new file mode 100644 (file)
index 0000000..769fb40
--- /dev/null
@@ -0,0 +1,102 @@
+// 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);
diff --git a/test/mjsunit/asm/atomics-or.js b/test/mjsunit/asm/atomics-or.js
new file mode 100644 (file)
index 0000000..df87d24
--- /dev/null
@@ -0,0 +1,93 @@
+// 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);
diff --git a/test/mjsunit/asm/atomics-store.js b/test/mjsunit/asm/atomics-store.js
new file mode 100644 (file)
index 0000000..1f7a5f9
--- /dev/null
@@ -0,0 +1,109 @@
+// 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);
diff --git a/test/mjsunit/asm/atomics-sub.js b/test/mjsunit/asm/atomics-sub.js
new file mode 100644 (file)
index 0000000..f9e56ff
--- /dev/null
@@ -0,0 +1,94 @@
+// 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);
diff --git a/test/mjsunit/asm/atomics-xor.js b/test/mjsunit/asm/atomics-xor.js
new file mode 100644 (file)
index 0000000..893ea01
--- /dev/null
@@ -0,0 +1,93 @@
+// 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);
diff --git a/test/mjsunit/harmony/atomics.js b/test/mjsunit/harmony/atomics.js
new file mode 100644 (file)
index 0000000..2027252
--- /dev/null
@@ -0,0 +1,472 @@
+// 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));
+    }
+  }
+})();
index 59f7ca1..5510dad 100644 (file)
         '../../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',