Backed out 2 changesets (bug 1394420) for failing testAtomicOperations.cpp, ESling and jit failures CLOSED TREE
authorCiure Andrei <aciure@mozilla.com>
Mon, 21 Jan 2019 14:26:34 +0200
changeset 514683 c311812c530c03588f7ac2fac4fd9f6c38103529
parent 514682 8c452bdd54f5d7b91322422c7955066ae7019f32
child 514709 48810cb8ba3fb643308bbf2c5400e1b42042ca45
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1394420
milestone66.0a1
backs outb2ffeeac7326d673ff09474ce3007e84687c5a62
2f5be1913934665cf692d3e43cadbc36f5448643
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 2 changesets (bug 1394420) for failing testAtomicOperations.cpp, ESling and jit failures CLOSED TREE Backed out changeset b2ffeeac7326 (bug 1394420) Backed out changeset 2f5be1913934 (bug 1394420)
js/src/jit-test/tests/atomics/memcpy-fidelity.js
js/src/jit/AtomicOperations.h
js/src/jit/MacroAssembler.h
js/src/jit/arm/AtomicOperations-arm.h
js/src/jit/arm/MacroAssembler-arm.cpp
js/src/jit/arm64/AtomicOperations-arm64-gcc.h
js/src/jit/arm64/AtomicOperations-arm64-msvc.h
js/src/jit/arm64/MacroAssembler-arm64.cpp
js/src/jit/mips-shared/AtomicOperations-mips-shared.h
js/src/jit/moz.build
js/src/jit/none/AtomicOperations-feeling-lucky.h
js/src/jit/shared/AtomicOperations-feeling-lucky-gcc.h
js/src/jit/shared/AtomicOperations-feeling-lucky-msvc.h
js/src/jit/shared/AtomicOperations-feeling-lucky.h
js/src/jit/shared/AtomicOperations-shared-jit.cpp
js/src/jit/shared/AtomicOperations-shared-jit.h
js/src/jit/x64/MacroAssembler-x64.cpp
js/src/jit/x86-shared/Assembler-x86-shared.h
js/src/jit/x86-shared/AtomicOperations-x86-shared-gcc.h
js/src/jit/x86-shared/AtomicOperations-x86-shared-msvc.h
js/src/vm/Initialization.cpp
deleted file mode 100644
--- a/js/src/jit-test/tests/atomics/memcpy-fidelity.js
+++ /dev/null
@@ -1,181 +0,0 @@
-// In order not to run afoul of C++ UB we have our own non-C++ definitions of
-// operations (they are actually jitted) that can operate racily on shared
-// memory, see jit/shared/AtomicOperations-shared-jit.cpp.
-//
-// Operations on fixed-width 1, 2, 4, and 8 byte data are adequately tested
-// elsewhere.  Here we specifically test our safe-when-racy replacements of
-// memcpy and memmove.
-//
-// There are two primitives in the engine, memcpy_down and memcpy_up.  These are
-// equivalent except when data overlap, in which case memcpy_down handles
-// overlapping copies that move from higher to lower addresses and memcpy_up
-// handles ditto from lower to higher.  memcpy uses memcpy_down always while
-// memmove selects the one to use dynamically based on its arguments.
-
-// Basic memcpy algorithm to be tested:
-//
-// - if src and target have the same alignment
-//   - byte copy up to word alignment
-//   - block copy as much as possible
-//   - word copy as much as possible
-//   - byte copy any tail
-// - else if on a platform that can deal with unaligned access
-//   (ie, x86, ARM64, and ARM if the proper flag is set)
-//   - block copy as much as possible
-//   - word copy as much as possible
-//   - byte copy any tail
-// - else // on a platform that can't deal with unaligned access
-//   (ie ARM without the flag or x86 DEBUG builds with the
-//   JS_NO_UNALIGNED_MEMCPY env var)
-//   - block copy with byte copies
-//   - word copy with byte copies
-//   - byte copy any tail
-
-var target_buf = new SharedArrayBuffer(1024);
-var src_buf = new SharedArrayBuffer(1024);
-
-///////////////////////////////////////////////////////////////////////////
-//
-// Different src and target buffer, this is memcpy "move down".  The same
-// code is used in the engine for overlapping buffers when target addresses
-// are lower than source addresses.
-
-fill(src_buf);
-
-// Basic 1K perfectly aligned copy, copies blocks only.
-{
-    let target = new Uint8Array(target_buf);
-    let src = new Uint8Array(src_buf);
-    clear(target_buf);
-    target.set(src);
-    check(target_buf, 0, 1024, 0);
-}
-
-// Buffers are equally aligned but not on a word boundary and not ending on a
-// word boundary either, so this will copy first some bytes, then some blocks,
-// then some words, and then some bytes.
-{
-    let fill = 0x79;
-    clear(target_buf, fill);
-    let target = new Uint8Array(target_buf, 1, 1022);
-    let src = new Uint8Array(src_buf, 1, 1022);
-    target.set(src);
-    check_fill(target_buf, 0, 1, fill);
-    check(target_buf, 1, 1023, 1);
-    check_fill(target_buf, 1023, 1024, fill);
-}
-
-// Buffers are unequally aligned, we'll copy bytes only on some platforms and
-// unaligned blocks/words on others.
-{
-    clear(target_buf);
-    let target = new Uint8Array(target_buf, 0, 1023);
-    let src = new Uint8Array(src_buf, 1);
-    target.set(src);
-    check(target_buf, 0, 1023, 1);
-    check_zero(target_buf, 1023, 1024);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// Overlapping src and target buffer and the target addresses are always
-// higher than the source addresses, this is memcpy "move up"
-
-// Buffers are equally aligned but not on a word boundary and not ending on a
-// word boundary either, so this will copy first some bytes, then some blocks,
-// then some words, and then some bytes.
-{
-    fill(target_buf);
-    let target = new Uint8Array(target_buf, 9, 999);
-    let src = new Uint8Array(target_buf, 1, 999);
-    target.set(src);
-    check(target_buf, 9, 1008, 1);
-    check(target_buf, 1008, 1024, 1008 & 255);
-}
-
-// Buffers are unequally aligned, we'll copy bytes only on some platforms and
-// unaligned blocks/words on others.
-{
-    fill(target_buf);
-    let target = new Uint8Array(target_buf, 2, 1022);
-    let src = new Uint8Array(target_buf, 1, 1022);
-    target.set(src);
-    check(target_buf, 2, 1024, 1);
-}
-
-///////////////////////////////////////////////////////////////////////////
-//
-// Copy 0 to 127 bytes from and to a variety of addresses to check that we
-// handle limits properly in these edge cases.
-
-// Too slow in debug-noopt builds but we don't want to flag the test as slow,
-// since that means it'll never be run.
-
-if (this.getBuildConfiguration && !getBuildConfiguration().debug)
-{
-    let t = new Uint8Array(target_buf);
-    for (let my_src_buf of [src_buf, target_buf]) {
-        for (let size=0; size < 127; size++) {
-            for (let src_offs=0; src_offs < 8; src_offs++) {
-                for (let target_offs=0; target_offs < 8; target_offs++) {
-                    clear(target_buf, Math.random()*255);
-                    let target = new Uint8Array(target_buf, target_offs, size);
-
-                    // Zero is boring
-                    let bias = (Math.random() * 100 % 12) | 0;
-
-                    // Note src may overlap target partially
-                    let src = new Uint8Array(my_src_buf, src_offs, size);
-                    for ( let i=0; i < size; i++ )
-                        src[i] = i+bias;
-
-                    // We expect these values to be unchanged by the copy
-                    let below = target_offs > 0 ? t[target_offs - 1] : 0;
-                    let above = t[target_offs + size];
-
-                    // Copy
-                    target.set(src);
-
-                    // Verify
-                    check(target_buf, target_offs, target_offs + size, bias);
-                    if (target_offs > 0)
-                        assertEq(t[target_offs-1], below);
-                    assertEq(t[target_offs+size], above);
-                }
-            }
-        }
-    }
-}
-
-
-// Utilities
-
-function clear(buf, fill) {
-    let a = new Uint8Array(buf);
-    for ( let i=0; i < a.length; i++ )
-        a[i] = fill;
-}
-
-function fill(buf) {
-    let a = new Uint8Array(buf);
-    for ( let i=0; i < a.length; i++ )
-        a[i] = i & 255
-}
-
-function check(buf, from, to, startingWith) {
-    let a = new Uint8Array(buf);
-    for ( let i=from; i < to; i++ ) {
-        assertEq(a[i], startingWith);
-        startingWith = (startingWith + 1) & 255;
-    }
-}
-
-function check_zero(buf, from, to) {
-    check_fill(buf, from, to, 0);
-}
-
-function check_fill(buf, from, to, fill) {
-    let a = new Uint8Array(buf);
-    for ( let i=from; i < to; i++ )
-        assertEq(a[i], fill);
-}
--- a/js/src/jit/AtomicOperations.h
+++ b/js/src/jit/AtomicOperations.h
@@ -142,23 +142,16 @@ class AtomicOperations {
   static inline void memcpySafeWhenRacy(void* dest, const void* src,
                                         size_t nbytes);
 
   // Replacement for memmove().  No access-atomicity guarantees.
   static inline void memmoveSafeWhenRacy(void* dest, const void* src,
                                          size_t nbytes);
 
  public:
-  // On some platforms we generate code for the atomics at run-time; that
-  // happens here.
-  static bool Initialize();
-
-  // Deallocate the code segment for generated atomics functions.
-  static void ShutDown();
-
   // Test lock-freedom for any int32 value.  This implements the
   // Atomics::isLockFree() operation in the ECMAScript Shared Memory and
   // Atomics specification, as follows:
   //
   // 4-byte accesses are always lock free (in the spec).
   // 1- and 2-byte accesses are always lock free (in SpiderMonkey).
   //
   // Lock-freedom for 8 bytes is determined by the platform's isLockfree8().
@@ -274,16 +267,34 @@ class AtomicOperations {
     memcpySafeWhenRacy(dest, src, nelem * sizeof(T));
   }
 
   template <typename T>
   static void podMoveSafeWhenRacy(SharedMem<T*> dest, SharedMem<T*> src,
                                   size_t nelem) {
     memmoveSafeWhenRacy(dest, src, nelem * sizeof(T));
   }
+
+#ifdef DEBUG
+  // Constraints that must hold for atomic operations on all tier-1 platforms:
+  //
+  // - atomic cells can be 1, 2, 4, or 8 bytes
+  // - all atomic operations are lock-free, including 8-byte operations
+  // - atomic operations can only be performed on naturally aligned cells
+  //
+  // (Tier-2 and tier-3 platforms need not support 8-byte atomics, and if they
+  // do, they need not be lock-free.)
+
+  template <typename T>
+  static bool tier1Constraints(const T* addr) {
+    static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
+    return (sizeof(T) < 8 || (hasAtomic8() && isLockfree8())) &&
+           !(uintptr_t(addr) & (sizeof(T) - 1));
+  }
+#endif
 };
 
 inline bool AtomicOperations::isLockfreeJS(int32_t size) {
   // Keep this in sync with visitAtomicIsLockFree() in jit/CodeGenerator.cpp.
 
   switch (size) {
     case 1:
       return true;
@@ -317,17 +328,17 @@ inline bool AtomicOperations::isLockfree
 // (and if the problem isn't just that the compiler uses a different name for a
 // known architecture), you have basically three options:
 //
 //  - find an already-supported compiler for the platform and use that instead
 //
 //  - write your own support code for the platform+compiler and create a new
 //    case below
 //
-//  - include jit/shared/AtomicOperations-feeling-lucky.h in a case for the
+//  - include jit/none/AtomicOperations-feeling-lucky.h in a case for the
 //    platform below, if you have a gcc-compatible compiler and truly feel
 //    lucky.  You may have to add a little code to that file, too.
 //
 // Simulators are confusing.  These atomic primitives must be compatible with
 // the code that the JIT emits, but of course for an ARM simulator running on
 // x86 the primitives here will be for x86, not for ARM, while the JIT emits ARM
 // code.  Our ARM simulator solves that the easy way: by using these primitives
 // to implement its atomic operations.  For other simulators there may need to
@@ -335,45 +346,59 @@ inline bool AtomicOperations::isLockfree
 // example, for our ARM64 simulator the primitives could in principle
 // participate in the memory exclusivity monitors implemented by the simulator.
 // Such a solution is likely to be difficult.
 
 #if defined(JS_SIMULATOR_MIPS32)
 #  if defined(__clang__) || defined(__GNUC__)
 #    include "jit/mips-shared/AtomicOperations-mips-shared.h"
 #  else
-#    error "AtomicOperations on MIPS-32 for unknown compiler"
+#    error "No AtomicOperations support for this platform+compiler combination"
 #  endif
 #elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \
     defined(_M_IX86)
-#  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
-#    include "jit/shared/AtomicOperations-shared-jit.h"
+#  if defined(__clang__) || defined(__GNUC__)
+#    include "jit/x86-shared/AtomicOperations-x86-shared-gcc.h"
+#  elif defined(_MSC_VER)
+#    include "jit/x86-shared/AtomicOperations-x86-shared-msvc.h"
 #  else
-#    include "jit/shared/AtomicOperations-feeling-lucky.h"
+#    error "No AtomicOperations support for this platform+compiler combination"
 #  endif
 #elif defined(__arm__)
-#  if defined(JS_CODEGEN_ARM)
-#    include "jit/shared/AtomicOperations-shared-jit.h"
+#  if defined(__clang__) || defined(__GNUC__)
+#    include "jit/arm/AtomicOperations-arm.h"
 #  else
-#    include "jit/shared/AtomicOperations-feeling-lucky.h"
+#    error "No AtomicOperations support for this platform+compiler combination"
 #  endif
 #elif defined(__aarch64__) || defined(_M_ARM64)
-#  if defined(JS_CODEGEN_ARM64)
-#    include "jit/shared/AtomicOperations-shared-jit.h"
+#  if defined(__clang__) || defined(__GNUC__)
+#    include "jit/arm64/AtomicOperations-arm64-gcc.h"
+#  elif defined(_MSC_VER)
+#    include "jit/arm64/AtomicOperations-arm64-msvc.h"
 #  else
-#    include "jit/shared/AtomicOperations-feeling-lucky.h"
+#    error "No AtomicOperations support for this platform+compiler combination"
 #  endif
 #elif defined(__mips__)
 #  if defined(__clang__) || defined(__GNUC__)
 #    include "jit/mips-shared/AtomicOperations-mips-shared.h"
 #  else
-#    error "AtomicOperations on MIPS for an unknown compiler"
+#    error "No AtomicOperations support for this platform+compiler combination"
 #  endif
-#elif defined(__ppc__) || defined(__PPC__) || defined(__sparc__) ||     \
-    defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \
-    defined(__PPC64LE__) || defined(__alpha__) || defined(__hppa__) ||  \
-    defined(__sh__) || defined(__s390__) || defined(__s390x__)
-#  include "jit/shared/AtomicOperations-feeling-lucky.h"
+#elif defined(__ppc__) || defined(__PPC__)
+#  include "jit/none/AtomicOperations-feeling-lucky.h"
+#elif defined(__sparc__)
+#  include "jit/none/AtomicOperations-feeling-lucky.h"
+#elif defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \
+    defined(__PPC64LE__)
+#  include "jit/none/AtomicOperations-feeling-lucky.h"
+#elif defined(__alpha__)
+#  include "jit/none/AtomicOperations-feeling-lucky.h"
+#elif defined(__hppa__)
+#  include "jit/none/AtomicOperations-feeling-lucky.h"
+#elif defined(__sh__)
+#  include "jit/none/AtomicOperations-feeling-lucky.h"
+#elif defined(__s390__) || defined(__s390x__)
+#  include "jit/none/AtomicOperations-feeling-lucky.h"
 #else
 #  error "No AtomicOperations support provided for this platform"
 #endif
 
 #endif  // jit_AtomicOperations_h
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -972,23 +972,23 @@ class MacroAssembler : public MacroAssem
   inline void maxFloat32(FloatRegister other, FloatRegister srcDest,
                          bool handleNaN) PER_SHARED_ARCH;
   inline void maxDouble(FloatRegister other, FloatRegister srcDest,
                         bool handleNaN) PER_SHARED_ARCH;
 
   // ===============================================================
   // Shift functions
 
-  // For shift-by-register there may be platform-specific variations, for
-  // example, x86 will perform the shift mod 32 but ARM will perform the shift
-  // mod 256.
+  // For shift-by-register there may be platform-specific
+  // variations, for example, x86 will perform the shift mod 32 but
+  // ARM will perform the shift mod 256.
   //
-  // For shift-by-immediate the platform assembler may restrict the immediate,
-  // for example, the ARM assembler requires the count for 32-bit shifts to be
-  // in the range [0,31].
+  // For shift-by-immediate the platform assembler may restrict the
+  // immediate, for example, the ARM assembler requires the count
+  // for 32-bit shifts to be in the range [0,31].
 
   inline void lshift32(Imm32 shift, Register srcDest) PER_SHARED_ARCH;
   inline void rshift32(Imm32 shift, Register srcDest) PER_SHARED_ARCH;
   inline void rshift32Arithmetic(Imm32 shift, Register srcDest) PER_SHARED_ARCH;
 
   inline void lshiftPtr(Imm32 imm, Register dest) PER_ARCH;
   inline void rshiftPtr(Imm32 imm, Register dest) PER_ARCH;
   inline void rshiftPtr(Imm32 imm, Register src, Register dest)
@@ -1942,24 +1942,16 @@ class MacroAssembler : public MacroAssem
       DEFINED_ON(mips_shared);
 
   void compareExchange(Scalar::Type type, const Synchronization& sync,
                        const BaseIndex& mem, Register expected,
                        Register replacement, Register valueTemp,
                        Register offsetTemp, Register maskTemp, Register output)
       DEFINED_ON(mips_shared);
 
-  // x64: `output` must be rax.
-  // ARM: Registers must be distinct; `replacement` and `output` must be
-  // (even,odd) pairs.
-
-  void compareExchange64(const Synchronization& sync, const Address& mem,
-                         Register64 expected, Register64 replacement,
-                         Register64 output) DEFINED_ON(arm, arm64, x64);
-
   // Exchange with memory.  Return the value initially in memory.
   // MIPS: `valueTemp`, `offsetTemp` and `maskTemp` must be defined for 8-bit
   // and 16-bit wide operations.
 
   void atomicExchange(Scalar::Type type, const Synchronization& sync,
                       const Address& mem, Register value, Register output)
       DEFINED_ON(arm, arm64, x86_shared);
 
@@ -1972,20 +1964,16 @@ class MacroAssembler : public MacroAssem
                       Register offsetTemp, Register maskTemp, Register output)
       DEFINED_ON(mips_shared);
 
   void atomicExchange(Scalar::Type type, const Synchronization& sync,
                       const BaseIndex& mem, Register value, Register valueTemp,
                       Register offsetTemp, Register maskTemp, Register output)
       DEFINED_ON(mips_shared);
 
-  void atomicExchange64(const Synchronization& sync, const Address& mem,
-                        Register64 value, Register64 output)
-      DEFINED_ON(arm64, x64);
-
   // Read-modify-write with memory.  Return the value in memory before the
   // operation.
   //
   // x86-shared:
   //   For 8-bit operations, `value` and `output` must have a byte subregister.
   //   For Add and Sub, `temp` must be invalid.
   //   For And, Or, and Xor, `output` must be eax and `temp` must have a byte
   //   subregister.
@@ -2017,25 +2005,16 @@ class MacroAssembler : public MacroAssem
                      Register valueTemp, Register offsetTemp, Register maskTemp,
                      Register output) DEFINED_ON(mips_shared);
 
   void atomicFetchOp(Scalar::Type type, const Synchronization& sync,
                      AtomicOp op, Register value, const BaseIndex& mem,
                      Register valueTemp, Register offsetTemp, Register maskTemp,
                      Register output) DEFINED_ON(mips_shared);
 
-  // x64:
-  //   For Add and Sub, `temp` must be invalid.
-  //   For And, Or, and Xor, `output` must be eax and `temp` must have a byte
-  //   subregister.
-
-  void atomicFetchOp64(const Synchronization& sync, AtomicOp op,
-                       Register64 value, const Address& mem, Register64 temp,
-                       Register64 output) DEFINED_ON(arm64, x64);
-
   // ========================================================================
   // Wasm atomic operations.
   //
   // Constraints, when omitted, are exactly as for the primitive operations
   // above.
 
   void wasmCompareExchange(const wasm::MemoryAccessDesc& access,
                            const Address& mem, Register expected,
@@ -2149,53 +2128,48 @@ class MacroAssembler : public MacroAssem
   void wasmAtomicLoad64(const wasm::MemoryAccessDesc& access,
                         const Address& mem, Register64 temp, Register64 output)
       DEFINED_ON(arm, mips32, x86);
 
   void wasmAtomicLoad64(const wasm::MemoryAccessDesc& access,
                         const BaseIndex& mem, Register64 temp,
                         Register64 output) DEFINED_ON(arm, mips32, x86);
 
-  // x86: `expected` must be the same as `output`, and must be edx:eax.
-  // x86: `replacement` must be ecx:ebx.
+  // x86: `expected` must be the same as `output`, and must be edx:eax
+  // x86: `replacement` must be ecx:ebx
   // x64: `output` must be rax.
   // ARM: Registers must be distinct; `replacement` and `output` must be
-  // (even,odd) pairs.
-  // ARM64: The base register in `mem` must not overlap `output`.
-  // MIPS: Registers must be distinct.
+  // (even,odd) pairs. MIPS: Registers must be distinct.
 
   void wasmCompareExchange64(const wasm::MemoryAccessDesc& access,
                              const Address& mem, Register64 expected,
                              Register64 replacement,
                              Register64 output) PER_ARCH;
 
   void wasmCompareExchange64(const wasm::MemoryAccessDesc& access,
                              const BaseIndex& mem, Register64 expected,
                              Register64 replacement,
                              Register64 output) PER_ARCH;
 
   // x86: `value` must be ecx:ebx; `output` must be edx:eax.
   // ARM: Registers must be distinct; `value` and `output` must be (even,odd)
-  // pairs.
-  // MIPS: Registers must be distinct.
+  // pairs. MIPS: Registers must be distinct.
 
   void wasmAtomicExchange64(const wasm::MemoryAccessDesc& access,
                             const Address& mem, Register64 value,
                             Register64 output) PER_ARCH;
 
   void wasmAtomicExchange64(const wasm::MemoryAccessDesc& access,
                             const BaseIndex& mem, Register64 value,
                             Register64 output) PER_ARCH;
 
   // x86: `output` must be edx:eax, `temp` must be ecx:ebx.
   // x64: For And, Or, and Xor `output` must be rax.
   // ARM: Registers must be distinct; `temp` and `output` must be (even,odd)
-  // pairs.
-  // MIPS: Registers must be distinct.
-  // MIPS32: `temp` should be invalid.
+  // pairs. MIPS: Registers must be distinct. MIPS32: `temp` should be invalid.
 
   void wasmAtomicFetchOp64(const wasm::MemoryAccessDesc& access, AtomicOp op,
                            Register64 value, const Address& mem,
                            Register64 temp, Register64 output)
       DEFINED_ON(arm, arm64, mips32, mips64, x64);
 
   void wasmAtomicFetchOp64(const wasm::MemoryAccessDesc& access, AtomicOp op,
                            Register64 value, const BaseIndex& mem,
new file mode 100644
--- /dev/null
+++ b/js/src/jit/arm/AtomicOperations-arm.h
@@ -0,0 +1,221 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_arm_AtomicOperations_arm_h
+#define jit_arm_AtomicOperations_arm_h
+
+#include "jit/arm/Architecture-arm.h"
+
+#include "vm/ArrayBufferObject.h"
+
+// For documentation, see jit/AtomicOperations.h
+
+// NOTE, this file is *not* used with the ARM simulator, only when compiling for
+// actual ARM hardware.  The simulators get the files that are appropriate for
+// the hardware the simulator is running on.  See the comments before the
+// #include nest at the bottom of jit/AtomicOperations.h for more information.
+
+// Firefox requires gcc > 4.8, so we will always have the __atomic intrinsics
+// added for use in C++11 <atomic>.
+//
+// Note that using these intrinsics for most operations is not correct: the code
+// has undefined behavior.  The gcc documentation states that the compiler
+// assumes the code is race free.  This supposedly means C++ will allow some
+// instruction reorderings (effectively those allowed by TSO) even for seq_cst
+// ordered operations, but these reorderings are not allowed by JS.  To do
+// better we will end up with inline assembler or JIT-generated code.
+
+#if !defined(__clang__) && !defined(__GNUC__)
+#  error "This file only for gcc-compatible compilers"
+#endif
+
+inline bool js::jit::AtomicOperations::hasAtomic8() {
+  // This guard is really only for tier-2 and tier-3 systems: LDREXD and
+  // STREXD have been available since ARMv6K, and only ARMv7 and later are
+  // tier-1.
+  return HasLDSTREXBHD();
+}
+
+inline bool js::jit::AtomicOperations::isLockfree8() {
+  // The JIT and the C++ compiler must agree on whether to use atomics
+  // for 64-bit accesses.  There are two ways to do this: either the
+  // JIT defers to the C++ compiler (so if the C++ code is compiled
+  // for ARMv6, say, and __atomic_always_lock_free(8) is false, then the
+  // JIT ignores the fact that the program is running on ARMv7 or newer);
+  // or the C++ code in this file calls out to run-time generated code
+  // to do whatever the JIT does.
+  //
+  // For now, make the JIT defer to the C++ compiler when we know what
+  // the C++ compiler will do, otherwise assume a lock is needed.
+  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int8_t), 0));
+  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int16_t), 0));
+  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int32_t), 0));
+
+  return hasAtomic8() && __atomic_always_lock_free(sizeof(int64_t), 0);
+}
+
+inline void js::jit::AtomicOperations::fenceSeqCst() {
+  __atomic_thread_fence(__ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::loadSeqCst(T* addr) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  T v;
+  __atomic_load(addr, &v, __ATOMIC_SEQ_CST);
+  return v;
+}
+
+template <typename T>
+inline void js::jit::AtomicOperations::storeSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  __atomic_store(addr, &val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::exchangeSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  T v;
+  __atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
+  return v;
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::compareExchangeSeqCst(T* addr, T oldval,
+                                                          T newval) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  __atomic_compare_exchange(addr, &oldval, &newval, false, __ATOMIC_SEQ_CST,
+                            __ATOMIC_SEQ_CST);
+  return oldval;
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchAddSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_add(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchSubSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_sub(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchAndSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_and(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchOrSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_or(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchXorSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_xor(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  T v;
+  __atomic_load(addr, &v, __ATOMIC_RELAXED);
+  return v;
+}
+
+namespace js {
+namespace jit {
+
+#define GCC_RACYLOADOP(T)                                         \
+  template <>                                                     \
+  inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) { \
+    return *addr;                                                 \
+  }
+
+// On 32-bit platforms, loadSafeWhenRacy need not be access-atomic for 64-bit
+// data, so just use regular accesses instead of the expensive __atomic_load
+// solution which must use LDREXD/CLREX.
+#ifndef JS_64BIT
+GCC_RACYLOADOP(int64_t)
+GCC_RACYLOADOP(uint64_t)
+#endif
+
+// Float and double accesses are not access-atomic.
+GCC_RACYLOADOP(float)
+GCC_RACYLOADOP(double)
+
+// Clang requires a specialization for uint8_clamped.
+template <>
+inline uint8_clamped js::jit::AtomicOperations::loadSafeWhenRacy(
+    uint8_clamped* addr) {
+  uint8_t v;
+  __atomic_load(&addr->val, &v, __ATOMIC_RELAXED);
+  return uint8_clamped(v);
+}
+
+#undef GCC_RACYLOADOP
+
+}  // namespace jit
+}  // namespace js
+
+template <typename T>
+inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  __atomic_store(addr, &val, __ATOMIC_RELAXED);
+}
+
+namespace js {
+namespace jit {
+
+#define GCC_RACYSTOREOP(T)                                                   \
+  template <>                                                                \
+  inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) { \
+    *addr = val;                                                             \
+  }
+
+// On 32-bit platforms, storeSafeWhenRacy need not be access-atomic for 64-bit
+// data, so just use regular accesses instead of the expensive __atomic_store
+// solution which must use LDREXD/STREXD.
+#ifndef JS_64BIT
+GCC_RACYSTOREOP(int64_t)
+GCC_RACYSTOREOP(uint64_t)
+#endif
+
+// Float and double accesses are not access-atomic.
+GCC_RACYSTOREOP(float)
+GCC_RACYSTOREOP(double)
+
+// Clang requires a specialization for uint8_clamped.
+template <>
+inline void js::jit::AtomicOperations::storeSafeWhenRacy(uint8_clamped* addr,
+                                                         uint8_clamped val) {
+  __atomic_store(&addr->val, &val.val, __ATOMIC_RELAXED);
+}
+
+#undef GCC_RACYSTOREOP
+
+}  // namespace jit
+}  // namespace js
+
+inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
+                                                          const void* src,
+                                                          size_t nbytes) {
+  MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest + nbytes));
+  MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src + nbytes));
+  memcpy(dest, src, nbytes);
+}
+
+inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
+                                                           const void* src,
+                                                           size_t nbytes) {
+  memmove(dest, src, nbytes);
+}
+
+#endif  // jit_arm_AtomicOperations_arm_h
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -5285,80 +5285,69 @@ void MacroAssembler::wasmAtomicLoad64(co
 
 void MacroAssembler::wasmAtomicLoad64(const wasm::MemoryAccessDesc& access,
                                       const BaseIndex& mem, Register64 temp,
                                       Register64 output) {
   WasmAtomicLoad64(*this, access, mem, temp, output);
 }
 
 template <typename T>
-static void CompareExchange64(MacroAssembler& masm,
-                              const wasm::MemoryAccessDesc* access,
-                              const Synchronization& sync, const T& mem,
-                              Register64 expect, Register64 replace,
-                              Register64 output) {
+static void WasmCompareExchange64(MacroAssembler& masm,
+                                  const wasm::MemoryAccessDesc& access,
+                                  const T& mem, Register64 expect,
+                                  Register64 replace, Register64 output) {
   MOZ_ASSERT(expect != replace && replace != output && output != expect);
 
   MOZ_ASSERT((replace.low.code() & 1) == 0);
   MOZ_ASSERT(replace.low.code() + 1 == replace.high.code());
 
   MOZ_ASSERT((output.low.code() & 1) == 0);
   MOZ_ASSERT(output.low.code() + 1 == output.high.code());
 
   Label again;
   Label done;
 
   SecondScratchRegisterScope scratch2(masm);
   Register ptr = ComputePointerForAtomic(masm, mem, scratch2);
 
-  masm.memoryBarrierBefore(sync);
+  masm.memoryBarrierBefore(access.sync());
 
   masm.bind(&again);
   BufferOffset load = masm.as_ldrexd(output.low, output.high, ptr);
-  if (access) {
-    masm.append(*access, load.getOffset());
-  }
+  masm.append(access, load.getOffset());
 
   masm.as_cmp(output.low, O2Reg(expect.low));
   masm.as_cmp(output.high, O2Reg(expect.high), MacroAssembler::Equal);
   masm.as_b(&done, MacroAssembler::NotEqual);
 
   ScratchRegisterScope scratch(masm);
 
   // Rd (temp) must differ from the two other arguments to strex.
   masm.as_strexd(scratch, replace.low, replace.high, ptr);
   masm.as_cmp(scratch, Imm8(1));
   masm.as_b(&again, MacroAssembler::Equal);
   masm.bind(&done);
 
-  masm.memoryBarrierAfter(sync);
+  masm.memoryBarrierAfter(access.sync());
 }
 
 void MacroAssembler::wasmCompareExchange64(const wasm::MemoryAccessDesc& access,
                                            const Address& mem,
                                            Register64 expect,
                                            Register64 replace,
                                            Register64 output) {
-  CompareExchange64(*this, &access, access.sync(), mem, expect, replace,
-                    output);
+  WasmCompareExchange64(*this, access, mem, expect, replace, output);
 }
 
 void MacroAssembler::wasmCompareExchange64(const wasm::MemoryAccessDesc& access,
                                            const BaseIndex& mem,
                                            Register64 expect,
                                            Register64 replace,
                                            Register64 output) {
-  CompareExchange64(*this, &access, access.sync(), mem, expect, replace,
-                    output);
-}
-
-void MacroAssembler::compareExchange64(const Synchronization& sync,
-                                       const Address& mem, Register64 expect,
-                                       Register64 replace, Register64 output) {
-  CompareExchange64(*this, nullptr, sync, mem, expect, replace, output);
+  WasmCompareExchange64(*this, access, mem, expect, replace, output);
 }
 
 template <typename T>
 static void WasmAtomicExchange64(MacroAssembler& masm,
                                  const wasm::MemoryAccessDesc& access,
                                  const T& mem, Register64 value,
                                  Register64 output) {
   MOZ_ASSERT(output != value);
new file mode 100644
--- /dev/null
+++ b/js/src/jit/arm64/AtomicOperations-arm64-gcc.h
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* For documentation, see jit/AtomicOperations.h */
+
+#ifndef jit_arm64_AtomicOperations_arm64_h
+#define jit_arm64_AtomicOperations_arm64_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Types.h"
+
+#include "vm/ArrayBufferObject.h"
+
+#if !defined(__clang__) && !defined(__GNUC__)
+#  error "This file only for gcc-compatible compilers"
+#endif
+
+inline bool js::jit::AtomicOperations::hasAtomic8() { return true; }
+
+inline bool js::jit::AtomicOperations::isLockfree8() {
+  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int8_t), 0));
+  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int16_t), 0));
+  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int32_t), 0));
+  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int64_t), 0));
+  return true;
+}
+
+inline void js::jit::AtomicOperations::fenceSeqCst() {
+  __atomic_thread_fence(__ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::loadSeqCst(T* addr) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  T v;
+  __atomic_load(addr, &v, __ATOMIC_SEQ_CST);
+  return v;
+}
+
+template <typename T>
+inline void js::jit::AtomicOperations::storeSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  __atomic_store(addr, &val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::exchangeSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  T v;
+  __atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
+  return v;
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::compareExchangeSeqCst(T* addr, T oldval,
+                                                          T newval) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  __atomic_compare_exchange(addr, &oldval, &newval, false, __ATOMIC_SEQ_CST,
+                            __ATOMIC_SEQ_CST);
+  return oldval;
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchAddSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_add(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchSubSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_sub(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchAndSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_and(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchOrSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_or(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchXorSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_xor(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  T v;
+  __atomic_load(addr, &v, __ATOMIC_RELAXED);
+  return v;
+}
+
+namespace js {
+namespace jit {
+
+// Clang requires a specialization for uint8_clamped.
+template <>
+inline js::uint8_clamped js::jit::AtomicOperations::loadSafeWhenRacy(
+    js::uint8_clamped* addr) {
+  uint8_t v;
+  __atomic_load(&addr->val, &v, __ATOMIC_RELAXED);
+  return js::uint8_clamped(v);
+}
+
+}  // namespace jit
+}  // namespace js
+
+template <typename T>
+inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  __atomic_store(addr, &val, __ATOMIC_RELAXED);
+}
+
+namespace js {
+namespace jit {
+
+// Clang requires a specialization for uint8_clamped.
+template <>
+inline void js::jit::AtomicOperations::storeSafeWhenRacy(
+    js::uint8_clamped* addr, js::uint8_clamped val) {
+  __atomic_store(&addr->val, &val.val, __ATOMIC_RELAXED);
+}
+
+}  // namespace jit
+}  // namespace js
+
+inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
+                                                          const void* src,
+                                                          size_t nbytes) {
+  MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest + nbytes));
+  MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src + nbytes));
+  memcpy(dest, src, nbytes);
+}
+
+inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
+                                                           const void* src,
+                                                           size_t nbytes) {
+  memmove(dest, src, nbytes);
+}
+
+#endif  // jit_arm64_AtomicOperations_arm64_h
new file mode 100644
--- /dev/null
+++ b/js/src/jit/arm64/AtomicOperations-arm64-msvc.h
@@ -0,0 +1,369 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_shared_AtomicOperations_x86_shared_msvc_h
+#define jit_shared_AtomicOperations_x86_shared_msvc_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Types.h"
+
+#if !defined(_MSC_VER)
+#  error "This file only for Microsoft Visual C++"
+#endif
+
+// For overall documentation, see jit/AtomicOperations.h/
+//
+// For general comments on lock-freedom, access-atomicity, and related matters
+// on x86 and x64, notably for justification of the implementations of the
+// 64-bit primitives on 32-bit systems, see the comment block in
+// AtomicOperations-x86-shared-gcc.h.
+
+// Below, _ReadWriteBarrier is a compiler directive, preventing reordering of
+// instructions and reuse of memory values across it in the compiler, but having
+// no impact on what the CPU does.
+
+// Note, here we use MSVC intrinsics directly.  But MSVC supports a slightly
+// higher level of function which uses the intrinsic when possible (8, 16, and
+// 32-bit operations, and 64-bit operations on 64-bit systems) and otherwise
+// falls back on CMPXCHG8B for 64-bit operations on 32-bit systems.  We could be
+// using those functions in many cases here (though not all).  I have not done
+// so because (a) I don't yet know how far back those functions are supported
+// and (b) I expect we'll end up dropping into assembler here eventually so as
+// to guarantee that the C++ compiler won't optimize the code.
+
+// Note, _InterlockedCompareExchange takes the *new* value as the second
+// argument and the *comparand* (expected old value) as the third argument.
+
+inline bool js::jit::AtomicOperations::hasAtomic8() { return true; }
+
+inline bool js::jit::AtomicOperations::isLockfree8() {
+  // The MSDN docs suggest very strongly that if code is compiled for Pentium
+  // or better the 64-bit primitives will be lock-free, see eg the "Remarks"
+  // secion of the page for _InterlockedCompareExchange64, currently here:
+  // https://msdn.microsoft.com/en-us/library/ttk2z1ws%28v=vs.85%29.aspx
+  //
+  // But I've found no way to assert that at compile time or run time, there
+  // appears to be no WinAPI is_lock_free() test.
+
+  return true;
+}
+
+inline void js::jit::AtomicOperations::fenceSeqCst() {
+  _ReadWriteBarrier();
+  // MemoryBarrier is defined in winnt.h, which we don't want to include here.
+  // This expression is the expansion of MemoryBarrier.
+  __dmb(_ARM64_BARRIER_SY);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::loadSeqCst(T* addr) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  _ReadWriteBarrier();
+  T v = *addr;
+  _ReadWriteBarrier();
+  return v;
+}
+
+#ifdef _M_IX86
+namespace js {
+namespace jit {
+
+#  define MSC_LOADOP(T)                                                       \
+    template <>                                                               \
+    inline T AtomicOperations::loadSeqCst(T* addr) {                          \
+      MOZ_ASSERT(tier1Constraints(addr));                                     \
+      _ReadWriteBarrier();                                                    \
+      return (T)_InterlockedCompareExchange64((__int64 volatile*)addr, 0, 0); \
+    }
+
+MSC_LOADOP(int64_t)
+MSC_LOADOP(uint64_t)
+
+#  undef MSC_LOADOP
+
+}  // namespace jit
+}  // namespace js
+#endif  // _M_IX86
+
+template <typename T>
+inline void js::jit::AtomicOperations::storeSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  _ReadWriteBarrier();
+  *addr = val;
+  fenceSeqCst();
+}
+
+#ifdef _M_IX86
+namespace js {
+namespace jit {
+
+#  define MSC_STOREOP(T)                                             \
+    template <>                                                      \
+    inline void AtomicOperations::storeSeqCst(T* addr, T val) {      \
+      MOZ_ASSERT(tier1Constraints(addr));                            \
+      _ReadWriteBarrier();                                           \
+      T oldval = *addr;                                              \
+      for (;;) {                                                     \
+        T nextval = (T)_InterlockedCompareExchange64(                \
+            (__int64 volatile*)addr, (__int64)val, (__int64)oldval); \
+        if (nextval == oldval) break;                                \
+        oldval = nextval;                                            \
+      }                                                              \
+      _ReadWriteBarrier();                                           \
+    }
+
+MSC_STOREOP(int64_t)
+MSC_STOREOP(uint64_t)
+
+#  undef MSC_STOREOP
+
+}  // namespace jit
+}  // namespace js
+#endif  // _M_IX86
+
+#define MSC_EXCHANGEOP(T, U, xchgop)                          \
+  template <>                                                 \
+  inline T AtomicOperations::exchangeSeqCst(T* addr, T val) { \
+    MOZ_ASSERT(tier1Constraints(addr));                       \
+    return (T)xchgop((U volatile*)addr, (U)val);              \
+  }
+
+#ifdef _M_IX86
+#  define MSC_EXCHANGEOP_CAS(T)                                      \
+    template <>                                                      \
+    inline T AtomicOperations::exchangeSeqCst(T* addr, T val) {      \
+      MOZ_ASSERT(tier1Constraints(addr));                            \
+      _ReadWriteBarrier();                                           \
+      T oldval = *addr;                                              \
+      for (;;) {                                                     \
+        T nextval = (T)_InterlockedCompareExchange64(                \
+            (__int64 volatile*)addr, (__int64)val, (__int64)oldval); \
+        if (nextval == oldval) break;                                \
+        oldval = nextval;                                            \
+      }                                                              \
+      _ReadWriteBarrier();                                           \
+      return oldval;                                                 \
+    }
+#endif  // _M_IX86
+
+namespace js {
+namespace jit {
+
+MSC_EXCHANGEOP(int8_t, char, _InterlockedExchange8)
+MSC_EXCHANGEOP(uint8_t, char, _InterlockedExchange8)
+MSC_EXCHANGEOP(int16_t, short, _InterlockedExchange16)
+MSC_EXCHANGEOP(uint16_t, short, _InterlockedExchange16)
+MSC_EXCHANGEOP(int32_t, long, _InterlockedExchange)
+MSC_EXCHANGEOP(uint32_t, long, _InterlockedExchange)
+
+#ifdef _M_IX86
+MSC_EXCHANGEOP_CAS(int64_t)
+MSC_EXCHANGEOP_CAS(uint64_t)
+#else
+MSC_EXCHANGEOP(int64_t, __int64, _InterlockedExchange64)
+MSC_EXCHANGEOP(uint64_t, __int64, _InterlockedExchange64)
+#endif
+
+}  // namespace jit
+}  // namespace js
+
+#undef MSC_EXCHANGEOP
+#undef MSC_EXCHANGEOP_CAS
+
+#define MSC_CAS(T, U, cmpxchg)                                        \
+  template <>                                                         \
+  inline T AtomicOperations::compareExchangeSeqCst(T* addr, T oldval, \
+                                                   T newval) {        \
+    MOZ_ASSERT(tier1Constraints(addr));                               \
+    return (T)cmpxchg((U volatile*)addr, (U)newval, (U)oldval);       \
+  }
+
+namespace js {
+namespace jit {
+
+MSC_CAS(int8_t, char, _InterlockedCompareExchange8)
+MSC_CAS(uint8_t, char, _InterlockedCompareExchange8)
+MSC_CAS(int16_t, short, _InterlockedCompareExchange16)
+MSC_CAS(uint16_t, short, _InterlockedCompareExchange16)
+MSC_CAS(int32_t, long, _InterlockedCompareExchange)
+MSC_CAS(uint32_t, long, _InterlockedCompareExchange)
+MSC_CAS(int64_t, __int64, _InterlockedCompareExchange64)
+MSC_CAS(uint64_t, __int64, _InterlockedCompareExchange64)
+
+}  // namespace jit
+}  // namespace js
+
+#undef MSC_CAS
+
+#define MSC_FETCHADDOP(T, U, xadd)                            \
+  template <>                                                 \
+  inline T AtomicOperations::fetchAddSeqCst(T* addr, T val) { \
+    MOZ_ASSERT(tier1Constraints(addr));                       \
+    return (T)xadd((U volatile*)addr, (U)val);                \
+  }
+
+#define MSC_FETCHSUBOP(T)                                     \
+  template <>                                                 \
+  inline T AtomicOperations::fetchSubSeqCst(T* addr, T val) { \
+    return fetchAddSeqCst(addr, (T)(0 - val));                \
+  }
+
+#ifdef _M_IX86
+#  define MSC_FETCHADDOP_CAS(T)                                               \
+    template <>                                                               \
+    inline T AtomicOperations::fetchAddSeqCst(T* addr, T val) {               \
+      MOZ_ASSERT(tier1Constraints(addr));                                     \
+      _ReadWriteBarrier();                                                    \
+      T oldval = *addr;                                                       \
+      for (;;) {                                                              \
+        T nextval = (T)_InterlockedCompareExchange64((__int64 volatile*)addr, \
+                                                     (__int64)(oldval + val), \
+                                                     (__int64)oldval);        \
+        if (nextval == oldval) break;                                         \
+        oldval = nextval;                                                     \
+      }                                                                       \
+      _ReadWriteBarrier();                                                    \
+      return oldval;                                                          \
+    }
+#endif  // _M_IX86
+
+namespace js {
+namespace jit {
+
+MSC_FETCHADDOP(int8_t, char, _InterlockedExchangeAdd8)
+MSC_FETCHADDOP(uint8_t, char, _InterlockedExchangeAdd8)
+MSC_FETCHADDOP(int16_t, short, _InterlockedExchangeAdd16)
+MSC_FETCHADDOP(uint16_t, short, _InterlockedExchangeAdd16)
+MSC_FETCHADDOP(int32_t, long, _InterlockedExchangeAdd)
+MSC_FETCHADDOP(uint32_t, long, _InterlockedExchangeAdd)
+
+#ifdef _M_IX86
+MSC_FETCHADDOP_CAS(int64_t)
+MSC_FETCHADDOP_CAS(uint64_t)
+#else
+MSC_FETCHADDOP(int64_t, __int64, _InterlockedExchangeAdd64)
+MSC_FETCHADDOP(uint64_t, __int64, _InterlockedExchangeAdd64)
+#endif
+
+MSC_FETCHSUBOP(int8_t)
+MSC_FETCHSUBOP(uint8_t)
+MSC_FETCHSUBOP(int16_t)
+MSC_FETCHSUBOP(uint16_t)
+MSC_FETCHSUBOP(int32_t)
+MSC_FETCHSUBOP(uint32_t)
+MSC_FETCHSUBOP(int64_t)
+MSC_FETCHSUBOP(uint64_t)
+
+}  // namespace jit
+}  // namespace js
+
+#undef MSC_FETCHADDOP
+#undef MSC_FETCHADDOP_CAS
+#undef MSC_FETCHSUBOP
+
+#define MSC_FETCHBITOPX(T, U, name, op)             \
+  template <>                                       \
+  inline T AtomicOperations::name(T* addr, T val) { \
+    MOZ_ASSERT(tier1Constraints(addr));             \
+    return (T)op((U volatile*)addr, (U)val);        \
+  }
+
+#define MSC_FETCHBITOP(T, U, andop, orop, xorop) \
+  MSC_FETCHBITOPX(T, U, fetchAndSeqCst, andop)   \
+  MSC_FETCHBITOPX(T, U, fetchOrSeqCst, orop)     \
+  MSC_FETCHBITOPX(T, U, fetchXorSeqCst, xorop)
+
+#ifdef _M_IX86
+#  define AND_OP &
+#  define OR_OP |
+#  define XOR_OP ^
+#  define MSC_FETCHBITOPX_CAS(T, name, OP)                                     \
+    template <>                                                                \
+    inline T AtomicOperations::name(T* addr, T val) {                          \
+      MOZ_ASSERT(tier1Constraints(addr));                                      \
+      _ReadWriteBarrier();                                                     \
+      T oldval = *addr;                                                        \
+      for (;;) {                                                               \
+        T nextval = (T)_InterlockedCompareExchange64((__int64 volatile*)addr,  \
+                                                     (__int64)(oldval OP val), \
+                                                     (__int64)oldval);         \
+        if (nextval == oldval) break;                                          \
+        oldval = nextval;                                                      \
+      }                                                                        \
+      _ReadWriteBarrier();                                                     \
+      return oldval;                                                           \
+    }
+
+#  define MSC_FETCHBITOP_CAS(T)                    \
+    MSC_FETCHBITOPX_CAS(T, fetchAndSeqCst, AND_OP) \
+    MSC_FETCHBITOPX_CAS(T, fetchOrSeqCst, OR_OP)   \
+    MSC_FETCHBITOPX_CAS(T, fetchXorSeqCst, XOR_OP)
+
+#endif
+
+namespace js {
+namespace jit {
+
+MSC_FETCHBITOP(int8_t, char, _InterlockedAnd8, _InterlockedOr8,
+               _InterlockedXor8)
+MSC_FETCHBITOP(uint8_t, char, _InterlockedAnd8, _InterlockedOr8,
+               _InterlockedXor8)
+MSC_FETCHBITOP(int16_t, short, _InterlockedAnd16, _InterlockedOr16,
+               _InterlockedXor16)
+MSC_FETCHBITOP(uint16_t, short, _InterlockedAnd16, _InterlockedOr16,
+               _InterlockedXor16)
+MSC_FETCHBITOP(int32_t, long, _InterlockedAnd, _InterlockedOr, _InterlockedXor)
+MSC_FETCHBITOP(uint32_t, long, _InterlockedAnd, _InterlockedOr, _InterlockedXor)
+
+#ifdef _M_IX86
+MSC_FETCHBITOP_CAS(int64_t)
+MSC_FETCHBITOP_CAS(uint64_t)
+#else
+MSC_FETCHBITOP(int64_t, __int64, _InterlockedAnd64, _InterlockedOr64,
+               _InterlockedXor64)
+MSC_FETCHBITOP(uint64_t, __int64, _InterlockedAnd64, _InterlockedOr64,
+               _InterlockedXor64)
+#endif
+
+}  // namespace jit
+}  // namespace js
+
+#undef MSC_FETCHBITOPX_CAS
+#undef MSC_FETCHBITOPX
+#undef MSC_FETCHBITOP_CAS
+#undef MSC_FETCHBITOP
+
+template <typename T>
+inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  // This is also appropriate for double, int64, and uint64 on 32-bit
+  // platforms since there are no guarantees of access-atomicity.
+  return *addr;
+}
+
+template <typename T>
+inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  // This is also appropriate for double, int64, and uint64 on 32-bit
+  // platforms since there are no guarantees of access-atomicity.
+  *addr = val;
+}
+
+inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
+                                                          const void* src,
+                                                          size_t nbytes) {
+  MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest + nbytes));
+  MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src + nbytes));
+  ::memcpy(dest, src, nbytes);
+}
+
+inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
+                                                           const void* src,
+                                                           size_t nbytes) {
+  ::memmove(dest, src, nbytes);
+}
+
+#endif  // jit_shared_AtomicOperations_x86_shared_msvc_h
--- a/js/src/jit/arm64/MacroAssembler-arm64.cpp
+++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp
@@ -1599,18 +1599,16 @@ static void CompareExchange(MacroAssembl
   Label again;
   Label done;
 
   vixl::UseScratchRegisterScope temps(&masm);
 
   Register scratch2 = temps.AcquireX().asUnsized();
   MemOperand ptr = ComputePointerForAtomic(masm, mem, scratch2);
 
-  MOZ_ASSERT(ptr.base().asUnsized() != output);
-
   masm.memoryBarrierBefore(sync);
 
   Register scratch = temps.AcquireX().asUnsized();
 
   masm.bind(&again);
   SignOrZeroExtend(masm, type, targetWidth, oldval, scratch);
   LoadExclusive(masm, access, type, targetWidth, ptr, output);
   masm.Cmp(R(output, targetWidth), R(scratch, targetWidth));
@@ -1704,37 +1702,16 @@ void MacroAssembler::compareExchange(Sca
 void MacroAssembler::compareExchange(Scalar::Type type,
                                      const Synchronization& sync,
                                      const BaseIndex& mem, Register oldval,
                                      Register newval, Register output) {
   CompareExchange(*this, nullptr, type, Width::_32, sync, mem, oldval, newval,
                   output);
 }
 
-void MacroAssembler::compareExchange64(const Synchronization& sync,
-                                       const Address& mem, Register64 expect,
-                                       Register64 replace, Register64 output) {
-  CompareExchange(*this, nullptr, Scalar::Int64, Width::_64, sync, mem,
-                  expect.reg, replace.reg, output.reg);
-}
-
-void MacroAssembler::atomicExchange64(const Synchronization& sync,
-                                      const Address& mem, Register64 value,
-                                      Register64 output) {
-  AtomicExchange(*this, nullptr, Scalar::Int64, Width::_64, sync, mem,
-                 value.reg, output.reg);
-}
-
-void MacroAssembler::atomicFetchOp64(const Synchronization& sync, AtomicOp op,
-                                     Register64 value, const Address& mem,
-                                     Register64 temp, Register64 output) {
-  AtomicFetchOp<true>(*this, nullptr, Scalar::Int64, Width::_64, sync, op, mem,
-                      value.reg, temp.reg, output.reg);
-}
-
 void MacroAssembler::wasmCompareExchange(const wasm::MemoryAccessDesc& access,
                                          const Address& mem, Register oldval,
                                          Register newval, Register output) {
   CompareExchange(*this, &access, access.type(), Width::_32, access.sync(), mem,
                   oldval, newval, output);
 }
 
 void MacroAssembler::wasmCompareExchange(const wasm::MemoryAccessDesc& access,
--- a/js/src/jit/mips-shared/AtomicOperations-mips-shared.h
+++ b/js/src/jit/mips-shared/AtomicOperations-mips-shared.h
@@ -56,25 +56,16 @@ struct MOZ_RAII AddressGuard {
   ~AddressGuard() { gAtomic64Lock.release(); }
 };
 
 #endif
 
 }  // namespace jit
 }  // namespace js
 
-inline bool js::jit::AtomicOperations::Initialize() {
-  // Nothing
-  return true;
-}
-
-inline void js::jit::AtomicOperations::ShutDown() {
-  // Nothing
-}
-
 inline bool js::jit::AtomicOperations::hasAtomic8() { return true; }
 
 inline bool js::jit::AtomicOperations::isLockfree8() {
   MOZ_ASSERT(__atomic_always_lock_free(sizeof(int8_t), 0));
   MOZ_ASSERT(__atomic_always_lock_free(sizeof(int16_t), 0));
   MOZ_ASSERT(__atomic_always_lock_free(sizeof(int32_t), 0));
 #if defined(JS_64BIT)
   MOZ_ASSERT(__atomic_always_lock_free(sizeof(int64_t), 0));
--- a/js/src/jit/moz.build
+++ b/js/src/jit/moz.build
@@ -107,17 +107,16 @@ UNIFIED_SOURCES += [
 if not CONFIG['ENABLE_ION']:
     LOpcodesGenerated.inputs += ['none/LIR-none.h']
     UNIFIED_SOURCES += [
         'none/Trampoline-none.cpp'
     ]
 elif CONFIG['JS_CODEGEN_X86'] or CONFIG['JS_CODEGEN_X64']:
     LOpcodesGenerated.inputs += ['x86-shared/LIR-x86-shared.h']
     UNIFIED_SOURCES += [
-        'shared/AtomicOperations-shared-jit.cpp',
         'x86-shared/Architecture-x86-shared.cpp',
         'x86-shared/Assembler-x86-shared.cpp',
         'x86-shared/AssemblerBuffer-x86-shared.cpp',
         'x86-shared/CodeGenerator-x86-shared.cpp',
         'x86-shared/Lowering-x86-shared.cpp',
         'x86-shared/MacroAssembler-x86-shared-SIMD.cpp',
         'x86-shared/MacroAssembler-x86-shared.cpp',
         'x86-shared/MoveEmitter-x86-shared.cpp',
@@ -150,17 +149,16 @@ elif CONFIG['JS_CODEGEN_ARM']:
         'arm/Bailouts-arm.cpp',
         'arm/CodeGenerator-arm.cpp',
         'arm/disasm/Constants-arm.cpp',
         'arm/disasm/Disasm-arm.cpp',
         'arm/Lowering-arm.cpp',
         'arm/MacroAssembler-arm.cpp',
         'arm/MoveEmitter-arm.cpp',
         'arm/Trampoline-arm.cpp',
-        'shared/AtomicOperations-shared-jit.cpp',
     ]
     if CONFIG['JS_SIMULATOR_ARM']:
         UNIFIED_SOURCES += [
             'arm/Simulator-arm.cpp'
         ]
     elif CONFIG['OS_ARCH'] == 'Darwin':
         SOURCES += [
             'arm/llvm-compiler-rt/arm/aeabi_idivmod.S',
@@ -182,18 +180,17 @@ elif CONFIG['JS_CODEGEN_ARM64']:
         'arm64/vixl/Decoder-vixl.cpp',
         'arm64/vixl/Disasm-vixl.cpp',
         'arm64/vixl/Instructions-vixl.cpp',
         'arm64/vixl/Instrument-vixl.cpp',
         'arm64/vixl/MacroAssembler-vixl.cpp',
         'arm64/vixl/MozAssembler-vixl.cpp',
         'arm64/vixl/MozCpu-vixl.cpp',
         'arm64/vixl/MozInstructions-vixl.cpp',
-        'arm64/vixl/Utils-vixl.cpp',
-        'shared/AtomicOperations-shared-jit.cpp',
+        'arm64/vixl/Utils-vixl.cpp'
     ]
     if CONFIG['JS_SIMULATOR_ARM64']:
         UNIFIED_SOURCES += [
             'arm64/vixl/Debugger-vixl.cpp',
             'arm64/vixl/Logic-vixl.cpp',
             'arm64/vixl/MozSimulator-vixl.cpp',
             'arm64/vixl/Simulator-vixl.cpp'
         ]
rename from js/src/jit/shared/AtomicOperations-feeling-lucky-gcc.h
rename to js/src/jit/none/AtomicOperations-feeling-lucky.h
--- a/js/src/jit/shared/AtomicOperations-feeling-lucky-gcc.h
+++ b/js/src/jit/none/AtomicOperations-feeling-lucky.h
@@ -2,50 +2,37 @@
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* For documentation, see jit/AtomicOperations.h, both the comment block at the
  * beginning and the #ifdef nest near the end.
  *
- * This is a common file for tier-3 platforms (including simulators for our
- * tier-1 platforms) that are not providing hardware-specific implementations of
- * the atomic operations.  Please keep it reasonably platform-independent by
- * adding #ifdefs at the beginning as much as possible, not throughout the file.
+ * This is a common file for tier-3 platforms that are not providing
+ * hardware-specific implementations of the atomic operations.  Please keep it
+ * reasonably platform-independent by adding #ifdefs at the beginning as much as
+ * possible, not throughout the file.
  *
  *
  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  * !!!!                              NOTE                                 !!!!
  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  *
  * The implementations in this file are NOT SAFE and cannot be safe even in
  * principle because they rely on C++ undefined behavior.  However, they are
  * frequently good enough for tier-3 platforms.
  */
 
-#ifndef jit_shared_AtomicOperations_feeling_lucky_gcc_h
-#define jit_shared_AtomicOperations_feeling_lucky_gcc_h
+#ifndef jit_none_AtomicOperations_feeling_lucky_h
+#define jit_none_AtomicOperations_feeling_lucky_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Types.h"
 
-// Explicitly exclude tier-1 platforms.
-
-#if ((defined(__x86_64__) || defined(_M_X64)) && defined(JS_CODEGEN_X64)) || \
-    ((defined(__i386__) || defined(_M_IX86)) && defined(JS_CODEGEN_X86)) ||  \
-    (defined(__arm__) && defined(JS_CODEGEN_ARM)) ||                         \
-    ((defined(__aarch64__) || defined(_M_ARM64)) && defined(JS_CODEGEN_ARM64))
-#  error "Do not use this code on a tier-1 platform when a JIT is available"
-#endif
-
-#if !(defined(__clang__) || defined(__GNUC__))
-#  error "This file only for gcc/Clang"
-#endif
-
 // 64-bit atomics are not required by the JS spec, and you can compile
 // SpiderMonkey without them.
 //
 // 64-bit lock-free atomics are however required for WebAssembly, and
 // WebAssembly will be disabled if you do not define both HAS_64BIT_ATOMICS and
 // HAS_64BIT_LOCKFREE.
 //
 // If you are only able to provide 64-bit non-lock-free atomics and you really
@@ -82,47 +69,43 @@
 #ifdef __sh__
 #  define GNUC_COMPATIBLE
 #endif
 
 #ifdef __s390__
 #  define GNUC_COMPATIBLE
 #endif
 
-// The default implementation tactic for gcc/clang is to use the newer __atomic
-// intrinsics added for use in C++11 <atomic>.  Where that isn't available, we
-// use GCC's older __sync functions instead.
+#ifdef __s390x__
+#  define HAS_64BIT_ATOMICS
+#  define HAS_64BIT_LOCKFREE
+#  define GNUC_COMPATIBLE
+#endif
+
+// The default implementation tactic for gcc/clang is to use the newer
+// __atomic intrinsics added for use in C++11 <atomic>.  Where that
+// isn't available, we use GCC's older __sync functions instead.
 //
-// ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS is kept as a backward compatible
-// option for older compilers: enable this to use GCC's old __sync functions
-// instead of the newer __atomic functions.  This will be required for GCC 4.6.x
-// and earlier, and probably for Clang 3.1, should we need to use those
-// versions.  Firefox no longer supports compilers that old.
+// ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS is kept as a backward
+// compatible option for older compilers: enable this to use GCC's old
+// __sync functions instead of the newer __atomic functions.  This
+// will be required for GCC 4.6.x and earlier, and probably for Clang
+// 3.1, should we need to use those versions.
 
 //#define ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
 
 // Sanity check.
 
 #if defined(HAS_64BIT_LOCKFREE) && !defined(HAS_64BIT_ATOMICS)
 #  error "This combination of features is senseless, please fix"
 #endif
 
 // Try to avoid platform #ifdefs below this point.
 
-inline bool js::jit::AtomicOperations::Initialize() {
-  // Nothing
-  return true;
-}
-
-inline void js::jit::AtomicOperations::ShutDown() {
-  // Nothing
-}
-
-// When compiling with Clang on 32-bit linux it will be necessary to link with
-// -latomic to get the proper 64-bit intrinsics.
+#ifdef GNUC_COMPATIBLE
 
 inline bool js::jit::AtomicOperations::hasAtomic8() {
 #  if defined(HAS_64BIT_ATOMICS)
   return true;
 #  else
   return false;
 #  endif
 }
@@ -201,51 +184,16 @@ inline void AtomicOperations::storeSeqCs
   MOZ_CRASH("No 64-bit atomics");
 }
 
 }  // namespace jit
 }  // namespace js
 #  endif
 
 template <typename T>
