Bug 1462261 - Don't use AlignedStorage2 to implement HashTableEntry. r=jandem
authorJeff Walden <[email protected]>
Wed, 16 May 2018 13:29:52 -0700
changeset 418910 233871244d8029b262685a7e35a5bb330b34ac9d
parent 418909 3239e0d823ff6fc85adda2b0c036f8b53c866fbf
child 418911 353d2ee295913b9d6660f0b8da2102a54c8133bf
push id103419
push user[email protected]
push dateFri, 18 May 2018 19:33:51 +0000
treeherdermozilla-inbound@7658d2d1e0d7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1462261
milestone62.0a1
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
Bug 1462261 - Don't use AlignedStorage2 to implement HashTableEntry. r=jandem
js/public/HashTable.h
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -2,17 +2,16 @@
  * 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 js_HashTable_h
 #define js_HashTable_h
 
-#include "mozilla/Alignment.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Casting.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/MemoryChecking.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
 #include "mozilla/Opaque.h"
@@ -25,17 +24,17 @@
 #include "js/Utility.h"
 
 namespace js {
 
 class TempAllocPolicy;
 template <class> struct DefaultHasher;
 template <class, class> class HashMapEntry;
 namespace detail {
-    template <class T> class HashTableEntry;
+    template <typename T> class HashTableEntry;
     template <class T, class HashPolicy, class AllocPolicy> class HashTable;
 } // namespace detail
 
 /*****************************************************************************/
 
 // The "generation" of a hash table is an opaque value indicating the state of
 // modification of the hash table through its lifetime.  If the generation of
 // a hash table compares equal at times T1 and T2, then lookups in the hash
@@ -785,41 +784,53 @@ struct IsPod<js::HashMapEntry<K, V> >
 
 namespace js {
 
 namespace detail {
 
 template <class T, class HashPolicy, class AllocPolicy>
 class HashTable;
 
-template <class T>
+template <typename T>
 class HashTableEntry
 {
-    template <class, class, class> friend class HashTable;
-    typedef typename mozilla::RemoveConst<T>::Type NonConstT;
+  private:
+    using NonConstT = typename mozilla::RemoveConst<T>::Type;
 
     HashNumber keyHash;
-    mozilla::AlignedStorage2<NonConstT> mem;
+    alignas(NonConstT) unsigned char valueData_[sizeof(NonConstT)];
+
+  private:
+    template <class, class, class> friend class HashTable;
+
+    // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
+    // -Werror compile error) to reinterpret_cast<> |valueData_| to |T*|, even
+    // through |void*|.  Placing the latter cast in these separate functions
+    // breaks the chain such that affected GCC versions no longer warn/error.
+    void* rawValuePtr() { return valueData_; }
 
     static const HashNumber sFreeKey = 0;
     static const HashNumber sRemovedKey = 1;
     static const HashNumber sCollisionBit = 1;
 
     static bool isLiveHash(HashNumber hash)
     {
         return hash > sRemovedKey;
     }
 
     HashTableEntry(const HashTableEntry&) = delete;
     void operator=(const HashTableEntry&) = delete;
     ~HashTableEntry() = delete;
 
+    NonConstT* valuePtr() { return reinterpret_cast<NonConstT*>(rawValuePtr()); }
+
     void destroyStoredT() {
-        mem.addr()->~T();
-        MOZ_MAKE_MEM_UNDEFINED(mem.addr(), sizeof(*mem.addr()));
+        NonConstT* ptr = valuePtr();
+        ptr->~T();
+        MOZ_MAKE_MEM_UNDEFINED(ptr, sizeof(*ptr));
     }
 
   public:
     // NB: HashTableEntry is treated as a POD: no constructor or destructor calls.
 
     void destroyIfLive() {
         if (isLive())
             destroyStoredT();
@@ -830,32 +841,32 @@ class HashTableEntry
         destroyStoredT();
     }
 
     void swap(HashTableEntry* other) {
         if (this == other)
             return;
         MOZ_ASSERT(isLive());
         if (other->isLive()) {
-            mozilla::Swap(*mem.addr(), *other->mem.addr());
+            mozilla::Swap(*valuePtr(), *other->valuePtr());
         } else {
-            *other->mem.addr() = mozilla::Move(*mem.addr());
+            *other->valuePtr() = mozilla::Move(*valuePtr());
             destroy();
         }
         mozilla::Swap(keyHash, other->keyHash);
     }
 
     T& get() {
         MOZ_ASSERT(isLive());
-        return *mem.addr();
+        return *valuePtr();
     }
 
     NonConstT& getMutable() {
         MOZ_ASSERT(isLive());
-        return *mem.addr();
+        return *valuePtr();
     }
 
     bool isFree() const {
         return keyHash == sFreeKey;
     }
 
     void clearLive() {
         MOZ_ASSERT(isLive());
@@ -906,32 +917,32 @@ class HashTableEntry
         return keyHash & ~sCollisionBit;
     }
 
     template <typename... Args>
     void setLive(HashNumber hn, Args&&... args)
     {
         MOZ_ASSERT(!isLive());
         keyHash = hn;
-        new(mem.addr()) T(mozilla::Forward<Args>(args)...);
+        new (valuePtr()) T(mozilla::Forward<Args>(args)...);
         MOZ_ASSERT(isLive());
     }
 };
 
 template <class T, class HashPolicy, class AllocPolicy>
 class HashTable : private AllocPolicy
 {
     friend class mozilla::ReentrancyGuard;
 
     typedef typename mozilla::RemoveConst<T>::Type NonConstT;
     typedef typename HashPolicy::KeyType Key;
     typedef typename HashPolicy::Lookup Lookup;
 
   public:
-    typedef HashTableEntry<T> Entry;
+    using Entry = HashTableEntry<T>;
 
     // A nullable pointer to a hash table element. A Ptr |p| can be tested
     // either explicitly |if (p.found()) p->...| or using boolean conversion
     // |if (p) p->...|. Ptr objects must not be used after any mutating hash
     // table operations unless |generation()| is tested.
     class Ptr
     {
         friend class HashTable;