Backed out changeset 1e582a0e5593 (bug 1852921) for causing build bustages
[gecko.git] / js / src / gc / StableCellHasher-inl.h
blobf76748afef52394f49d79b2975e9f7c07e341da1
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(!IsInsideNursery(tgt));
136 MOZ_ASSERT(CurrentThreadCanAccessRuntime(tgt->runtimeFromAnyThread()));
137 MOZ_ASSERT(src->zone() == tgt->zone());
139 Zone* zone = tgt->zone();
140 MOZ_ASSERT(!zone->uniqueIds().has(tgt));
141 zone->uniqueIds().rekeyIfMoved(src, tgt);
144 inline void RemoveUniqueId(Cell* cell) {
145 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cell->runtimeFromAnyThread()));
146 // The cell may no longer be in the hash table if it was swapped with a
147 // NativeObject.
148 cell->zone()->uniqueIds().remove(cell);
151 } // namespace gc
153 static inline js::HashNumber UniqueIdToHash(uint64_t uid) {
154 // This uses the default hasher which returns the lower 32 bits of 64 bit
155 // integers as the hash code. This is OK because he result will be scrambled
156 // later by ScrambleHashCode().
157 return DefaultHasher<uint64_t>::hash(uid);
160 template <typename T>
161 /* static */ bool StableCellHasher<T>::maybeGetHash(const Lookup& l,
162 HashNumber* hashOut) {
163 if (!l) {
164 *hashOut = 0;
165 return true;
168 uint64_t uid;
169 if (!gc::MaybeGetUniqueId(l, &uid)) {
170 return false;
173 *hashOut = UniqueIdToHash(uid);
174 return true;
177 template <typename T>
178 /* static */ bool StableCellHasher<T>::ensureHash(const Lookup& l,
179 HashNumber* hashOut) {
180 if (!l) {
181 *hashOut = 0;
182 return true;
185 uint64_t uid;
186 if (!gc::GetOrCreateUniqueId(l, &uid)) {
187 return false;
190 *hashOut = UniqueIdToHash(uid);
191 return true;
194 template <typename T>
195 /* static */ HashNumber StableCellHasher<T>::hash(const Lookup& l) {
196 if (!l) {
197 return 0;
200 // We have to access the zone from-any-thread here: a worker thread may be
201 // cloning a self-hosted object from the main runtime's self- hosting zone
202 // into another runtime. The zone's uid lock will protect against multiple
203 // workers doing this simultaneously.
204 MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) ||
205 CurrentThreadIsPerformingGC());
207 return UniqueIdToHash(gc::GetUniqueIdInfallible(l));
210 template <typename T>
211 /* static */ bool StableCellHasher<T>::match(const Key& k, const Lookup& l) {
212 if (k == l) {
213 return true;
216 if (!k || !l) {
217 return false;
220 MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) ||
221 CurrentThreadIsPerformingGC());
223 #ifdef DEBUG
224 // Incremental table sweeping means that existing table entries may no
225 // longer have unique IDs. We fail the match in that case and the entry is
226 // removed from the table later on.
227 if (!gc::HasUniqueId(k)) {
228 Key key = k;
229 MOZ_ASSERT(IsAboutToBeFinalizedUnbarriered(key));
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