-inline T js::jit::AtomicOperations::exchangeSeqCst(T* addr, T val) {
-  static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
-#  ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
-  T v;
-  __sync_synchronize();
-  do {
-    v = *addr;
-  } while (__sync_val_compare_and_swap(addr, v, val) != v);
-  return v;
-#  else
-  T v;
-  __atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
-  return v;
-#  endif
-}
-
-#  ifndef HAS_64BIT_ATOMICS
-namespace js {
-namespace jit {
-
-template <>
-inline int64_t AtomicOperations::exchangeSeqCst(int64_t* addr, int64_t val) {
-  MOZ_CRASH("No 64-bit atomics");
-}
-
-template <>
-inline uint64_t AtomicOperations::exchangeSeqCst(uint64_t* addr, uint64_t val) {
-  MOZ_CRASH("No 64-bit atomics");
-}
-
-}  // namespace jit
-}  // namespace js
-#  endif
-
-template <typename T>
 inline T js::jit::AtomicOperations::compareExchangeSeqCst(T* addr, T oldval,
                                                           T newval) {
   static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
 #  ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
   return __sync_val_compare_and_swap(addr, oldval, newval);
 #  else
   __atomic_compare_exchange(addr, &oldval, &newval, false, __ATOMIC_SEQ_CST,
                             __ATOMIC_SEQ_CST);
@@ -415,30 +363,24 @@ inline uint64_t AtomicOperations::fetchX
 }  // namespace js
 #  endif
 
 template <typename T>
 inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
   static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
   // This is actually roughly right even on 32-bit platforms since in that
   // case, double, int64, and uint64 loads need not be access-atomic.
