Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / js / src / gc / StableCellHasher-inl.h
blob34a8827cfb3aed62ea9c14c81b096c2133942251
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef gc_StableCellHasher_inl_h
8 #define gc_StableCellHasher_inl_h
10 #include "gc/StableCellHasher.h"
12 #include "mozilla/HashFunctions.h"
14 #include "gc/Cell.h"
15 #include "gc/Marking.h"
16 #include "gc/Zone.h"
17 #include "vm/JSObject.h"
18 #include "vm/NativeObject.h"
19 #include "vm/Runtime.h"
21 namespace js {
22 namespace gc {
24 extern uint64_t NextCellUniqueId(JSRuntime* rt);
26 inline bool MaybeGetUniqueId(Cell* cell, uint64_t* uidp) {
27 MOZ_ASSERT(uidp);
28 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cell->runtimeFromAnyThread()) ||
29 CurrentThreadIsPerformingGC());
31 if (cell->is<JSObject>()) {
32 JSObject* obj = cell->as<JSObject>();
33 if (obj->is<NativeObject>()) {
34 auto* nobj = &obj->as<NativeObject>();
35 if (!nobj->hasUniqueId()) {
36 return false;
39 *uidp = nobj->uniqueId();
40 return true;
44 // Get an existing uid, if one has been set.
45 auto p = cell->zone()->uniqueIds().readonlyThreadsafeLookup(cell);
46 if (!p) {
47 return false;
50 *uidp = p->value();
52 return true;
55 extern bool CreateUniqueIdForNativeObject(NativeObject* obj, uint64_t* uidp);
56 extern bool CreateUniqueIdForNonNativeObject(Cell* cell, UniqueIdMap::AddPtr,
57 uint64_t* uidp);
59 inline bool GetOrCreateUniqueId(Cell* cell, uint64_t* uidp) {
60 MOZ_ASSERT(uidp);
61 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cell->runtimeFromAnyThread()) ||
62 CurrentThreadIsPerformingGC());
64 if (cell->is<JSObject>()) {
65 JSObject* obj = cell->as<JSObject>();
66 if (obj->is<NativeObject>()) {
67 auto* nobj = &obj->as<NativeObject>();
68 if (nobj->hasUniqueId()) {
69 *uidp = nobj->uniqueId();
70 return true;
73 return CreateUniqueIdForNativeObject(nobj, uidp);
77 // Get an existing uid, if one has been set.
78 auto p = cell->zone()->uniqueIds().lookupForAdd(cell);
79 if (p) {
80 *uidp = p->value();
81 return true;
84 return CreateUniqueIdForNonNativeObject(cell, p, uidp);
87 inline bool SetOrUpdateUniqueId(JSContext* cx, Cell* cell, uint64_t uid) {
88 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cell->runtimeFromAnyThread()));
90 if (cell->is<JSObject>()) {
91 JSObject* obj = cell->as<JSObject>();
92 if (obj->is<NativeObject>()) {
93 auto* nobj = &obj->as<NativeObject>();
94 return nobj->setOrUpdateUniqueId(cx, uid);
98 // If the cell was in the nursery, hopefully unlikely, then we need to
99 // tell the nursery about it so that it can sweep the uid if the thing
100 // does not get tenured.
101 JSRuntime* runtime = cell->runtimeFromMainThread();
102 if (IsInsideNursery(cell) &&
103 !runtime->gc.nursery().addedUniqueIdToCell(cell)) {
104 return false;
107 return cell->zone()->uniqueIds().put(cell, uid);
110 inline uint64_t GetUniqueIdInfallible(Cell* cell) {
111 uint64_t uid;
112 AutoEnterOOMUnsafeRegion oomUnsafe;
113 if (!GetOrCreateUniqueId(cell, &uid)) {
114 oomUnsafe.crash("failed to allocate uid");
116 return uid;
119 inline bool HasUniqueId(Cell* cell) {
120 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cell->runtimeFromAnyThread()) ||
121 CurrentThreadIsPerformingGC());
123 if (cell->is<JSObject>()) {
124 JSObject* obj = cell->as<JSObject>();
125 if (obj->is<NativeObject>()) {
126 return obj->as<NativeObject>().hasUniqueId();
130 return cell->zone()->uniqueIds().has(cell);
133 inline void TransferUniqueId(Cell* tgt, Cell* src) {
134 MOZ_ASSERT(src != tgt);
135 MOZ_ASSERT(CurrentThreadCanAccessRuntime(tgt->runtimeFromAnyThread()));
136 MOZ_ASSERT(src->zone() == tgt->zone());
138 Zone* zone = tgt->zone();
139 MOZ_ASSERT_IF(zone->uniqueIds().has(src), !zone->uniqueIds().has(tgt));
140 zone->uniqueIds().rekeyIfMoved(src, tgt);
143 inline void RemoveUniqueId(Cell* cell) {
144 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cell->runtimeFromAnyThread()));
145 // The cell may no longer be in the hash table if it was swapped with a
146 // NativeObject.
147 cell->zone()->uniqueIds().remove(cell);
150 } // namespace gc
152 static inline js::HashNumber UniqueIdToHash(uint64_t uid) {
153 // This uses the default hasher which returns the lower 32 bits of 64 bit
154 // integers as the hash code. This is OK because he result will be scrambled
155 // later by ScrambleHashCode().
156 return DefaultHasher<uint64_t>::hash(uid);
159 template <typename T>
160 /* static */ bool StableCellHasher<T>::maybeGetHash(const Lookup& l,
161 HashNumber* hashOut) {
162 if (!l) {
163 *hashOut = 0;
164 return true;
167 uint64_t uid;
168 if (!gc::MaybeGetUniqueId(l, &uid)) {
169 return false;
172 *hashOut = UniqueIdToHash(uid);
173 return true;
176 template <typename T>
177 /* static */ bool StableCellHasher<T>::ensureHash(const Lookup& l,
178 HashNumber* hashOut) {
179 if (!l) {
180 *hashOut = 0;
181 return true;
184 uint64_t uid;
185 if (!gc::GetOrCreateUniqueId(l, &uid)) {
186 return false;
189 *hashOut = UniqueIdToHash(uid);
190 return true;
193 template <typename T>
194 /* static */ HashNumber StableCellHasher<T>::hash(const Lookup& l) {
195 if (!l) {
196 return 0;
199 // We have to access the zone from-any-thread here: a worker thread may be
200 // cloning a self-hosted object from the main runtime's self- hosting zone
201 // into another runtime. The zone's uid lock will protect against multiple
202 // workers doing this simultaneously.
203 MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) ||
204 CurrentThreadIsPerformingGC());
206 return UniqueIdToHash(gc::GetUniqueIdInfallible(l));
209 template <typename T>
210 /* static */ bool StableCellHasher<T>::match(const Key& k, const Lookup& l) {
211 if (k == l) {
212 return true;
215 if (!k || !l) {
216 return false;
219 MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) ||
220 CurrentThreadIsPerformingGC());
222 #ifdef DEBUG
223 // Incremental table sweeping means that existing table entries may no
224 // longer have unique IDs. We fail the match in that case and the entry is
225 // removed from the table later on.
226 if (!gc::HasUniqueId(k)) {
227 Key key = k;
228 MOZ_ASSERT(key->zoneFromAnyThread()->needsIncrementalBarrier() &&
229 !key->isMarkedAny());
231 MOZ_ASSERT(gc::HasUniqueId(l));
232 #endif
234 uint64_t keyId;
235 if (!gc::MaybeGetUniqueId(k, &keyId)) {
236 // Key is dead and cannot match lookup which must be live.
237 return false;
240 return keyId == gc::GetUniqueIdInfallible(l);
243 } // namespace js
245 #endif // gc_StableCellHasher_inl_h