Copied from https://hg.mozilla.org/releases/mozilla-esr38/raw-rev/71f611fd27c7 # HG changeset patch # User Jeff Walden # Date 1458941573 25200 # Node ID 71f611fd27c7d6cb7d6dab9895c2922948042543 # Parent 861f6b83ce1deade2a976cabe059776ad51ce370 Bug 1246061. r=luke, r=froydnj, a=sylvestre diff --git a/js/public/HashTable.h b/js/public/HashTable.h --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -8,16 +8,17 @@ #define js_HashTable_h #include "mozilla/Alignment.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/Casting.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" +#include "mozilla/Opaque.h" #include "mozilla/PodOperations.h" #include "mozilla/ReentrancyGuard.h" #include "mozilla/TemplateLib.h" #include "mozilla/TypeTraits.h" #include "js/Utility.h" namespace js { @@ -27,16 +28,18 @@ template struct DefaultHasher; template class HashMapEntry; namespace detail { template class HashTableEntry; template class HashTable; } /*****************************************************************************/ +using Generation = mozilla::Opaque; + // A JS-friendly, STL-like container providing a hash-based map from keys to // values. In particular, HashMap calls constructors and destructors of all // objects added so non-PODs may be used safely. // // Key/Value requirements: // - movable, destructible, assignable // HashPolicy requirements: // - see Hash Policy section below @@ -200,17 +203,19 @@ class HashMap return impl.sizeOfExcludingThis(mallocSizeOf); } size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); } // If |generation()| is the same before and after a HashMap operation, // pointers into the table remain valid. - uint32_t generation() const { return impl.generation(); } + Generation generation() const { + return impl.generation(); + } /************************************************** Shorthand operations */ bool has(const Lookup& l) const { return impl.lookup(l).found(); } // Overwrite existing value with v. Return false on oom. @@ -431,17 +436,19 @@ class HashSet return impl.sizeOfExcludingThis(mallocSizeOf); } size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); } // If |generation()| is the same before and after a HashSet operation, // pointers into the table remain valid. - uint32_t generation() const { return impl.generation(); } + Generation generation() const { + return impl.generation(); + } /************************************************** Shorthand operations */ bool has(const Lookup& l) const { return impl.lookup(l).found(); } // Add |u| if it is not present already. Return false on oom. @@ -766,17 +773,17 @@ class HashTable : private AllocPolicy // table operations unless |generation()| is tested. class Ptr { friend class HashTable; Entry* entry_; #ifdef JS_DEBUG const HashTable* table_; - uint32_t generation; + Generation generation; #endif protected: Ptr(Entry& entry, const HashTable& tableArg) : entry_(&entry) #ifdef JS_DEBUG , table_(&tableArg) , generation(tableArg.generation()) @@ -873,17 +880,17 @@ class HashTable : private AllocPolicy while (cur < end && !cur->isLive()) ++cur; } Entry* cur, *end; #ifdef JS_DEBUG const HashTable* table_; uint64_t mutationCount; - uint32_t generation; + Generation generation; bool validEntry; #endif public: Range() : cur(nullptr) , end(nullptr) #ifdef JS_DEBUG @@ -1012,18 +1019,18 @@ class HashTable : private AllocPolicy // HashTable is not copyable or assignable HashTable(const HashTable&) = delete; void operator=(const HashTable&) = delete; private: static const size_t CAP_BITS = 24; public: - Entry* table; // entry storage - uint32_t gen; // entry storage generation number + uint64_t gen; // entry storage generation number + Entry* table; // entry storage uint32_t entryCount; // number of entries in table uint32_t removedCount:CAP_BITS; // removed entry sentinels in table uint32_t hashShift:8; // multiplicative hash shift #ifdef JS_DEBUG uint64_t mutationCount; mutable bool mEntered; mutable struct Stats @@ -1097,18 +1104,18 @@ class HashTable : private AllocPolicy for (Entry* e = oldTable, *end = e + capacity; e < end; ++e) e->destroyIfLive(); alloc.free_(oldTable); } public: explicit HashTable(AllocPolicy ap) : AllocPolicy(ap) + , gen(0) , table(nullptr) - , gen(0) , entryCount(0) , removedCount(0) , hashShift(sHashBits) #ifdef JS_DEBUG , mutationCount(0) , mEntered(false) #endif {} @@ -1524,20 +1531,20 @@ class HashTable : private AllocPolicy } uint32_t capacity() const { MOZ_ASSERT(table); return JS_BIT(sHashBits - hashShift); } - uint32_t generation() const + Generation generation() const { MOZ_ASSERT(table); - return gen; + return Generation(gen); } size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return mallocSizeOf(table); } size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const diff --git a/js/src/jsapi.h b/js/src/jsapi.h --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -270,20 +270,16 @@ class AutoHashMapRooter : protected Auto size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return map.sizeOfExcludingThis(mallocSizeOf); } size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return map.sizeOfIncludingThis(mallocSizeOf); } - uint32_t generation() const { - return map.generation(); - } - /************************************************** Shorthand operations */ bool has(const Lookup& l) const { return map.has(l); } template bool put(const KeyInput& k, const ValueInput& v) { @@ -385,20 +381,16 @@ class AutoHashSetRooter : protected Auto size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return set.sizeOfExcludingThis(mallocSizeOf); } size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return set.sizeOfIncludingThis(mallocSizeOf); } - uint32_t generation() const { - return set.generation(); - } - /************************************************** Shorthand operations */ bool has(const Lookup& l) const { return set.has(l); } bool put(const T& t) { return set.put(t); diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -30,21 +30,21 @@ class DebugModeOSRVolatileJitFrameIterat } typedef HashSet ObjectSet; typedef HashSet ShapeSet; /* Detects cycles when traversing an object graph. */ class AutoCycleDetector { + Generation hashsetGenerationAtInit; JSContext* cx; RootedObject obj; + ObjectSet::AddPtr hashsetAddPointer; bool cyclic; - uint32_t hashsetGenerationAtInit; - ObjectSet::AddPtr hashsetAddPointer; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER public: AutoCycleDetector(JSContext* cx, HandleObject objArg MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : cx(cx), obj(cx, objArg), cyclic(true) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -22,25 +22,25 @@ DefaultHasher::hash(const Look { return DefaultHasher::hash(key.object.get()) ^ HashId(key.id.get()); } namespace { class AutoEntryHolder { typedef WatchpointMap::Map Map; + Generation gen; Map& map; Map::Ptr p; - uint32_t gen; RootedObject obj; RootedId id; public: AutoEntryHolder(JSContext* cx, Map& map, Map::Ptr p) - : map(map), p(p), gen(map.generation()), obj(cx, p->key().object), id(cx, p->key().id) + : gen(map.generation()), map(map), p(p), obj(cx, p->key().object), id(cx, p->key().id) { MOZ_ASSERT(!p->value().held); p->value().held = true; } ~AutoEntryHolder() { if (gen != map.generation()) p = map.lookup(WatchKey(obj, id)); diff --git a/js/src/shell/jsheaptools.cpp b/js/src/shell/jsheaptools.cpp --- a/js/src/shell/jsheaptools.cpp +++ b/js/src/shell/jsheaptools.cpp @@ -267,17 +267,17 @@ HeapReverser::traverseEdge(void* cell, J Map::AddPtr a = map.lookupForAdd(cell); if (!a) { /* * We've never visited this cell before. Add it to the map (thus * marking it as visited), and put it on the work stack, to be * visited from the main loop. */ Node n(kind); - uint32_t generation = map.generation(); + Generation generation = map.generation(); if (!map.add(a, cell, Move(n)) || !work.append(Child(cell, kind))) return false; /* If the map has been resized, re-check the pointer. */ if (map.generation() != generation) a = map.lookupForAdd(cell); } diff --git a/mfbt/Opaque.h b/mfbt/Opaque.h new file mode 100644 --- /dev/null +++ b/mfbt/Opaque.h @@ -0,0 +1,44 @@ +/* -*- 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/. */ + +/* An opaque integral type supporting only comparison operators. */ + +#ifndef mozilla_Opaque_h +#define mozilla_Opaque_h + +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +/** + * Opaque is a replacement for integral T in cases where only comparisons + * must be supported, and it's desirable to prevent accidental dependency on + * exact values. + */ +template +class Opaque final +{ + static_assert(mozilla::IsIntegral::value, + "mozilla::Opaque only supports integral types"); + + T mValue; + +public: + Opaque() {} + explicit Opaque(T aValue) : mValue(aValue) {} + + bool operator==(const Opaque& aOther) const { + return mValue == aOther.mValue; + } + + bool operator!=(const Opaque& aOther) const { + return !(*this == aOther); + } +}; + +} // namespace mozilla + +#endif /* mozilla_Opaque_h */ diff --git a/mfbt/moz.build b/mfbt/moz.build --- a/mfbt/moz.build +++ b/mfbt/moz.build @@ -48,16 +48,17 @@ EXPORTS.mozilla = [ 'MathAlgorithms.h', 'Maybe.h', 'MaybeOneOf.h', 'MemoryChecking.h', 'MemoryReporting.h', 'Move.h', 'NullPtr.h', 'NumericLimits.h', + 'Opaque.h', 'Pair.h', 'PodOperations.h', 'Poison.h', 'Range.h', 'RangedPtr.h', 'RefCountType.h', 'ReentrancyGuard.h', 'RefPtr.h',