-  //
-  // We could use __atomic_load, but it would be needlessly expensive on
-  // 32-bit platforms that could support it and just plain wrong on others.
   return *addr;
 }
 
 template <typename T>
 inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
   static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
   // This is actually roughly right even on 32-bit platforms since in that
   // case, double, int64, and uint64 loads need not be access-atomic.
-  //
-  // We could use __atomic_store, but it would be needlessly expensive on
-  // 32-bit platforms that could support it and just plain wrong on others.
   *addr = val;
 }
 
 inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
                                                           const void* src,
                                                           size_t nbytes) {
   MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest + nbytes));
   MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src + nbytes));
@@ -446,13 +388,55 @@ inline void js::jit::AtomicOperations::m
 }
 
 inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
                                                            const void* src,
                                                            size_t nbytes) {
   ::memmove(dest, src, nbytes);
 }
 
+template <typename T>
+inline T js::jit::AtomicOperations::exchangeSeqCst(T* addr, T val) {
+  static_assert(sizeof(T) <= 8, "atomics supported up to 8 bytes only");
+#  ifdef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
+  T v;
+  __sync_synchronize();
+  do {
+    v = *addr;
+  } while (__sync_val_compare_and_swap(addr, v, val) != v);
+  return v;
+#  else
+  T v;
+  __atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
+  return v;
+#  endif
+}
+
+#  ifndef HAS_64BIT_ATOMICS
+namespace js {
+namespace jit {
+
+template <>
+inline int64_t AtomicOperations::exchangeSeqCst(int64_t* addr, int64_t val) {
+  MOZ_CRASH("No 64-bit atomics");
+}
+
+template <>
+inline uint64_t AtomicOperations::exchangeSeqCst(uint64_t* addr, uint64_t val) {
+  MOZ_CRASH("No 64-bit atomics");
+}
+
+}  // namespace jit
+}  // namespace js
+#  endif
+
+#else
+
+#  error "Either use GCC or Clang, or add code here"
+
+#endif
+
 #undef ATOMICS_IMPLEMENTED_WITH_SYNC_INTRINSICS
+#undef GNUC_COMPATIBLE
 #undef HAS_64BIT_ATOMICS
 #undef HAS_64BIT_LOCKFREE
 
-#endif  // jit_shared_AtomicOperations_feeling_lucky_gcc_h
+#endif  // jit_none_AtomicOperations_feeling_lucky_h
deleted file mode 100644
--- a/js/src/jit/shared/AtomicOperations-feeling-lucky.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef jit_shared_AtomicOperations_feeling_lucky_h
-#define jit_shared_AtomicOperations_feeling_lucky_h
-
-#if defined(__clang__) || defined(__GNUC__)
-# include "jit/shared/AtomicOperations-feeling-lucky-gcc.h"
-#elif defined(_MSC_VER)
-# include "jit/shared/AtomicOperations-feeling-lucky-msvc.h"
-#else
-# error "No AtomicOperations support for this platform+compiler combination"
-#endif
-
-#endif // jit_shared_AtomicOperations_feeling_lucky_h
-
deleted file mode 100644
--- a/js/src/jit/shared/AtomicOperations-shared-jit.cpp
+++ /dev/null
@@ -1,1018 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/Atomics.h"
-
-#ifdef JS_CODEGEN_ARM
-#  include "jit/arm/Architecture-arm.h"
-#endif
-#include "jit/AtomicOperations.h"
-#include "jit/IonTypes.h"
-#include "jit/MacroAssembler.h"
-#include "jit/RegisterSets.h"
-
-#include "jit/MacroAssembler-inl.h"
-
-using namespace js;
-using namespace js::jit;
-
-// Assigned registers must follow these rules:
-//
-//  - if they overlap the argument registers (for arguments we use) then they
-//
-//                     M   M   U   U   SSSS  TTTTT
-//          ====\      MM MM   U   U  S        T      /====
-//          =====>     M M M   U   U   SSS     T     <=====
-//          ====/      M   M   U   U      S    T      \====
-//                     M   M    UUU   SSSS     T
-//
-//    require no register movement, even for 64-bit registers.  (If this becomes
-//    too complex to handle then we need to create an abstraction that uses the
-//    MoveResolver, see comments on bug 1394420.)
-//
-//  - they should be volatile when possible so that we don't have to save and
-//    restore them.
-//
-// Note that the functions we're generating have a very limited number of
-// signatures, and the register assignments need only work for these signatures.
-// The signatures are these:
-//
-//   ()
-//   (ptr)
-//   (ptr, val/val64)
-//   (ptr, ptr)
-//   (ptr, val/val64, val/val64)
-//
-// It would be nice to avoid saving and restoring all the nonvolatile registers
-// for all the operations, and instead save and restore only the registers used
-// by each specific operation, but the amount of protocol needed to accomplish
-// that probably does not pay for itself.
-
-#if defined(JS_CODEGEN_X64)
-
-// Selected registers match the argument registers exactly, and none of them
-// overlap the result register.
-
-static const LiveRegisterSet AtomicNonVolatileRegs;
-
-static constexpr Register AtomicPtrReg = IntArgReg0;
-static constexpr Register AtomicPtr2Reg = IntArgReg1;
-static constexpr Register AtomicValReg = IntArgReg1;
-static constexpr Register64 AtomicValReg64(IntArgReg1);
-static constexpr Register AtomicVal2Reg = IntArgReg2;
-static constexpr Register64 AtomicVal2Reg64(IntArgReg2);
-static constexpr Register AtomicTemp = IntArgReg3;
-static constexpr Register64 AtomicTemp64(IntArgReg3);
-
-#elif defined(JS_CODEGEN_ARM64)
-
-// Selected registers match the argument registers, except that the Ptr is not
-// in IntArgReg0 so as not to conflict with the result register.
-
-static const LiveRegisterSet AtomicNonVolatileRegs;
-
-static constexpr Register AtomicPtrReg = IntArgReg4;
-static constexpr Register AtomicPtr2Reg = IntArgReg1;
-static constexpr Register AtomicValReg = IntArgReg1;
-static constexpr Register64 AtomicValReg64(IntArgReg1);
-static constexpr Register AtomicVal2Reg = IntArgReg2;
-static constexpr Register64 AtomicVal2Reg64(IntArgReg2);
-static constexpr Register AtomicTemp = IntArgReg3;
-static constexpr Register64 AtomicTemp64(IntArgReg3);
-
-#elif defined(JS_CODEGEN_ARM)
-
-// Assigned registers except temp are disjoint from the argument registers,
-// since accounting for both 32-bit and 64-bit arguments and constraints on the
-// result register is much too messy.  The temp is in an argument register since
-// it won't be used until we've moved all arguments to other registers.
-
-static const LiveRegisterSet AtomicNonVolatileRegs =
-  LiveRegisterSet(GeneralRegisterSet((uint32_t(1) << Registers::r4) |
-                                     (uint32_t(1) << Registers::r5) |
-                                     (uint32_t(1) << Registers::r6) |
-                                     (uint32_t(1) << Registers::r7) |
-                                     (uint32_t(1) << Registers::r8)),
-                  FloatRegisterSet(0));
-
-static constexpr Register AtomicPtrReg = r8;
-static constexpr Register AtomicPtr2Reg = r6;
-static constexpr Register AtomicTemp = r3;
-static constexpr Register AtomicValReg = r6;
-static constexpr Register64 AtomicValReg64(r7, r6);
-static constexpr Register AtomicVal2Reg = r4;
-static constexpr Register64 AtomicVal2Reg64(r5, r4);
-
-#elif defined(JS_CODEGEN_X86)
-
-// There are no argument registers.
-
-static const LiveRegisterSet AtomicNonVolatileRegs =
-  LiveRegisterSet(GeneralRegisterSet((1 << X86Encoding::rbx) |
-                                     (1 << X86Encoding::rsi)),
-                  FloatRegisterSet(0));
-
-static constexpr Register AtomicPtrReg = esi;
-static constexpr Register AtomicPtr2Reg = ebx;
-static constexpr Register AtomicValReg = ebx;
-static constexpr Register AtomicVal2Reg = ecx;
-static constexpr Register AtomicTemp = edx;
-
-// 64-bit registers for cmpxchg8b.  ValReg/Val2Reg/Temp are not used in this
-// case.
-
-static constexpr Register64 AtomicValReg64(edx, eax);
-static constexpr Register64 AtomicVal2Reg64(ecx, ebx);
-
-#else
-#  error "Not implemented - not a tier1 platform"
-#endif
-
-// These are useful shorthands and hide the meaningless uint/int distinction.
-
-static constexpr Scalar::Type SIZE8 = Scalar::Uint8;
-static constexpr Scalar::Type SIZE16 = Scalar::Uint16;
-static constexpr Scalar::Type SIZE32 = Scalar::Uint32;
-static constexpr Scalar::Type SIZE64 = Scalar::Int64;
-#ifdef JS_64BIT
-static constexpr Scalar::Type SIZEWORD = SIZE64;
-#else
-static constexpr Scalar::Type SIZEWORD = SIZE32;
-#endif
-
-// A "block" is a sequence of bytes that is a reasonable quantum to copy to
-// amortize call overhead when implementing memcpy and memmove.  A block will
-// not fit in registers on all platforms and copying it without using
-// intermediate memory will therefore be sensitive to overlap.
-//
-// A "word" is an item that we can copy using only register intermediate storage
-// on all platforms; words can be individually copied without worrying about
-// overlap.
-//
-// Blocks and words can be aligned or unaligned; specific (generated) copying
-// functions handle this in platform-specific ways.
-
-static constexpr size_t WORDSIZE = sizeof(uintptr_t); // Also see SIZEWORD above
-static constexpr size_t BLOCKSIZE = 8 * WORDSIZE;     // Must be a power of 2
-
-static_assert(BLOCKSIZE % WORDSIZE == 0, "A block is an integral number of words");
-
-static constexpr size_t WORDMASK = WORDSIZE - 1;
-static constexpr size_t BLOCKMASK = BLOCKSIZE - 1;
-
-struct ArgIterator
-{
-    ABIArgGenerator abi;
-    unsigned argBase = 0;
-};
-
-static void GenGprArg(MacroAssembler& masm, MIRType t, ArgIterator* iter,
-                      Register reg) {
-  MOZ_ASSERT(t == MIRType::Pointer || t == MIRType::Int32);
-  ABIArg arg = iter->abi.next(t);
-  switch (arg.kind()) {
-    case ABIArg::GPR: {
-      if (arg.gpr() != reg) {
-        masm.movePtr(arg.gpr(), reg);
-      }
-      break;
-    }
-    case ABIArg::Stack: {
-      Address src(masm.getStackPointer(),
-                  iter->argBase + arg.offsetFromArgBase());
-      masm.loadPtr(src, reg);
-      break;
-    }
-    default: {
-      MOZ_CRASH("Not possible");
-    }
-  }
-}
-
-static void GenGpr64Arg(MacroAssembler& masm, ArgIterator* iter,
-                        Register64 reg) {
-  ABIArg arg = iter->abi.next(MIRType::Int64);
-  switch (arg.kind()) {
-    case ABIArg::GPR: {
-      if (arg.gpr64() != reg) {
-        masm.move64(arg.gpr64(), reg);
-      }
-      break;
-    }
-    case ABIArg::Stack: {
-      Address src(masm.getStackPointer(),
-                  iter->argBase + arg.offsetFromArgBase());
-#ifdef JS_64BIT
-      masm.load64(src, reg);
-#else
-      masm.load32(LowWord(src), reg.low);
-      masm.load32(HighWord(src), reg.high);
-#endif
-      break;
-    }
-#if defined(JS_CODEGEN_REGISTER_PAIR)
-    case ABIArg::GPR_PAIR: {
-      if (arg.gpr64() != reg) {
-        masm.move32(arg.oddGpr(), reg.high);
-        masm.move32(arg.evenGpr(), reg.low);
-      }
-      break;
-    }
-#endif
-    default: {
-      MOZ_CRASH("Not possible");
-    }
-  }
-}
-
-static uint32_t GenPrologue(MacroAssembler& masm, ArgIterator* iter) {
-  masm.assumeUnreachable("Shouldn't get here");
-  masm.flushBuffer();
-  masm.haltingAlign(CodeAlignment);
-  masm.setFramePushed(0);
-  uint32_t start = masm.currentOffset();
-  masm.PushRegsInMask(AtomicNonVolatileRegs);
-  iter->argBase = sizeof(void*) + masm.framePushed();
-  return start;
-}
-
-static void GenEpilogue(MacroAssembler& masm) {
-  masm.PopRegsInMask(AtomicNonVolatileRegs);
-  MOZ_ASSERT(masm.framePushed() == 0);
-#if defined(JS_CODEGEN_ARM64)
-  masm.Ret();
-#elif defined(JS_CODEGEN_ARM)
-  masm.mov(lr, pc);
-#else
-  masm.ret();
-#endif
-}
-
-#ifndef JS_64BIT
-static uint32_t GenNop(MacroAssembler& masm) {
-  ArgIterator iter;
-  uint32_t start = GenPrologue(masm, &iter);
-  GenEpilogue(masm);
-  return start;
-}
-#endif
-
-static uint32_t GenFenceSeqCst(MacroAssembler& masm) {
-  ArgIterator iter;
-  uint32_t start = GenPrologue(masm, &iter);
-  masm.memoryBarrier(MembarFull);
-  GenEpilogue(masm);
-  return start;
-}
-
-static uint32_t GenLoad(MacroAssembler& masm, Scalar::Type size,
-                        Synchronization sync) {
-  ArgIterator iter;
-  uint32_t start = GenPrologue(masm, &iter);
-  GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
-
-  masm.memoryBarrier(sync.barrierBefore);
-  Address addr(AtomicPtrReg, 0);
-  switch (size) {
-    case SIZE8:
-      masm.load8ZeroExtend(addr, ReturnReg);
-      break;
-    case SIZE16:
-      masm.load16ZeroExtend(addr, ReturnReg);
-      break;
-    case SIZE32:
-      masm.load32(addr, ReturnReg);
-      break;
-    case SIZE64:
-#if defined(JS_64BIT)
-      masm.load64(addr, ReturnReg64);
-      break;
-#else
-      MOZ_CRASH("64-bit atomic load not available on this platform");
-#endif
-    default:
-      MOZ_CRASH("Unknown size");
-  }
-  masm.memoryBarrier(sync.barrierAfter);
-
-  GenEpilogue(masm);
-  return start;
-}
-
-static uint32_t GenStore(MacroAssembler& masm, Scalar::Type size,
-                         Synchronization sync) {
-  ArgIterator iter;
-  uint32_t start = GenPrologue(masm, &iter);
-  GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
-
-  masm.memoryBarrier(sync.barrierBefore);
-  Address addr(AtomicPtrReg, 0);
-  switch (size) {
-    case SIZE8:
-      GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
-      masm.store8(AtomicValReg, addr);
-      break;
-    case SIZE16:
-      GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
-      masm.store16(AtomicValReg, addr);
-      break;
-    case SIZE32:
-      GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
-      masm.store32(AtomicValReg, addr);
-      break;
-    case SIZE64:
-#if defined(JS_64BIT)
-      GenGpr64Arg(masm, &iter, AtomicValReg64);
-      masm.store64(AtomicValReg64, addr);
-      break;
-#else
-      MOZ_CRASH("64-bit atomic store not available on this platform");
-#endif
-    default:
-      MOZ_CRASH("Unknown size");
-  }
-  masm.memoryBarrier(sync.barrierAfter);
-
-  GenEpilogue(masm);
-  return start;
-}
-
-enum class CopyDir {
-  DOWN,                       // Move data down, ie, iterate toward higher addresses
-  UP                          // The other way
-};
-
-static uint32_t GenCopy(MacroAssembler& masm, Scalar::Type size,
-                        uint32_t unroll, CopyDir direction) {
-  ArgIterator iter;
-  uint32_t start = GenPrologue(masm, &iter);
-
-  Register dest = AtomicPtrReg;
-  Register src = AtomicPtr2Reg;
-
-  GenGprArg(masm, MIRType::Pointer, &iter, dest);
-  GenGprArg(masm, MIRType::Pointer, &iter, src);
-
-  uint32_t offset = direction == CopyDir::DOWN ? 0 : unroll-1;
-  for (uint32_t i = 0; i < unroll; i++) {
-    switch (size) {
-      case SIZE8:
-        masm.load8ZeroExtend(Address(src, offset), AtomicTemp);
-        masm.store8(AtomicTemp, Address(dest, offset));
-        break;
-      case SIZE16:
-        masm.load16ZeroExtend(Address(src, offset*2), AtomicTemp);
-        masm.store16(AtomicTemp, Address(dest, offset*2));
-        break;
-      case SIZE32:
-        masm.load32(Address(src, offset*4), AtomicTemp);
-        masm.store32(AtomicTemp, Address(dest, offset*4));
-        break;
-      case SIZE64:
-#if defined(JS_64BIT)
-        masm.load64(Address(src, offset*8), AtomicTemp64);
-        masm.store64(AtomicTemp64, Address(dest, offset*8));
-        break;
-#else
-        MOZ_CRASH("64-bit atomic load/store not available on this platform");
-#endif
-      default:
-        MOZ_CRASH("Unknown size");
-    }
-    offset += direction == CopyDir::DOWN ? 1 : -1;
-  }
-
-  GenEpilogue(masm);
-  return start;
-}
-
-static uint32_t GenCmpxchg(MacroAssembler& masm, Scalar::Type size,
-                           Synchronization sync) {
-  ArgIterator iter;
-  uint32_t start = GenPrologue(masm, &iter);
-  GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
-
-  Address addr(AtomicPtrReg, 0);
-  switch (size) {
-    case SIZE8:
-    case SIZE16:
-    case SIZE32:
-      GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
-      GenGprArg(masm, MIRType::Int32, &iter, AtomicVal2Reg);
-      masm.compareExchange(size, sync, addr, AtomicValReg, AtomicVal2Reg, ReturnReg);
-      break;
-    case SIZE64:
-      GenGpr64Arg(masm, &iter, AtomicValReg64);
-      GenGpr64Arg(masm, &iter, AtomicVal2Reg64);
-#if defined(JS_CODEGEN_X86)
-      MOZ_ASSERT(AtomicValReg64 == Register64(edx, eax));
-      MOZ_ASSERT(AtomicVal2Reg64 == Register64(ecx, ebx));
-      masm.lock_cmpxchg8b(edx, eax, ecx, ebx, Operand(addr));
-
-      MOZ_ASSERT(ReturnReg64 == Register64(edi, eax));
-      masm.mov(edx, edi);
-#else
-      masm.compareExchange64(sync, addr, AtomicValReg64, AtomicVal2Reg64, ReturnReg64);
-#endif
-      break;
-    default:
-      MOZ_CRASH("Unknown size");
-  }
-
-  GenEpilogue(masm);
-  return start;
-}
-
-static uint32_t GenExchange(MacroAssembler& masm, Scalar::Type size,
-                            Synchronization sync) {
-  ArgIterator iter;
-  uint32_t start = GenPrologue(masm, &iter);
-  GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
-
-  Address addr(AtomicPtrReg, 0);
-  switch (size) {
-    case SIZE8:
-    case SIZE16:
-    case SIZE32:
-      GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
-      masm.atomicExchange(size, sync, addr, AtomicValReg, ReturnReg);
-      break;
-    case SIZE64:
-#if defined(JS_64BIT)
-      GenGpr64Arg(masm, &iter, AtomicValReg64);
-      masm.atomicExchange64(sync, addr, AtomicValReg64, ReturnReg64);
-      break;
-#else
-      MOZ_CRASH("64-bit atomic exchange not available on this platform");
-#endif
-    default:
-      MOZ_CRASH("Unknown size");
-  }
-
-  GenEpilogue(masm);
-  return start;
-}
-
-static uint32_t
-GenFetchOp(MacroAssembler& masm, Scalar::Type size, AtomicOp op,
-           Synchronization sync) {
-  ArgIterator iter;
-  uint32_t start = GenPrologue(masm, &iter);
-  GenGprArg(masm, MIRType::Pointer, &iter, AtomicPtrReg);
-
-  Address addr(AtomicPtrReg, 0);
-  switch (size) {
-    case SIZE8:
-    case SIZE16:
-    case SIZE32: {
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
-      Register tmp = op == AtomicFetchAddOp || op == AtomicFetchSubOp
-        ? Register::Invalid()
-        : AtomicTemp;
-#else
-      Register tmp = AtomicTemp;
-#endif
-      GenGprArg(masm, MIRType::Int32, &iter, AtomicValReg);
-      masm.atomicFetchOp(size, sync, op, AtomicValReg, addr, tmp, ReturnReg);
-      break;
-    }
-    case SIZE64: {
-#if defined(JS_64BIT)
-#  if defined(JS_CODEGEN_X64)
-      Register64 tmp = op == AtomicFetchAddOp || op == AtomicFetchSubOp
-        ? Register64::Invalid()
-        : AtomicTemp64;
-#  else
-      Register64 tmp = AtomicTemp64;
-#  endif
-      GenGpr64Arg(masm, &iter, AtomicValReg64);
-      masm.atomicFetchOp64(sync, op, AtomicValReg64, addr, tmp, ReturnReg64);
-      break;
-#else
-      MOZ_CRASH("64-bit atomic fetchOp not available on this platform");
-#endif
-    }
-    default:
-      MOZ_CRASH("Unknown size");
-  }
-
-  GenEpilogue(masm);
-  return start;
-}
-
-namespace js {
-namespace jit {
-
-void (*AtomicFenceSeqCst)();
-
-#ifndef JS_64BIT
-void (*AtomicCompilerFence)();
-#endif
-
-uint8_t (*AtomicLoad8SeqCst)(const uint8_t* addr);
-uint16_t (*AtomicLoad16SeqCst)(const uint16_t* addr);
-uint32_t (*AtomicLoad32SeqCst)(const uint32_t* addr);
-#ifdef JS_64BIT
-uint64_t (*AtomicLoad64SeqCst)(const uint64_t* addr);
-#endif
-
-uint8_t (*AtomicLoad8Unsynchronized)(const uint8_t* addr);
-uint16_t (*AtomicLoad16Unsynchronized)(const uint16_t* addr);
-uint32_t (*AtomicLoad32Unsynchronized)(const uint32_t* addr);
-#ifdef JS_64BIT
-uint64_t (*AtomicLoad64Unsynchronized)(const uint64_t* addr);
-#endif
-
-uint8_t (*AtomicStore8SeqCst)(uint8_t* addr, uint8_t val);
-uint16_t (*AtomicStore16SeqCst)(uint16_t* addr, uint16_t val);
-uint32_t (*AtomicStore32SeqCst)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-uint64_t (*AtomicStore64SeqCst)(uint64_t* addr, uint64_t val);
-#endif
-
-uint8_t (*AtomicStore8Unsynchronized)(uint8_t* addr, uint8_t val);
-uint16_t (*AtomicStore16Unsynchronized)(uint16_t* addr, uint16_t val);
-uint32_t (*AtomicStore32Unsynchronized)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-uint64_t (*AtomicStore64Unsynchronized)(uint64_t* addr, uint64_t val);
-#endif
-
-// See the definitions of BLOCKSIZE and WORDSIZE earlier.  The "unaligned"
-// functions perform individual byte copies (and must always be "down" or "up").
-// The others ignore alignment issues, and thus either depend on unaligned
-// accesses being OK or not being invoked on unaligned addresses.
-//
-// src and dest point to the lower addresses of the respective data areas
-// irrespective of "up" or "down".
-
-static void (*AtomicCopyUnalignedBlockDownUnsynchronized)(uint8_t* dest, const uint8_t* src);
-static void (*AtomicCopyUnalignedBlockUpUnsynchronized)(uint8_t* dest, const uint8_t* src);
-static void (*AtomicCopyUnalignedWordDownUnsynchronized)(uint8_t* dest, const uint8_t* src);
-static void (*AtomicCopyUnalignedWordUpUnsynchronized)(uint8_t* dest, const uint8_t* src);
-
-static void (*AtomicCopyBlockDownUnsynchronized)(uint8_t* dest, const uint8_t* src);
-static void (*AtomicCopyBlockUpUnsynchronized)(uint8_t* dest, const uint8_t* src);
-static void (*AtomicCopyWordUnsynchronized)(uint8_t* dest, const uint8_t* src);
-static void (*AtomicCopyByteUnsynchronized)(uint8_t* dest, const uint8_t* src);
-
-uint8_t (*AtomicCmpXchg8SeqCst)(uint8_t* addr, uint8_t oldval, uint8_t newval);
-uint16_t (*AtomicCmpXchg16SeqCst)(uint16_t* addr, uint16_t oldval, uint16_t newval);
-uint32_t (*AtomicCmpXchg32SeqCst)(uint32_t* addr, uint32_t oldval, uint32_t newval);
-uint64_t (*AtomicCmpXchg64SeqCst)(uint64_t* addr, uint64_t oldval, uint64_t newval);
-
-uint8_t (*AtomicExchange8SeqCst)(uint8_t* addr, uint8_t val);
-uint16_t (*AtomicExchange16SeqCst)(uint16_t* addr, uint16_t val);
-uint32_t (*AtomicExchange32SeqCst)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-uint64_t (*AtomicExchange64SeqCst)(uint64_t* addr, uint64_t val);
-#endif
-
-uint8_t (*AtomicAdd8SeqCst)(uint8_t* addr, uint8_t val);
-uint16_t (*AtomicAdd16SeqCst)(uint16_t* addr, uint16_t val);
-uint32_t (*AtomicAdd32SeqCst)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-uint64_t (*AtomicAdd64SeqCst)(uint64_t* addr, uint64_t val);
-#endif
-
-uint8_t (*AtomicAnd8SeqCst)(uint8_t* addr, uint8_t val);
-uint16_t (*AtomicAnd16SeqCst)(uint16_t* addr, uint16_t val);
-uint32_t (*AtomicAnd32SeqCst)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-uint64_t (*AtomicAnd64SeqCst)(uint64_t* addr, uint64_t val);
-#endif
-
-uint8_t (*AtomicOr8SeqCst)(uint8_t* addr, uint8_t val);
-uint16_t (*AtomicOr16SeqCst)(uint16_t* addr, uint16_t val);
-uint32_t (*AtomicOr32SeqCst)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-uint64_t (*AtomicOr64SeqCst)(uint64_t* addr, uint64_t val);
-#endif
-
-uint8_t (*AtomicXor8SeqCst)(uint8_t* addr, uint8_t val);
-uint16_t (*AtomicXor16SeqCst)(uint16_t* addr, uint16_t val);
-uint32_t (*AtomicXor32SeqCst)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-uint64_t (*AtomicXor64SeqCst)(uint64_t* addr, uint64_t val);
-#endif
-
-static bool UnalignedAccessesAreOK() {
-#ifdef DEBUG
-  const char* flag = getenv("JS_NO_UNALIGNED_MEMCPY");
-  if (flag && *flag == '1')
-    return false;
-#endif
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
-  return true;
-#elif defined(JS_CODEGEN_ARM)
-  return !HasAlignmentFault();
-#elif defined(JS_CODEGEN_ARM64)
-  // This is not necessarily true but it's the best guess right now.
-  return true;
-#else
-  return false;
-#endif
-}
-
-void AtomicMemcpyDownUnsynchronized(uint8_t* dest, const uint8_t* src,
-                                    size_t nbytes) {
-  const uint8_t* lim = src + nbytes;
-
-  // Set up bulk copying.  The cases are ordered the way they are on the
-  // assumption that if we can achieve aligned copies even with a little
-  // preprocessing then that is better than unaligned copying on a platform
-  // that supports it.
-
-  if (nbytes >= WORDSIZE) {
-    void (*copyBlock)(uint8_t* dest, const uint8_t* src);
-    void (*copyWord)(uint8_t* dest, const uint8_t* src);
-
-    if (((uintptr_t(dest) ^ uintptr_t(src)) & WORDMASK) == 0) {
-      const uint8_t* cutoff = (const uint8_t*)JS_ROUNDUP(uintptr_t(src),
-                                                         WORDSIZE);
-      MOZ_ASSERT(cutoff <= lim); // because nbytes >= WORDSIZE
-      while (src < cutoff) {
-        AtomicCopyByteUnsynchronized(dest++, src++);
-      }
-      copyBlock = AtomicCopyBlockDownUnsynchronized;
-      copyWord = AtomicCopyWordUnsynchronized;
-    }
-    else if (UnalignedAccessesAreOK()) {
-      copyBlock = AtomicCopyBlockDownUnsynchronized;
-      copyWord = AtomicCopyWordUnsynchronized;
-    } else {
-      copyBlock = AtomicCopyUnalignedBlockDownUnsynchronized;
-      copyWord = AtomicCopyUnalignedWordDownUnsynchronized;
-    }
-
-    // Bulk copy, first larger blocks and then individual words.
-
-    const uint8_t* blocklim = src + ((lim - src) & ~BLOCKMASK);
-    while (src < blocklim) {
-      copyBlock(dest, src);
-      dest += BLOCKSIZE;
-      src += BLOCKSIZE;
-    }
-
-    const uint8_t* wordlim = src + ((lim - src) & ~WORDMASK);
-    while (src < wordlim) {
-      copyWord(dest, src);
-      dest += WORDSIZE;
-      src += WORDSIZE;
-    }
-  }
-
-  // Byte copy any remaining tail.
-
-  while (src < lim) {
-    AtomicCopyByteUnsynchronized(dest++, src++);
-  }
-}
-
-void AtomicMemcpyUpUnsynchronized(uint8_t* dest, const uint8_t* src,
-                                  size_t nbytes) {
-  const uint8_t* lim = src;
-
-  src += nbytes;
-  dest += nbytes;
-
-  if (nbytes >= WORDSIZE) {
-    void (*copyBlock)(uint8_t* dest, const uint8_t* src);
-    void (*copyWord)(uint8_t* dest, const uint8_t* src);
-
-    if (((uintptr_t(dest) ^ uintptr_t(src)) & WORDMASK) == 0) {
-      const uint8_t* cutoff = (const uint8_t*)(uintptr_t(src) & ~WORDMASK);
-      MOZ_ASSERT(cutoff >= lim); // Because nbytes >= WORDSIZE
-      while (src > cutoff) {
-        AtomicCopyByteUnsynchronized(--dest, --src);
-      }
-      copyBlock = AtomicCopyBlockUpUnsynchronized;
-      copyWord = AtomicCopyWordUnsynchronized;
-    }
-    else if (UnalignedAccessesAreOK()) {
-      copyBlock = AtomicCopyBlockUpUnsynchronized;
-      copyWord = AtomicCopyWordUnsynchronized;
-    } else {
-      copyBlock = AtomicCopyUnalignedBlockUpUnsynchronized;
-      copyWord = AtomicCopyUnalignedWordUpUnsynchronized;
-    }
-
-    const uint8_t* blocklim = src - ((src - lim) & ~BLOCKMASK);
-    while (src > blocklim) {
-      dest -= BLOCKSIZE;
-      src -= BLOCKSIZE;
-      copyBlock(dest, src);
-    }
-
-    const uint8_t* wordlim = src - ((src - lim) & ~WORDMASK);
-    while (src > wordlim) {
-      dest -= WORDSIZE;
-      src -= WORDSIZE;
-      copyWord(dest, src);
-    }
-  }
-
-  while (src > lim) {
-    AtomicCopyByteUnsynchronized(--dest, --src);
-  }
-}
-
-// These will be read and written only by the main thread during startup and
-// shutdown.
-
-static uint8_t* codeSegment;
-static uint32_t codeSegmentSize;
-
-bool InitializeJittedAtomics() {
-  // We should only initialize once.
-  MOZ_ASSERT(!codeSegment);
-
-  LifoAlloc lifo(4096);
-  TempAllocator alloc(&lifo);
-  JitContext jcx(&alloc);
-  StackMacroAssembler masm;
-
-  uint32_t fenceSeqCst = GenFenceSeqCst(masm);
-
-#ifndef JS_64BIT
-  uint32_t nop = GenNop(masm);
-#endif
-
-  Synchronization Full = Synchronization::Full();
-  Synchronization None = Synchronization::None();
-
-  uint32_t load8SeqCst = GenLoad(masm, SIZE8, Full);
-  uint32_t load16SeqCst = GenLoad(masm, SIZE16, Full);
-  uint32_t load32SeqCst = GenLoad(masm, SIZE32, Full);
-#ifdef JS_64BIT
-  uint32_t load64SeqCst = GenLoad(masm, SIZE64, Full);
-#endif
-
-  uint32_t load8Unsynchronized = GenLoad(masm, SIZE8, None);
-  uint32_t load16Unsynchronized = GenLoad(masm, SIZE16, None);
-  uint32_t load32Unsynchronized = GenLoad(masm, SIZE32, None);
-#ifdef JS_64BIT
-  uint32_t load64Unsynchronized = GenLoad(masm, SIZE64, None);
-#endif
-
-  uint32_t store8SeqCst = GenStore(masm, SIZE8, Full);
-  uint32_t store16SeqCst = GenStore(masm, SIZE16, Full);
-  uint32_t store32SeqCst = GenStore(masm, SIZE32, Full);
-#ifdef JS_64BIT
-  uint32_t store64SeqCst = GenStore(masm, SIZE64, Full);
-#endif
-
-  uint32_t store8Unsynchronized = GenStore(masm, SIZE8, None);
-  uint32_t store16Unsynchronized = GenStore(masm, SIZE16, None);
-  uint32_t store32Unsynchronized = GenStore(masm, SIZE32, None);
-#ifdef JS_64BIT
-  uint32_t store64Unsynchronized = GenStore(masm, SIZE64, None);
-#endif
-
-  uint32_t copyUnalignedBlockDownUnsynchronized =
-    GenCopy(masm, SIZE8, BLOCKSIZE, CopyDir::DOWN);
-  uint32_t copyUnalignedBlockUpUnsynchronized =
-    GenCopy(masm, SIZE8, BLOCKSIZE, CopyDir::UP);
-  uint32_t copyUnalignedWordDownUnsynchronized =
-    GenCopy(masm, SIZE8, WORDSIZE, CopyDir::DOWN);
-  uint32_t copyUnalignedWordUpUnsynchronized =
-    GenCopy(masm, SIZE8, WORDSIZE, CopyDir::UP);
-
-  uint32_t copyBlockDownUnsynchronized =
-    GenCopy(masm, SIZEWORD, BLOCKSIZE/WORDSIZE, CopyDir::DOWN);
-  uint32_t copyBlockUpUnsynchronized =
-    GenCopy(masm, SIZEWORD, BLOCKSIZE/WORDSIZE, CopyDir::UP);
-  uint32_t copyWordUnsynchronized = GenCopy(masm, SIZEWORD, 1, CopyDir::DOWN);
-  uint32_t copyByteUnsynchronized = GenCopy(masm, SIZE8, 1, CopyDir::DOWN);
-
-  uint32_t cmpxchg8SeqCst = GenCmpxchg(masm, SIZE8, Full);
-  uint32_t cmpxchg16SeqCst = GenCmpxchg(masm, SIZE16, Full);
-  uint32_t cmpxchg32SeqCst = GenCmpxchg(masm, SIZE32, Full);
-  uint32_t cmpxchg64SeqCst = GenCmpxchg(masm, SIZE64, Full);
-
-  uint32_t exchange8SeqCst = GenExchange(masm, SIZE8, Full);
-  uint32_t exchange16SeqCst = GenExchange(masm, SIZE16, Full);
-  uint32_t exchange32SeqCst = GenExchange(masm, SIZE32, Full);
-#ifdef JS_64BIT
-  uint32_t exchange64SeqCst = GenExchange(masm, SIZE64, Full);
-#endif
-
-  uint32_t add8SeqCst = GenFetchOp(masm, SIZE8, AtomicFetchAddOp, Full);
-  uint32_t add16SeqCst = GenFetchOp(masm, SIZE16, AtomicFetchAddOp, Full);
-  uint32_t add32SeqCst = GenFetchOp(masm, SIZE32, AtomicFetchAddOp, Full);
-#ifdef JS_64BIT
-  uint32_t add64SeqCst = GenFetchOp(masm, SIZE64, AtomicFetchAddOp, Full);
-#endif
-
-  uint32_t and8SeqCst = GenFetchOp(masm, SIZE8, AtomicFetchAndOp, Full);
-  uint32_t and16SeqCst = GenFetchOp(masm, SIZE16, AtomicFetchAndOp, Full);
-  uint32_t and32SeqCst = GenFetchOp(masm, SIZE32, AtomicFetchAndOp, Full);
-#ifdef JS_64BIT
-  uint32_t and64SeqCst = GenFetchOp(masm, SIZE64, AtomicFetchAndOp, Full);
-#endif
-
-  uint32_t or8SeqCst = GenFetchOp(masm, SIZE8, AtomicFetchOrOp, Full);
-  uint32_t or16SeqCst = GenFetchOp(masm, SIZE16, AtomicFetchOrOp, Full);
-  uint32_t or32SeqCst = GenFetchOp(masm, SIZE32, AtomicFetchOrOp, Full);
-#ifdef JS_64BIT
-  uint32_t or64SeqCst = GenFetchOp(masm, SIZE64, AtomicFetchOrOp, Full);
-#endif
-
-  uint32_t xor8SeqCst = GenFetchOp(masm, SIZE8, AtomicFetchXorOp, Full);
-  uint32_t xor16SeqCst = GenFetchOp(masm, SIZE16, AtomicFetchXorOp, Full);
-  uint32_t xor32SeqCst = GenFetchOp(masm, SIZE32, AtomicFetchXorOp, Full);
-#ifdef JS_64BIT
-  uint32_t xor64SeqCst = GenFetchOp(masm, SIZE64, AtomicFetchXorOp, Full);
-#endif
-
-  masm.finish();
-  if (masm.oom()) {
-    return false;
-  }
-
-  // Allocate executable memory.
-  uint32_t codeLength = masm.bytesNeeded();
-  size_t roundedCodeLength = JS_ROUNDUP(codeLength, ExecutableCodePageSize);
-  uint8_t* code =
-    (uint8_t*)AllocateExecutableMemory(roundedCodeLength,
-                                       ProtectionSetting::Writable,
-                                       MemCheckKind::MakeUndefined);
-  if (!code) {
-    return false;
-  }
-
-  // Zero the padding.
-  memset(code + codeLength, 0, roundedCodeLength - codeLength);
-
-  // Copy the code into place but do not flush, as the flush path requires a
-  // JSContext* we do not have.
-  masm.executableCopy(code, /* flushICache = */ false);
-
-  // Flush the icache using a primitive method.
-  ExecutableAllocator::cacheFlush(code, roundedCodeLength);
-
-  // Reprotect the whole region to avoid having separate RW and RX mappings.
-  if (!ExecutableAllocator::makeExecutable(code, roundedCodeLength)) {
-    DeallocateExecutableMemory(code, roundedCodeLength);
-    return false;
-  }
-
-  // Create the function pointers.
-
-  AtomicFenceSeqCst = (void(*)())(code + fenceSeqCst);
-
-#ifndef JS_64BIT
-  AtomicCompilerFence = (void(*)())(code + nop);
-#endif
-
-  AtomicLoad8SeqCst = (uint8_t(*)(const uint8_t* addr))(code + load8SeqCst);
-  AtomicLoad16SeqCst = (uint16_t(*)(const uint16_t* addr))(code + load16SeqCst);
-  AtomicLoad32SeqCst = (uint32_t(*)(const uint32_t* addr))(code + load32SeqCst);
-#ifdef JS_64BIT
-  AtomicLoad64SeqCst = (uint64_t(*)(const uint64_t* addr))(code + load64SeqCst);
-#endif
-
-  AtomicLoad8Unsynchronized =
-    (uint8_t(*)(const uint8_t* addr))(code + load8Unsynchronized);
-  AtomicLoad16Unsynchronized =
-    (uint16_t(*)(const uint16_t* addr))(code + load16Unsynchronized);
-  AtomicLoad32Unsynchronized =
-    (uint32_t(*)(const uint32_t* addr))(code + load32Unsynchronized);
-#ifdef JS_64BIT
-  AtomicLoad64Unsynchronized =
-    (uint64_t(*)(const uint64_t* addr))(code + load64Unsynchronized);
-#endif
-
-  AtomicStore8SeqCst =
-    (uint8_t(*)(uint8_t* addr, uint8_t val))(code + store8SeqCst);
-  AtomicStore16SeqCst =
-    (uint16_t(*)(uint16_t* addr, uint16_t val))(code + store16SeqCst);
-  AtomicStore32SeqCst =
-    (uint32_t(*)(uint32_t* addr, uint32_t val))(code + store32SeqCst);
-#ifdef JS_64BIT
-  AtomicStore64SeqCst =
-    (uint64_t(*)(uint64_t* addr, uint64_t val))(code + store64SeqCst);
-#endif
-
-  AtomicStore8Unsynchronized =
-    (uint8_t(*)(uint8_t* addr, uint8_t val))(code + store8Unsynchronized);
-  AtomicStore16Unsynchronized =
-    (uint16_t(*)(uint16_t* addr, uint16_t val))(code + store16Unsynchronized);
-  AtomicStore32Unsynchronized =
-    (uint32_t(*)(uint32_t* addr, uint32_t val))(code + store32Unsynchronized);
-#ifdef JS_64BIT
-  AtomicStore64Unsynchronized =
-    (uint64_t(*)(uint64_t* addr, uint64_t val))(code + store64Unsynchronized);
-#endif
-
-  AtomicCopyUnalignedBlockDownUnsynchronized =
-    (void(*)(uint8_t* dest, const uint8_t* src))(
-      code + copyUnalignedBlockDownUnsynchronized);
-  AtomicCopyUnalignedBlockUpUnsynchronized =
-    (void(*)(uint8_t* dest, const uint8_t* src))(
-      code + copyUnalignedBlockUpUnsynchronized);
-  AtomicCopyUnalignedWordDownUnsynchronized =
-    (void(*)(uint8_t* dest, const uint8_t* src))(
-      code + copyUnalignedWordDownUnsynchronized);
-  AtomicCopyUnalignedWordUpUnsynchronized =
-    (void(*)(uint8_t* dest, const uint8_t* src))(
-      code + copyUnalignedWordUpUnsynchronized);
-
-  AtomicCopyBlockDownUnsynchronized =
-    (void(*)(uint8_t* dest, const uint8_t* src))(
-      code + copyBlockDownUnsynchronized);
-  AtomicCopyBlockUpUnsynchronized =
-    (void(*)(uint8_t* dest, const uint8_t* src))(
-      code + copyBlockUpUnsynchronized);
-  AtomicCopyWordUnsynchronized =
-    (void(*)(uint8_t* dest, const uint8_t* src))(code + copyWordUnsynchronized);
-  AtomicCopyByteUnsynchronized =
-    (void(*)(uint8_t* dest, const uint8_t* src))(code + copyByteUnsynchronized);
-
-  AtomicCmpXchg8SeqCst =
-    (uint8_t(*)(uint8_t* addr, uint8_t oldval, uint8_t newval))(
-      code + cmpxchg8SeqCst);
-  AtomicCmpXchg16SeqCst =
-    (uint16_t(*)(uint16_t* addr, uint16_t oldval, uint16_t newval))(
-      code + cmpxchg16SeqCst);
-  AtomicCmpXchg32SeqCst =
-    (uint32_t(*)(uint32_t* addr, uint32_t oldval, uint32_t newval))(
-      code + cmpxchg32SeqCst);
-  AtomicCmpXchg64SeqCst =
-    (uint64_t(*)(uint64_t* addr, uint64_t oldval, uint64_t newval))(
-      code + cmpxchg64SeqCst);
-
-  AtomicExchange8SeqCst = (uint8_t(*)(uint8_t* addr, uint8_t val))(
-    code + exchange8SeqCst);
-  AtomicExchange16SeqCst = (uint16_t(*)(uint16_t* addr, uint16_t val))(
-    code + exchange16SeqCst);
-  AtomicExchange32SeqCst = (uint32_t(*)(uint32_t* addr, uint32_t val))(
-    code + exchange32SeqCst);
-#ifdef JS_64BIT
-  AtomicExchange64SeqCst = (uint64_t(*)(uint64_t* addr, uint64_t val))(
-    code + exchange64SeqCst);
-#endif
-
-  AtomicAdd8SeqCst =
-    (uint8_t(*)(uint8_t* addr, uint8_t val))(code + add8SeqCst);
-  AtomicAdd16SeqCst =
-    (uint16_t(*)(uint16_t* addr, uint16_t val))(code + add16SeqCst);
-  AtomicAdd32SeqCst =
-    (uint32_t(*)(uint32_t* addr, uint32_t val))(code + add32SeqCst);
-#ifdef JS_64BIT
-  AtomicAdd64SeqCst =
-    (uint64_t(*)(uint64_t* addr, uint64_t val))(code + add64SeqCst);
-#endif
-
-  AtomicAnd8SeqCst =
-    (uint8_t(*)(uint8_t* addr, uint8_t val))(code + and8SeqCst);
-  AtomicAnd16SeqCst =
-    (uint16_t(*)(uint16_t* addr, uint16_t val))(code + and16SeqCst);
-  AtomicAnd32SeqCst =
-    (uint32_t(*)(uint32_t* addr, uint32_t val))(code + and32SeqCst);
-#ifdef JS_64BIT
-  AtomicAnd64SeqCst =
-    (uint64_t(*)(uint64_t* addr, uint64_t val))(code + and64SeqCst);
-#endif
-
-  AtomicOr8SeqCst =
-    (uint8_t(*)(uint8_t* addr, uint8_t val))(code + or8SeqCst);
-  AtomicOr16SeqCst =
-    (uint16_t(*)(uint16_t* addr, uint16_t val))(code + or16SeqCst);
-  AtomicOr32SeqCst =
-    (uint32_t(*)(uint32_t* addr, uint32_t val))(code + or32SeqCst);
-#ifdef JS_64BIT
-  AtomicOr64SeqCst =
-    (uint64_t(*)(uint64_t* addr, uint64_t val))(code + or64SeqCst);
-#endif
-
-  AtomicXor8SeqCst =
-    (uint8_t(*)(uint8_t* addr, uint8_t val))(code + xor8SeqCst);
-  AtomicXor16SeqCst =
-    (uint16_t(*)(uint16_t* addr, uint16_t val))(code + xor16SeqCst);
-  AtomicXor32SeqCst =
-    (uint32_t(*)(uint32_t* addr, uint32_t val))(code + xor32SeqCst);
-#ifdef JS_64BIT
-  AtomicXor64SeqCst =
-    (uint64_t(*)(uint64_t* addr, uint64_t val))(code + xor64SeqCst);
-#endif
-
-  codeSegment = code;
-  codeSegmentSize = roundedCodeLength;
-
-  return true;
-}
-
-void ShutDownJittedAtomics() {
-  // Must have been initialized.
-  MOZ_ASSERT(codeSegment);
-
-  DeallocateExecutableMemory(codeSegment, codeSegmentSize);
-  codeSegment = nullptr;
-  codeSegmentSize = 0;
-}
-
-} // jit
-} // js
deleted file mode 100644
--- a/js/src/jit/shared/AtomicOperations-shared-jit.h
+++ /dev/null
@@ -1,605 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* For overall documentation, see jit/AtomicOperations.h.
- *
- * NOTE CAREFULLY: This file is only applicable when we have configured a JIT
- * and the JIT is for the same architecture that we're compiling the shell for.
- * Simulators must use a different mechanism.
- *
- * See comments before the include nest near the end of jit/AtomicOperations.h
- * if you didn't understand that.
- */
-
-#ifndef jit_shared_AtomicOperations_shared_jit_h
-#define jit_shared_AtomicOperations_shared_jit_h
-
-#include "mozilla/Assertions.h"
-#include "mozilla/Types.h"
-
-#include "jsapi.h"
-
-#include "vm/ArrayBufferObject.h"
-
-namespace js {
-namespace jit {
-
-// The function pointers in this section all point to jitted code.
-//
-// On 32-bit systems we assume for simplicity's sake that we don't have any
-// 64-bit atomic operations except cmpxchg (this is a concession to x86 but it's
-// not a hardship).  On 32-bit systems we therefore implement other 64-bit
-// atomic operations in terms of cmpxchg along with some C++ code and a local
-// reordering fence to prevent other loads and stores from being intermingled
-// with operations in the implementation of the atomic.
-
-// `fence` performs a full memory barrier.
-extern void (*AtomicFenceSeqCst)();
-
-#ifndef JS_64BIT
-// `compiler_fence` erects a reordering boundary for operations on the current
-// thread.  We use it to prevent the compiler from reordering loads and stores
-// inside larger primitives that are synthesized from cmpxchg.
-extern void (*AtomicCompilerFence)();
-#endif
-
-extern uint8_t (*AtomicLoad8SeqCst)(const uint8_t* addr);
-extern uint16_t (*AtomicLoad16SeqCst)(const uint16_t* addr);
-extern uint32_t (*AtomicLoad32SeqCst)(const uint32_t* addr);
-#ifdef JS_64BIT
-extern uint64_t (*AtomicLoad64SeqCst)(const uint64_t* addr);
-#endif
-
-// These are access-atomic up to sizeof(uintptr_t).
-extern uint8_t (*AtomicLoad8Unsynchronized)(const uint8_t* addr);
-extern uint16_t (*AtomicLoad16Unsynchronized)(const uint16_t* addr);
-extern uint32_t (*AtomicLoad32Unsynchronized)(const uint32_t* addr);
-#ifdef JS_64BIT
-extern uint64_t (*AtomicLoad64Unsynchronized)(const uint64_t* addr);
-#endif
-
-extern uint8_t (*AtomicStore8SeqCst)(uint8_t* addr, uint8_t val);
-extern uint16_t (*AtomicStore16SeqCst)(uint16_t* addr, uint16_t val);
-extern uint32_t (*AtomicStore32SeqCst)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-extern uint64_t (*AtomicStore64SeqCst)(uint64_t* addr, uint64_t val);
-#endif
-
-// These are access-atomic up to sizeof(uintptr_t).
-extern uint8_t (*AtomicStore8Unsynchronized)(uint8_t* addr, uint8_t val);
-extern uint16_t (*AtomicStore16Unsynchronized)(uint16_t* addr, uint16_t val);
-extern uint32_t (*AtomicStore32Unsynchronized)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-extern uint64_t (*AtomicStore64Unsynchronized)(uint64_t* addr, uint64_t val);
-#endif
-
-// `exchange` takes a cell address and a value.  It stores it in the cell and
-// returns the value previously in the cell.
-extern uint8_t (*AtomicExchange8SeqCst)(uint8_t* addr, uint8_t val);
-extern uint16_t (*AtomicExchange16SeqCst)(uint16_t* addr, uint16_t val);
-extern uint32_t (*AtomicExchange32SeqCst)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-extern uint64_t (*AtomicExchange64SeqCst)(uint64_t* addr, uint64_t val);
-#endif
-
-// `add` adds a value atomically to the cell and returns the old value in the
-// cell.  (There is no `sub`; just add the negated value.)
-extern uint8_t (*AtomicAdd8SeqCst)(uint8_t* addr, uint8_t val);
-extern uint16_t (*AtomicAdd16SeqCst)(uint16_t* addr, uint16_t val);
-extern uint32_t (*AtomicAdd32SeqCst)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-extern uint64_t (*AtomicAdd64SeqCst)(uint64_t* addr, uint64_t val);
-#endif
-
-// `and` bitwise-ands a value atomically into the cell and returns the old value
-// in the cell.
-extern uint8_t (*AtomicAnd8SeqCst)(uint8_t* addr, uint8_t val);
-extern uint16_t (*AtomicAnd16SeqCst)(uint16_t* addr, uint16_t val);
-extern uint32_t (*AtomicAnd32SeqCst)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-extern uint64_t (*AtomicAnd64SeqCst)(uint64_t* addr, uint64_t val);
-#endif
-
-// `or` bitwise-ors a value atomically into the cell and returns the old value
-// in the cell.
-extern uint8_t (*AtomicOr8SeqCst)(uint8_t* addr, uint8_t val);
-extern uint16_t (*AtomicOr16SeqCst)(uint16_t* addr, uint16_t val);
-extern uint32_t (*AtomicOr32SeqCst)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-extern uint64_t (*AtomicOr64SeqCst)(uint64_t* addr, uint64_t val);
-#endif
-
-// `xor` bitwise-xors a value atomically into the cell and returns the old value
-// in the cell.
-extern uint8_t (*AtomicXor8SeqCst)(uint8_t* addr, uint8_t val);
-extern uint16_t (*AtomicXor16SeqCst)(uint16_t* addr, uint16_t val);
-extern uint32_t (*AtomicXor32SeqCst)(uint32_t* addr, uint32_t val);
-#ifdef JS_64BIT
-extern uint64_t (*AtomicXor64SeqCst)(uint64_t* addr, uint64_t val);
-#endif
-
-// `cmpxchg` takes a cell address, an expected value and a replacement value.
-// If the value in the cell equals the expected value then the replacement value
-// is stored in the cell.  It always returns the value previously in the cell.
-extern uint8_t (*AtomicCmpXchg8SeqCst)(uint8_t* addr, uint8_t oldval, uint8_t newval);
-extern uint16_t (*AtomicCmpXchg16SeqCst)(uint16_t* addr, uint16_t oldval, uint16_t newval);
-extern uint32_t (*AtomicCmpXchg32SeqCst)(uint32_t* addr, uint32_t oldval, uint32_t newval);
-extern uint64_t (*AtomicCmpXchg64SeqCst)(uint64_t* addr, uint64_t oldval, uint64_t newval);
-
-// `...MemcpyDown` moves bytes toward lower addresses in memory: dest <= src.
-// `...MemcpyUp` moves bytes toward higher addresses in memory: dest >= src.
-extern void AtomicMemcpyDownUnsynchronized(uint8_t* dest, const uint8_t* src, size_t nbytes);
-extern void AtomicMemcpyUpUnsynchronized(uint8_t* dest, const uint8_t* src, size_t nbytes);
-
-} }
-
-inline bool js::jit::AtomicOperations::hasAtomic8() {
-  return true;
-}
-
-inline bool js::jit::AtomicOperations::isLockfree8() {
-  return true;
-}
-
-inline void
-js::jit::AtomicOperations::fenceSeqCst() {
-  AtomicFenceSeqCst();
-}
-
-#define JIT_LOADOP(T, U, loadop)                            \
-  template<> inline T                                       \
-  AtomicOperations::loadSeqCst(T* addr) {                   \
-    JS::AutoSuppressGCAnalysis nogc;                        \
-    return (T)loadop((U*)addr);                             \
-  }
-
-#ifndef JS_64BIT
-#  define JIT_LOADOP_CAS(T)                                     \
-  template<>                                                    \
-  inline T                                                      \
-  AtomicOperations::loadSeqCst(T* addr) {                       \
-    JS::AutoSuppressGCAnalysis nogc;                            \
-    AtomicCompilerFence();                                      \
-    return (T)AtomicCmpXchg64SeqCst((uint64_t*)addr, 0, 0);     \
-  }
-#endif // !JS_64BIT
-
-namespace js {
-namespace jit {
-
-JIT_LOADOP(int8_t, uint8_t, AtomicLoad8SeqCst)
-JIT_LOADOP(uint8_t, uint8_t, AtomicLoad8SeqCst)
-JIT_LOADOP(int16_t, uint16_t, AtomicLoad16SeqCst)
-JIT_LOADOP(uint16_t, uint16_t, AtomicLoad16SeqCst)
-JIT_LOADOP(int32_t, uint32_t, AtomicLoad32SeqCst)
-JIT_LOADOP(uint32_t, uint32_t, AtomicLoad32SeqCst)
-
-#ifdef JIT_LOADOP_CAS
-JIT_LOADOP_CAS(int64_t)
-JIT_LOADOP_CAS(uint64_t)
-#else
-JIT_LOADOP(int64_t, uint64_t, AtomicLoad64SeqCst)
-JIT_LOADOP(uint64_t, uint64_t, AtomicLoad64SeqCst)
-#endif
-
-}}
-
-#undef JIT_LOADOP
-#undef JIT_LOADOP_CAS
-
-#define JIT_STOREOP(T, U, storeop)                      \
-  template<> inline void                                \
-  AtomicOperations::storeSeqCst(T* addr, T val) {       \
-    JS::AutoSuppressGCAnalysis nogc;                    \
-    storeop((U*)addr, val);                             \
-  }
-
-#ifndef JS_64BIT
-#  define JIT_STOREOP_CAS(T)                                          \
-  template<>                                                          \
-  inline void                                                         \
-  AtomicOperations::storeSeqCst(T* addr, T val) {                     \
-    JS::AutoSuppressGCAnalysis nogc;                                  \
-    AtomicCompilerFence();                                            \
-    T oldval = *addr; /* good initial approximation */                \
-    for (;;) {                                                        \
-      T nextval = (T)AtomicCmpXchg64SeqCst((uint64_t*)addr,           \
-                                           (uint64_t)oldval,          \
-                                           (uint64_t)val);            \
-      if (nextval == oldval) {                                        \
-        break;                                                        \
-      }                                                               \
-      oldval = nextval;                                               \
-    }                                                                 \
-    AtomicCompilerFence();                                            \
-  }
-#endif // !JS_64BIT
-
-namespace js {
-namespace jit {
-
-JIT_STOREOP(int8_t, uint8_t, AtomicStore8SeqCst)
-JIT_STOREOP(uint8_t, uint8_t, AtomicStore8SeqCst)
-JIT_STOREOP(int16_t, uint16_t, AtomicStore16SeqCst)
-JIT_STOREOP(uint16_t, uint16_t, AtomicStore16SeqCst)
-JIT_STOREOP(int32_t, uint32_t, AtomicStore32SeqCst)
-JIT_STOREOP(uint32_t, uint32_t, AtomicStore32SeqCst)
-
-#ifdef JIT_STOREOP_CAS
-JIT_STOREOP_CAS(int64_t)
-JIT_STOREOP_CAS(uint64_t)
-#else
-JIT_STOREOP(int64_t, uint64_t, AtomicStore64SeqCst)
-JIT_STOREOP(uint64_t, uint64_t, AtomicStore64SeqCst)
-#endif
-
-}}
-
-#undef JIT_STOREOP
-#undef JIT_STOREOP_CAS
-
-#define JIT_EXCHANGEOP(T, U, xchgop)                            \
-  template<> inline T                                           \
-  AtomicOperations::exchangeSeqCst(T* addr, T val) {            \
-    JS::AutoSuppressGCAnalysis nogc;                            \
-    return (T)xchgop((U*)addr, (U)val);                         \
-  }
-
-#ifndef JS_64BIT
-#  define JIT_EXCHANGEOP_CAS(T)                                       \
-  template<> inline T                                                 \
-  AtomicOperations::exchangeSeqCst(T* addr, T val) {                  \
-    JS::AutoSuppressGCAnalysis nogc;                                  \
-    AtomicCompilerFence();                                            \
-    T oldval = *addr;                                                 \
-    for (;;) {                                                        \
-      T nextval = (T)AtomicCmpXchg64SeqCst((uint64_t*)addr,           \
-                                           (uint64_t)oldval,          \
-                                           (uint64_t)val);            \
-      if (nextval == oldval) {                                        \
-        break;                                                        \
-      }                                                               \
-      oldval = nextval;                                               \
-    }                                                                 \
-    AtomicCompilerFence();                                            \
-    return oldval;                                                    \
-  }
-#endif // !JS_64BIT
-
-namespace js {
-namespace jit {
-
-JIT_EXCHANGEOP(int8_t, uint8_t, AtomicExchange8SeqCst)
-JIT_EXCHANGEOP(uint8_t, uint8_t, AtomicExchange8SeqCst)
-JIT_EXCHANGEOP(int16_t, uint16_t, AtomicExchange16SeqCst)
-JIT_EXCHANGEOP(uint16_t, uint16_t, AtomicExchange16SeqCst)
-JIT_EXCHANGEOP(int32_t, uint32_t, AtomicExchange32SeqCst)
-JIT_EXCHANGEOP(uint32_t, uint32_t, AtomicExchange32SeqCst)
-
-#ifdef JIT_EXCHANGEOP_CAS
-JIT_EXCHANGEOP_CAS(int64_t)
-JIT_EXCHANGEOP_CAS(uint64_t)
-#else
-JIT_EXCHANGEOP(int64_t, uint64_t, AtomicExchange64SeqCst)
-JIT_EXCHANGEOP(uint64_t, uint64_t, AtomicExchange64SeqCst)
-#endif
-
-}}
-
-#undef JIT_EXCHANGEOP
-#undef JIT_EXCHANGEOP_CAS
-
-#define JIT_CAS(T, U, cmpxchg)                                          \
-  template<> inline T                                                   \
-  AtomicOperations::compareExchangeSeqCst(T* addr, T oldval, T newval) { \
-    JS::AutoSuppressGCAnalysis nogc;                                    \
-    return (T)cmpxchg((U*)addr, (U)oldval, (U)newval);                  \
-  }
-
-namespace js {
-namespace jit {
-
-JIT_CAS(int8_t, uint8_t, AtomicCmpXchg8SeqCst)
-JIT_CAS(uint8_t, uint8_t, AtomicCmpXchg8SeqCst)
-JIT_CAS(int16_t, uint16_t, AtomicCmpXchg16SeqCst)
-JIT_CAS(uint16_t, uint16_t, AtomicCmpXchg16SeqCst)
-JIT_CAS(int32_t, uint32_t, AtomicCmpXchg32SeqCst)
-JIT_CAS(uint32_t, uint32_t, AtomicCmpXchg32SeqCst)
-JIT_CAS(int64_t, uint64_t, AtomicCmpXchg64SeqCst)
-JIT_CAS(uint64_t, uint64_t, AtomicCmpXchg64SeqCst)
-
-}}
-
-#undef JIT_CAS
-
-#define JIT_FETCHADDOP(T, U, xadd)                                   \
-  template<> inline T                                                \
-  AtomicOperations::fetchAddSeqCst(T* addr, T val) {                 \
-    JS::AutoSuppressGCAnalysis nogc;                                 \
-    return (T)xadd((U*)addr, (U)val);                                \
-  }                                                                  \
-
-#define JIT_FETCHSUBOP(T)                                            \
-  template<> inline T                                                \
-  AtomicOperations::fetchSubSeqCst(T* addr, T val) {                 \
-    JS::AutoSuppressGCAnalysis nogc;                                 \
-    return fetchAddSeqCst(addr, (T)(0-val));                         \
-  }
-
-#ifndef JS_64BIT
-#  define JIT_FETCHADDOP_CAS(T)                                         \
-  template<> inline T                                                   \
-  AtomicOperations::fetchAddSeqCst(T* addr, T val) {                    \
-    JS::AutoSuppressGCAnalysis nogc;                                    \
-    AtomicCompilerFence();                                              \
-    T oldval = *addr; /* Good initial approximation */                  \
-    for (;;) {                                                          \
-      T nextval = (T)AtomicCmpXchg64SeqCst((uint64_t*)addr,             \
-                                           (uint64_t)oldval,            \
-                                           (uint64_t)(oldval + val));   \
-      if (nextval == oldval) {                                          \
-        break;                                                          \
-      }                                                                 \
-      oldval = nextval;                                                 \
-    }                                                                   \
-    AtomicCompilerFence();                                              \
-    return oldval;                                                      \
-  }
-#endif // !JS_64BIT
-
-namespace js {
-namespace jit {
-
-JIT_FETCHADDOP(int8_t, uint8_t, AtomicAdd8SeqCst)
-JIT_FETCHADDOP(uint8_t, uint8_t, AtomicAdd8SeqCst)
-JIT_FETCHADDOP(int16_t, uint16_t, AtomicAdd16SeqCst)
-JIT_FETCHADDOP(uint16_t, uint16_t, AtomicAdd16SeqCst)
-JIT_FETCHADDOP(int32_t, uint32_t, AtomicAdd32SeqCst)
-JIT_FETCHADDOP(uint32_t, uint32_t, AtomicAdd32SeqCst)
-
-#ifdef JIT_FETCHADDOP_CAS
-JIT_FETCHADDOP_CAS(int64_t)
-JIT_FETCHADDOP_CAS(uint64_t)
-#else
-JIT_FETCHADDOP(int64_t,  uint64_t, AtomicAdd64SeqCst)
-JIT_FETCHADDOP(uint64_t, uint64_t, AtomicAdd64SeqCst)
-#endif
-
-JIT_FETCHSUBOP(int8_t)
-JIT_FETCHSUBOP(uint8_t)
-JIT_FETCHSUBOP(int16_t)
-JIT_FETCHSUBOP(uint16_t)
-JIT_FETCHSUBOP(int32_t)
-JIT_FETCHSUBOP(uint32_t)
-JIT_FETCHSUBOP(int64_t)
-JIT_FETCHSUBOP(uint64_t)
-
-}}
-
-#undef JIT_FETCHADDOP
-#undef JIT_FETCHADDOP_CAS
-#undef JIT_FETCHSUBOP
-
-#define JIT_FETCHBITOPX(T, U, name, op)                                 \
-  template<> inline T                                                   \
-  AtomicOperations::name(T* addr, T val) {                              \
-    JS::AutoSuppressGCAnalysis nogc;                                    \
-    return (T)op((U *)addr, (U)val);                                    \
-  }
-
-#define JIT_FETCHBITOP(T, U, andop, orop, xorop)                        \
-  JIT_FETCHBITOPX(T, U, fetchAndSeqCst, andop)                          \
-  JIT_FETCHBITOPX(T, U, fetchOrSeqCst, orop)                            \
-  JIT_FETCHBITOPX(T, U, fetchXorSeqCst, xorop)
-
-#ifndef JS_64BIT
-
-#  define AND_OP &
-#  define OR_OP  |
-#  define XOR_OP ^
-
-#  define JIT_FETCHBITOPX_CAS(T, name, OP)                              \
-  template<> inline T                                                   \
-  AtomicOperations::name(T* addr, T val) {                              \
-    JS::AutoSuppressGCAnalysis nogc;                                    \
-    AtomicCompilerFence();                                              \
-    T oldval = *addr;                                                   \
-    for (;;) {                                                          \
-      T nextval = (T)AtomicCmpXchg64SeqCst((uint64_t*)addr,             \
-                                           (uint64_t)oldval,            \
-                                           (uint64_t)(oldval OP val));  \
-      if (nextval == oldval) {                                          \
-        break;                                                          \
-      }                                                                 \
-      oldval = nextval;                                                 \
-    }                                                                   \
-    AtomicCompilerFence();                                              \
-    return oldval;                                                      \
-  }
-
-#  define JIT_FETCHBITOP_CAS(T)                                      \
-  JIT_FETCHBITOPX_CAS(T, fetchAndSeqCst, AND_OP)                     \
-  JIT_FETCHBITOPX_CAS(T, fetchOrSeqCst, OR_OP)                       \
-  JIT_FETCHBITOPX_CAS(T, fetchXorSeqCst, XOR_OP)
-
-#endif  // !JS_64BIT
-
-namespace js {
-namespace jit {
-
-JIT_FETCHBITOP(int8_t, uint8_t, AtomicAnd8SeqCst, AtomicOr8SeqCst, AtomicXor8SeqCst)
-JIT_FETCHBITOP(uint8_t, uint8_t, AtomicAnd8SeqCst, AtomicOr8SeqCst, AtomicXor8SeqCst)
-JIT_FETCHBITOP(int16_t, uint16_t, AtomicAnd16SeqCst, AtomicOr16SeqCst, AtomicXor16SeqCst)
-JIT_FETCHBITOP(uint16_t, uint16_t, AtomicAnd16SeqCst, AtomicOr16SeqCst, AtomicXor16SeqCst)
-JIT_FETCHBITOP(int32_t, uint32_t,  AtomicAnd32SeqCst, AtomicOr32SeqCst, AtomicXor32SeqCst)
-JIT_FETCHBITOP(uint32_t, uint32_t, AtomicAnd32SeqCst, AtomicOr32SeqCst, AtomicXor32SeqCst)
-
-#ifdef JIT_FETCHBITOP_CAS
-JIT_FETCHBITOP_CAS(int64_t)
-JIT_FETCHBITOP_CAS(uint64_t)
-#else
-JIT_FETCHBITOP(int64_t,  uint64_t, AtomicAnd64SeqCst, AtomicOr64SeqCst, AtomicXor64SeqCst)
-JIT_FETCHBITOP(uint64_t, uint64_t, AtomicAnd64SeqCst, AtomicOr64SeqCst, AtomicXor64SeqCst)
-#endif
-
-}}
-
-#undef JIT_FETCHBITOPX_CAS
-#undef JIT_FETCHBITOPX
-#undef JIT_FETCHBITOP_CAS
-#undef JIT_FETCHBITOP
-
-#define JIT_LOADSAFE(T, U, loadop)                              \
-  template<>                                                    \
-  inline T                                                      \
-  js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {        \
-    JS::AutoSuppressGCAnalysis nogc;                            \
-    union { U u; T t; };                                        \
-    u = loadop((U*)addr);                                       \
-    return t;                                                   \
-  }
-
-#ifndef JS_64BIT
-#  define JIT_LOADSAFE_TEARING(T)                               \
-  template<>                                                    \
-  inline T                                                      \
-  js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {        \
-    JS::AutoSuppressGCAnalysis nogc;                            \
-    MOZ_ASSERT(sizeof(T) == 8);                                 \
-    union { uint32_t u[2]; T t; };                              \
-    uint32_t* ptr = (uint32_t*)addr;                            \
-    u[0] = AtomicLoad32Unsynchronized(ptr);                     \
-    u[1] = AtomicLoad32Unsynchronized(ptr + 1);                 \
-    return t;                                                   \
-  }
-#endif // !JS_64BIT
-
-namespace js {
-namespace jit {
-
-JIT_LOADSAFE(int8_t,   uint8_t, AtomicLoad8Unsynchronized)
-JIT_LOADSAFE(uint8_t,  uint8_t, AtomicLoad8Unsynchronized)
-JIT_LOADSAFE(int16_t,  uint16_t, AtomicLoad16Unsynchronized)
-JIT_LOADSAFE(uint16_t, uint16_t, AtomicLoad16Unsynchronized)
-JIT_LOADSAFE(int32_t,  uint32_t, AtomicLoad32Unsynchronized)
-JIT_LOADSAFE(uint32_t, uint32_t, AtomicLoad32Unsynchronized)
-#ifdef JIT_LOADSAFE_TEARING
-JIT_LOADSAFE_TEARING(int64_t)
-JIT_LOADSAFE_TEARING(uint64_t)
-JIT_LOADSAFE_TEARING(double)
-#else
-JIT_LOADSAFE(int64_t,  uint64_t, AtomicLoad64Unsynchronized)
-JIT_LOADSAFE(uint64_t, uint64_t, AtomicLoad64Unsynchronized)
-JIT_LOADSAFE(double,   uint64_t, AtomicLoad64Unsynchronized)
-#endif
-JIT_LOADSAFE(float,    uint32_t, AtomicLoad32Unsynchronized)
-
-// Clang requires a specialization for uint8_clamped.
-template<>
-inline uint8_clamped js::jit::AtomicOperations::loadSafeWhenRacy(
-  uint8_clamped* addr) {
-  return uint8_clamped(loadSafeWhenRacy((uint8_t*)addr));
-}
-
-}}
-
-#undef JIT_LOADSAFE
-#undef JIT_LOADSAFE_TEARING
-
-#define JIT_STORESAFE(T, U, storeop)                               \
-  template<>                                                       \
-  inline void                                                      \
-  js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {   \
-    JS::AutoSuppressGCAnalysis nogc;                               \
-    union { U u; T t; };                                           \
-    t = val;                                                       \
-    storeop((U*)addr, u);                                          \
-  }
-
-#ifndef JS_64BIT
-#  define JIT_STORESAFE_TEARING(T)                                    \
-  template<>                                                          \
-  inline void                                                         \
-  js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {      \
-    JS::AutoSuppressGCAnalysis nogc;                                  \
-    union { uint32_t u[2]; T t; };                                    \
-    t = val;                                                          \
-    uint32_t* ptr = (uint32_t*)addr;                                  \
-    AtomicStore32Unsynchronized(ptr, u[0]);                           \
-    AtomicStore32Unsynchronized(ptr + 1, u[1]);                       \
-  }
-#endif // !JS_64BIT
-
-namespace js {
-namespace jit {
-
-JIT_STORESAFE(int8_t,   uint8_t, AtomicStore8Unsynchronized)
-JIT_STORESAFE(uint8_t,  uint8_t, AtomicStore8Unsynchronized)
-JIT_STORESAFE(int16_t,  uint16_t, AtomicStore16Unsynchronized)
-JIT_STORESAFE(uint16_t, uint16_t, AtomicStore16Unsynchronized)
-JIT_STORESAFE(int32_t,  uint32_t, AtomicStore32Unsynchronized)
-JIT_STORESAFE(uint32_t, uint32_t, AtomicStore32Unsynchronized)
-#ifdef JIT_STORESAFE_TEARING
-JIT_STORESAFE_TEARING(int64_t)
-JIT_STORESAFE_TEARING(uint64_t)
-JIT_STORESAFE_TEARING(double)
-#else
-JIT_STORESAFE(int64_t,  uint64_t, AtomicStore64Unsynchronized)
-JIT_STORESAFE(uint64_t, uint64_t, AtomicStore64Unsynchronized)
-JIT_STORESAFE(double,   uint64_t, AtomicStore64Unsynchronized)
-#endif
-JIT_STORESAFE(float,    uint32_t, AtomicStore32Unsynchronized)
-
-// Clang requires a specialization for uint8_clamped.
-template<>
-inline void js::jit::AtomicOperations::storeSafeWhenRacy(uint8_clamped* addr,
-                                                         uint8_clamped val) {
-    storeSafeWhenRacy((uint8_t*)addr, (uint8_t)val);
-}
-
-}}
-
-#undef JIT_STORESAFE
-#undef JIT_STORESAFE_TEARING
-
-void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest, const void* src,
-                                                   size_t nbytes) {
-    JS::AutoSuppressGCAnalysis nogc;
-    MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest+nbytes));
-    MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src+nbytes));
-    AtomicMemcpyDownUnsynchronized((uint8_t*)dest, (const uint8_t*)src, nbytes);
-}
-
-inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
-                                                           const void* src,
-                                                           size_t nbytes) {
-    JS::AutoSuppressGCAnalysis nogc;
-    if ((char*)dest <= (char*)src) {
-        AtomicMemcpyDownUnsynchronized((uint8_t*)dest, (const uint8_t*)src,
-                                       nbytes);
-    } else {
-        AtomicMemcpyUpUnsynchronized((uint8_t*)dest, (const uint8_t*)src,
-                                     nbytes);
-    }
-}
-
-namespace js {
-namespace jit {
-
-extern bool InitializeJittedAtomics();
-extern void ShutDownJittedAtomics();
-
-}}
-
-inline bool js::jit::AtomicOperations::Initialize() {
-  return InitializeJittedAtomics();
-}
-
-inline void js::jit::AtomicOperations::ShutDown() {
-  ShutDownJittedAtomics();
-}
-
-#endif // jit_shared_AtomicOperations_shared_jit_h
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -925,43 +925,37 @@ void MacroAssembler::wasmAtomicExchange6
   if (value != output) {
     movq(value.reg, output.reg);
   }
   append(access, masm.size());
   xchgq(output.reg, Operand(mem));
 }
 
 template <typename T>
-static void AtomicFetchOp64(MacroAssembler& masm,
-                            const wasm::MemoryAccessDesc* access, AtomicOp op,
-                            Register value, const T& mem, Register temp,
-                            Register output) {
+static void WasmAtomicFetchOp64(MacroAssembler& masm,
+                                const wasm::MemoryAccessDesc access,
+                                AtomicOp op, Register value, const T& mem,
+                                Register temp, Register output) {
   if (op == AtomicFetchAddOp) {
     if (value != output) {
       masm.movq(value, output);
     }
-    if (access) {
-      masm.append(*access, masm.size());
-    }
+    masm.append(access, masm.size());
     masm.lock_xaddq(output, Operand(mem));
   } else if (op == AtomicFetchSubOp) {
     if (value != output) {
       masm.movq(value, output);
     }
     masm.negq(output);
-    if (access) {
-      masm.append(*access, masm.size());
-    }
+    masm.append(access, masm.size());
     masm.lock_xaddq(output, Operand(mem));
   } else {
     Label again;
     MOZ_ASSERT(output == rax);
-    if (access) {
-      masm.append(*access, masm.size());
-    }
+    masm.append(access, masm.size());
     masm.movq(Operand(mem), rax);
     masm.bind(&again);
     masm.movq(rax, temp);
     switch (op) {
       case AtomicFetchAndOp:
         masm.andq(value, temp);
         break;
       case AtomicFetchOrOp:
@@ -977,24 +971,24 @@ static void AtomicFetchOp64(MacroAssembl
     masm.j(MacroAssembler::NonZero, &again);
   }
 }
 
 void MacroAssembler::wasmAtomicFetchOp64(const wasm::MemoryAccessDesc& access,
                                          AtomicOp op, Register64 value,
                                          const Address& mem, Register64 temp,
                                          Register64 output) {
-  AtomicFetchOp64(*this, &access, op, value.reg, mem, temp.reg, output.reg);
+  WasmAtomicFetchOp64(*this, access, op, value.reg, mem, temp.reg, output.reg);
 }
 
 void MacroAssembler::wasmAtomicFetchOp64(const wasm::MemoryAccessDesc& access,
                                          AtomicOp op, Register64 value,
                                          const BaseIndex& mem, Register64 temp,
                                          Register64 output) {
-  AtomicFetchOp64(*this, &access, op, value.reg, mem, temp.reg, output.reg);
+  WasmAtomicFetchOp64(*this, access, op, value.reg, mem, temp.reg, output.reg);
 }
 
 void MacroAssembler::wasmAtomicEffectOp64(const wasm::MemoryAccessDesc& access,
                                           AtomicOp op, Register64 value,
                                           const BaseIndex& mem) {
   append(access, size());
   switch (op) {
     case AtomicFetchAddOp:
@@ -1012,35 +1006,9 @@ void MacroAssembler::wasmAtomicEffectOp6
     case AtomicFetchXorOp:
       lock_xorq(value.reg, Operand(mem));
       break;
     default:
       MOZ_CRASH();
   }
 }
 
-void MacroAssembler::compareExchange64(const Synchronization&,
-                                       const Address& mem, Register64 expected,
-                                       Register64 replacement,
-                                       Register64 output) {
-  MOZ_ASSERT(output.reg == rax);
-  if (expected != output) {
-    movq(expected.reg, output.reg);
-  }
-  lock_cmpxchgq(replacement.reg, Operand(mem));
-}
-
-void MacroAssembler::atomicExchange64(const Synchronization&,
-                                      const Address& mem, Register64 value,
-                                      Register64 output) {
-  if (value != output) {
-    movq(value.reg, output.reg);
-  }
-  xchgq(output.reg, Operand(mem));
-}
-
-void MacroAssembler::atomicFetchOp64(const Synchronization& sync, AtomicOp op,
-                                     Register64 value, const Address& mem,
-                                     Register64 temp, Register64 output) {
-  AtomicFetchOp64(*this, nullptr, op, value.reg, mem, temp.reg, output.reg);
-}
-
 //}}} check_macroassembler_style
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.h
@@ -204,29 +204,16 @@ class CPUInfo {
   static bool popcntPresent;
   static bool bmi1Present;
   static bool bmi2Present;
   static bool lzcntPresent;
   static bool needAmdBugWorkaround;
 
   static void SetSSEVersion();
 
-  // The flags can become set at startup when we JIT non-JS code eagerly; thus
-  // we reset the flags before setting any flags explicitly during testing, so
-  // that the flags can be in a consistent state.
-
-  static void reset() {
-    maxSSEVersion = UnknownSSE;
-    maxEnabledSSEVersion = UnknownSSE;
-    avxPresent = false;
-    avxEnabled = false;
-    popcntPresent = false;
-    needAmdBugWorkaround = false;
-  }
-
  public:
   static bool IsSSE2Present() {
 #ifdef JS_CODEGEN_X64
     return true;
 #else
     return GetSSEVersion() >= SSE2;
 #endif
   }
@@ -236,29 +223,24 @@ class CPUInfo {
   static bool IsSSE42Present() { return GetSSEVersion() >= SSE4_2; }
   static bool IsPOPCNTPresent() { return popcntPresent; }
   static bool IsBMI1Present() { return bmi1Present; }
   static bool IsBMI2Present() { return bmi2Present; }
   static bool IsLZCNTPresent() { return lzcntPresent; }
   static bool NeedAmdBugWorkaround() { return needAmdBugWorkaround; }
 
   static void SetSSE3Disabled() {
-    reset();
     maxEnabledSSEVersion = SSE2;
     avxEnabled = false;
   }
   static void SetSSE4Disabled() {
-    reset();
     maxEnabledSSEVersion = SSSE3;
     avxEnabled = false;
   }
-  static void SetAVXEnabled() {
-    reset();
-    avxEnabled = true;
-  }
+  static void SetAVXEnabled() { avxEnabled = true; }
 };
 
 class AssemblerX86Shared : public AssemblerShared {
  protected:
   struct RelativePatch {
     int32_t offset;
     void* target;
     RelocationKind kind;
new file mode 100644
--- /dev/null
+++ b/js/src/jit/x86-shared/AtomicOperations-x86-shared-gcc.h
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* For overall documentation, see jit/AtomicOperations.h */
+
+#ifndef jit_shared_AtomicOperations_x86_shared_gcc_h
+#define jit_shared_AtomicOperations_x86_shared_gcc_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Types.h"
+
+#include "vm/ArrayBufferObject.h"
+
+#if !defined(__clang__) && !defined(__GNUC__)
+#  error "This file only for gcc-compatible compilers"
+#endif
+
+// Lock-freedom and access-atomicity on x86 and x64.
+//
+// In general, aligned accesses are access-atomic up to 8 bytes ever since the
+// Pentium; Firefox requires SSE2, which was introduced with the Pentium 4, so
+// we may assume access-atomicity.
+//
+// Four-byte accesses and smaller are simple:
+//  - Use MOV{B,W,L} to load and store.  Stores require a post-fence
+//    for sequential consistency as defined by the JS spec.  The fence
+//    can be MFENCE, or the store can be implemented using XCHG.
+//  - For compareExchange use LOCK; CMPXCGH{B,W,L}
+//  - For exchange, use XCHG{B,W,L}
+//  - For add, etc use LOCK; ADD{B,W,L} etc
+//
+// Eight-byte accesses are easy on x64:
+//  - Use MOVQ to load and store (again with a fence for the store)
+//  - For compareExchange, we use CMPXCHGQ
+//  - For exchange, we use XCHGQ
+//  - For add, etc use LOCK; ADDQ etc
+//
+// Eight-byte accesses are harder on x86:
+//  - For load, use a sequence of MOVL + CMPXCHG8B
+//  - For store, use a sequence of MOVL + a CMPXCGH8B in a loop,
+//    no additional fence required
+//  - For exchange, do as for store
+//  - For add, etc do as for store
+
+// Firefox requires gcc > 4.8, so we will always have the __atomic intrinsics
+// added for use in C++11 <atomic>.
+//
+// Note that using these intrinsics for most operations is not correct: the code
+// has undefined behavior.  The gcc documentation states that the compiler
+// assumes the code is race free.  This supposedly means C++ will allow some
+// instruction reorderings (effectively those allowed by TSO) even for seq_cst
+// ordered operations, but these reorderings are not allowed by JS.  To do
+// better we will end up with inline assembler or JIT-generated code.
+
+// For now, we require that the C++ compiler's atomics are lock free, even for
+// 64-bit accesses.
+
+// When compiling with Clang on 32-bit linux it will be necessary to link with
+// -latomic to get the proper 64-bit intrinsics.
+
+inline bool js::jit::AtomicOperations::hasAtomic8() { return true; }
+
+inline bool js::jit::AtomicOperations::isLockfree8() {
+  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int8_t), 0));
+  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int16_t), 0));
+  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int32_t), 0));
+  MOZ_ASSERT(__atomic_always_lock_free(sizeof(int64_t), 0));
+  return true;
+}
+
+inline void js::jit::AtomicOperations::fenceSeqCst() {
+  __atomic_thread_fence(__ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::loadSeqCst(T* addr) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  T v;
+  __atomic_load(addr, &v, __ATOMIC_SEQ_CST);
+  return v;
+}
+
+template <typename T>
+inline void js::jit::AtomicOperations::storeSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  __atomic_store(addr, &val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::exchangeSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  T v;
+  __atomic_exchange(addr, &val, &v, __ATOMIC_SEQ_CST);
+  return v;
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::compareExchangeSeqCst(T* addr, T oldval,
+                                                          T newval) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  __atomic_compare_exchange(addr, &oldval, &newval, false, __ATOMIC_SEQ_CST,
+                            __ATOMIC_SEQ_CST);
+  return oldval;
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchAddSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_add(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchSubSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_sub(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchAndSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_and(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchOrSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_or(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::fetchXorSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  return __atomic_fetch_xor(addr, val, __ATOMIC_SEQ_CST);
+}
+
+template <typename T>
+inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  T v;
+  __atomic_load(addr, &v, __ATOMIC_RELAXED);
+  return v;
+}
+
+namespace js {
+namespace jit {
+
+#define GCC_RACYLOADOP(T)                                         \
+  template <>                                                     \
+  inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) { \
+    return *addr;                                                 \
+  }
+
+// On 32-bit platforms, loadSafeWhenRacy need not be access-atomic for 64-bit
+// data, so just use regular accesses instead of the expensive __atomic_load
+// solution which must use CMPXCHG8B.
+#ifndef JS_64BIT
+GCC_RACYLOADOP(int64_t)
+GCC_RACYLOADOP(uint64_t)
+#endif
+
+// Float and double accesses are not access-atomic.
+GCC_RACYLOADOP(float)
+GCC_RACYLOADOP(double)
+
+// Clang requires a specialization for uint8_clamped.
+template <>
+inline uint8_clamped js::jit::AtomicOperations::loadSafeWhenRacy(
+    uint8_clamped* addr) {
+  uint8_t v;
+  __atomic_load(&addr->val, &v, __ATOMIC_RELAXED);
+  return uint8_clamped(v);
+}
+
+#undef GCC_RACYLOADOP
+
+}  // namespace jit
+}  // namespace js
+
+template <typename T>
+inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
+  __atomic_store(addr, &val, __ATOMIC_RELAXED);
+}
+
+namespace js {
+namespace jit {
+
+#define GCC_RACYSTOREOP(T)                                                   \
+  template <>                                                                \
+  inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) { \
+    *addr = val;                                                             \
+  }
+
+// On 32-bit platforms, storeSafeWhenRacy need not be access-atomic for 64-bit
+// data, so just use regular accesses instead of the expensive __atomic_store
+// solution which must use CMPXCHG8B.
+#ifndef JS_64BIT
+GCC_RACYSTOREOP(int64_t)
+GCC_RACYSTOREOP(uint64_t)
+#endif
+
+// Float and double accesses are not access-atomic.
+GCC_RACYSTOREOP(float)
+GCC_RACYSTOREOP(double)
+
+// Clang requires a specialization for uint8_clamped.
+template <>
+inline void js::jit::AtomicOperations::storeSafeWhenRacy(uint8_clamped* addr,
+                                                         uint8_clamped val) {
+  __atomic_store(&addr->val, &val.val, __ATOMIC_RELAXED);
+}
+
+#undef GCC_RACYSTOREOP
+
+}  // namespace jit
+}  // namespace js
+
+inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
+                                                          const void* src,
+                                                          size_t nbytes) {
+  MOZ_ASSERT(!((char*)dest <= (char*)src && (char*)src < (char*)dest + nbytes));
+  MOZ_ASSERT(!((char*)src <= (char*)dest && (char*)dest < (char*)src + nbytes));
+  ::memcpy(dest, src, nbytes);
+}
+
+inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
+                                                           const void* src,
+                                                           size_t nbytes) {
+  ::memmove(dest, src, nbytes);
+}
+
+#endif  // jit_shared_AtomicOperations_x86_shared_gcc_h
rename from js/src/jit/shared/AtomicOperations-feeling-lucky-msvc.h
rename to js/src/jit/x86-shared/AtomicOperations-x86-shared-msvc.h
--- a/js/src/jit/shared/AtomicOperations-feeling-lucky-msvc.h
+++ b/js/src/jit/x86-shared/AtomicOperations-x86-shared-msvc.h
@@ -1,127 +1,112 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef jit_shared_AtomicOperations_feeling_lucky_msvc_h
-#define jit_shared_AtomicOperations_feeling_lucky_msvc_h
+#ifndef jit_shared_AtomicOperations_x86_shared_msvc_h
+#define jit_shared_AtomicOperations_x86_shared_msvc_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Types.h"
 
-// Explicitly exclude tier-1 platforms.
-
-#if ((defined(__x86_64__) || defined(_M_X64)) && defined(JS_CODEGEN_X64)) || \
-    ((defined(__i386__) || defined(_M_IX86)) && defined(JS_CODEGEN_X86)) ||  \
-    (defined(__arm__) && defined(JS_CODEGEN_ARM)) ||                         \
-    ((defined(__aarch64__) || defined(_M_ARM64)) && defined(JS_CODEGEN_ARM64))
-#  error "Do not use this code on a tier-1 platform when a JIT is available"
-#endif
-
 #if !defined(_MSC_VER)
 #  error "This file only for Microsoft Visual C++"
 #endif
 
-// For overall documentation, see jit/AtomicOperations.h.
+// For overall documentation, see jit/AtomicOperations.h/
+//
+// For general comments on lock-freedom, access-atomicity, and related matters
+// on x86 and x64, notably for justification of the implementations of the
+// 64-bit primitives on 32-bit systems, see the comment block in
+// AtomicOperations-x86-shared-gcc.h.
 
 // Below, _ReadWriteBarrier is a compiler directive, preventing reordering of
 // instructions and reuse of memory values across it in the compiler, but having
 // no impact on what the CPU does.
 
 // Note, here we use MSVC intrinsics directly.  But MSVC supports a slightly
 // higher level of function which uses the intrinsic when possible (8, 16, and
 // 32-bit operations, and 64-bit operations on 64-bit systems) and otherwise
 // falls back on CMPXCHG8B for 64-bit operations on 32-bit systems.  We could be
 // using those functions in many cases here (though not all).  I have not done
-// so because I don't yet know how far back those functions are supported.
+// so because (a) I don't yet know how far back those functions are supported
+// and (b) I expect we'll end up dropping into assembler here eventually so as
+// to guarantee that the C++ compiler won't optimize the code.
 
 // Note, _InterlockedCompareExchange takes the *new* value as the second
 // argument and the *comparand* (expected old value) as the third argument.
 
-inline bool js::jit::AtomicOperations::Initialize() {
-  // Nothing
-  return true;
-}
-
-inline void js::jit::AtomicOperations::ShutDown() {
-  // Nothing
-}
-
 inline bool js::jit::AtomicOperations::hasAtomic8() { return true; }
 
 inline bool js::jit::AtomicOperations::isLockfree8() {
   // The MSDN docs suggest very strongly that if code is compiled for Pentium
   // or better the 64-bit primitives will be lock-free, see eg the "Remarks"
   // secion of the page for _InterlockedCompareExchange64, currently here:
   // https://msdn.microsoft.com/en-us/library/ttk2z1ws%28v=vs.85%29.aspx
   //
   // But I've found no way to assert that at compile time or run time, there
   // appears to be no WinAPI is_lock_free() test.
 
   return true;
 }
 
 inline void js::jit::AtomicOperations::fenceSeqCst() {
   _ReadWriteBarrier();
-#if defined(_M_IX86) || defined(_M_X64)
   _mm_mfence();
-#elif defined(_M_ARM64)
-  // MemoryBarrier is defined in winnt.h, which we don't want to include here.
-  // This expression is the expansion of MemoryBarrier.
-  __dmb(_ARM64_BARRIER_SY);
-#else
-#error "Unknown hardware for MSVC"
-#endif
 }
 
 template <typename T>
 inline T js::jit::AtomicOperations::loadSeqCst(T* addr) {
+  MOZ_ASSERT(tier1Constraints(addr));
   _ReadWriteBarrier();
   T v = *addr;
   _ReadWriteBarrier();
   return v;
 }
 
 #ifdef _M_IX86
 namespace js {
 namespace jit {
 
 #  define MSC_LOADOP(T)                                                       \
     template <>                                                               \
     inline T AtomicOperations::loadSeqCst(T* addr) {                          \
+      MOZ_ASSERT(tier1Constraints(addr));                                     \
       _ReadWriteBarrier();                                                    \
       return (T)_InterlockedCompareExchange64((__int64 volatile*)addr, 0, 0); \
     }
 
 MSC_LOADOP(int64_t)
 MSC_LOADOP(uint64_t)
 
 #  undef MSC_LOADOP
 
 }  // namespace jit
 }  // namespace js
 #endif  // _M_IX86
 
 template <typename T>
 inline void js::jit::AtomicOperations::storeSeqCst(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
   _ReadWriteBarrier();
   *addr = val;
   fenceSeqCst();
 }
 
 #ifdef _M_IX86
 namespace js {
 namespace jit {
 
 #  define MSC_STOREOP(T)                                             \
     template <>                                                      \
     inline void AtomicOperations::storeSeqCst(T* addr, T val) {      \
+      MOZ_ASSERT(tier1Constraints(addr));                            \
       _ReadWriteBarrier();                                           \
       T oldval = *addr;                                              \
       for (;;) {                                                     \
         T nextval = (T)_InterlockedCompareExchange64(                \
             (__int64 volatile*)addr, (__int64)val, (__int64)oldval); \
         if (nextval == oldval) break;                                \
         oldval = nextval;                                            \
       }                                                              \
@@ -135,23 +120,25 @@ MSC_STOREOP(uint64_t)
 
 }  // namespace jit
 }  // namespace js
 #endif  // _M_IX86
 
 #define MSC_EXCHANGEOP(T, U, xchgop)                          \
   template <>                                                 \
   inline T AtomicOperations::exchangeSeqCst(T* addr, T val) { \
+    MOZ_ASSERT(tier1Constraints(addr));                       \
     return (T)xchgop((U volatile*)addr, (U)val);              \
   }
 
 #ifdef _M_IX86
 #  define MSC_EXCHANGEOP_CAS(T)                                      \
     template <>                                                      \
     inline T AtomicOperations::exchangeSeqCst(T* addr, T val) {      \
+      MOZ_ASSERT(tier1Constraints(addr));                            \
       _ReadWriteBarrier();                                           \
       T oldval = *addr;                                              \
       for (;;) {                                                     \
         T nextval = (T)_InterlockedCompareExchange64(                \
             (__int64 volatile*)addr, (__int64)val, (__int64)oldval); \
         if (nextval == oldval) break;                                \
         oldval = nextval;                                            \
       }                                                              \
@@ -183,16 +170,17 @@ MSC_EXCHANGEOP(uint64_t, __int64, _Inter
 
 #undef MSC_EXCHANGEOP
 #undef MSC_EXCHANGEOP_CAS
 
 #define MSC_CAS(T, U, cmpxchg)                                        \
   template <>                                                         \
   inline T AtomicOperations::compareExchangeSeqCst(T* addr, T oldval, \
                                                    T newval) {        \
+    MOZ_ASSERT(tier1Constraints(addr));                               \
     return (T)cmpxchg((U volatile*)addr, (U)newval, (U)oldval);       \
   }
 
 namespace js {
 namespace jit {
 
 MSC_CAS(int8_t, char, _InterlockedCompareExchange8)
 MSC_CAS(uint8_t, char, _InterlockedCompareExchange8)
@@ -206,29 +194,31 @@ MSC_CAS(uint64_t, __int64, _InterlockedC
 }  // namespace jit
 }  // namespace js
 
 #undef MSC_CAS
 
 #define MSC_FETCHADDOP(T, U, xadd)                            \
   template <>                                                 \
   inline T AtomicOperations::fetchAddSeqCst(T* addr, T val) { \
+    MOZ_ASSERT(tier1Constraints(addr));                       \
     return (T)xadd((U volatile*)addr, (U)val);                \
   }
 
 #define MSC_FETCHSUBOP(T)                                     \
   template <>                                                 \
   inline T AtomicOperations::fetchSubSeqCst(T* addr, T val) { \
     return fetchAddSeqCst(addr, (T)(0 - val));                \
   }
 
 #ifdef _M_IX86
 #  define MSC_FETCHADDOP_CAS(T)                                               \
     template <>                                                               \
     inline T AtomicOperations::fetchAddSeqCst(T* addr, T val) {               \
+      MOZ_ASSERT(tier1Constraints(addr));                                     \
       _ReadWriteBarrier();                                                    \
       T oldval = *addr;                                                       \
       for (;;) {                                                              \
         T nextval = (T)_InterlockedCompareExchange64((__int64 volatile*)addr, \
                                                      (__int64)(oldval + val), \
                                                      (__int64)oldval);        \
         if (nextval == oldval) break;                                         \
         oldval = nextval;                                                     \
@@ -270,31 +260,33 @@ MSC_FETCHSUBOP(uint64_t)
 
 #undef MSC_FETCHADDOP
 #undef MSC_FETCHADDOP_CAS
 #undef MSC_FETCHSUBOP
 
 #define MSC_FETCHBITOPX(T, U, name, op)             \
   template <>                                       \
   inline T AtomicOperations::name(T* addr, T val) { \
+    MOZ_ASSERT(tier1Constraints(addr));             \
     return (T)op((U volatile*)addr, (U)val);        \
   }
 
 #define MSC_FETCHBITOP(T, U, andop, orop, xorop) \
   MSC_FETCHBITOPX(T, U, fetchAndSeqCst, andop)   \
   MSC_FETCHBITOPX(T, U, fetchOrSeqCst, orop)     \
   MSC_FETCHBITOPX(T, U, fetchXorSeqCst, xorop)
 
 #ifdef _M_IX86
 #  define AND_OP &
 #  define OR_OP |
 #  define XOR_OP ^
 #  define MSC_FETCHBITOPX_CAS(T, name, OP)                                     \
     template <>                                                                \
     inline T AtomicOperations::name(T* addr, T val) {                          \
+      MOZ_ASSERT(tier1Constraints(addr));                                      \
       _ReadWriteBarrier();                                                     \
       T oldval = *addr;                                                        \
       for (;;) {                                                               \
         T nextval = (T)_InterlockedCompareExchange64((__int64 volatile*)addr,  \
                                                      (__int64)(oldval OP val), \
                                                      (__int64)oldval);         \
         if (nextval == oldval) break;                                          \
         oldval = nextval;                                                      \
@@ -339,23 +331,25 @@ MSC_FETCHBITOP(uint64_t, __int64, _Inter
 
 #undef MSC_FETCHBITOPX_CAS
 #undef MSC_FETCHBITOPX
 #undef MSC_FETCHBITOP_CAS
 #undef MSC_FETCHBITOP
 
 template <typename T>
 inline T js::jit::AtomicOperations::loadSafeWhenRacy(T* addr) {
+  MOZ_ASSERT(tier1Constraints(addr));
   // This is also appropriate for double, int64, and uint64 on 32-bit
   // platforms since there are no guarantees of access-atomicity.
   return *addr;
 }
 
 template <typename T>
 inline void js::jit::AtomicOperations::storeSafeWhenRacy(T* addr, T val) {
+  MOZ_ASSERT(tier1Constraints(addr));
   // This is also appropriate for double, int64, and uint64 on 32-bit
   // platforms since there are no guarantees of access-atomicity.
   *addr = val;
 }
 
 inline void js::jit::AtomicOperations::memcpySafeWhenRacy(void* dest,
                                                           const void* src,
                                                           size_t nbytes) {
@@ -365,9 +359,9 @@ inline void js::jit::AtomicOperations::m
 }
 
 inline void js::jit::AtomicOperations::memmoveSafeWhenRacy(void* dest,
                                                            const void* src,
                                                            size_t nbytes) {
   ::memmove(dest, src, nbytes);
 }
 
-#endif  // jit_shared_AtomicOperations_feeling_lucky_msvc_h
+#endif  // jit_shared_AtomicOperations_x86_shared_msvc_h
--- a/js/src/vm/Initialization.cpp
+++ b/js/src/vm/Initialization.cpp
@@ -12,17 +12,16 @@
 
 #include <ctype.h>
 
 #include "jstypes.h"
 
 #include "builtin/AtomicsObject.h"
 #include "ds/MemoryProtectionExceptionHandler.h"
 #include "gc/Statistics.h"
-#include "jit/AtomicOperations.h"
 #include "jit/ExecutableAllocator.h"
 #include "jit/Ion.h"
 #include "jit/JitCommon.h"
 #include "js/Utility.h"
 #if ENABLE_INTL_API
 #  include "unicode/uclean.h"
 #  include "unicode/utypes.h"
 #endif  // ENABLE_INTL_API
@@ -123,18 +122,16 @@ JS_PUBLIC_API const char* JS::detail::In
   RETURN_IF_FAIL(js::jit::InitializeIon());
 
   RETURN_IF_FAIL(js::InitDateTimeState());
 
 #ifdef MOZ_VTUNE
   RETURN_IF_FAIL(js::vtune::Initialize());
 #endif
 
-  RETURN_IF_FAIL(js::jit::AtomicOperations::Initialize());
-
 #if EXPOSE_INTL_API
   UErrorCode err = U_ZERO_ERROR;
   u_init(&err);
   if (U_FAILURE(err)) {
     return "u_init() failed";
   }
 #endif  // EXPOSE_INTL_API
 
@@ -173,18 +170,16 @@ JS_PUBLIC_API void JS_ShutDown(void) {
   FutexThread::destroy();
 
   js::DestroyHelperThreadsState();
 
 #ifdef JS_SIMULATOR
   js::jit::SimulatorProcess::destroy();
 #endif
 
-  js::jit::AtomicOperations::ShutDown();
-
 #ifdef JS_TRACE_LOGGING
   js::DestroyTraceLoggerThreadState();
   js::DestroyTraceLoggerGraphState();
 #endif
 
   js::MemoryProtectionExceptionHandler::uninstall();
 
   js::wasm::ShutDown();