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"
15 #include "gc/Marking.h"
17 #include "vm/JSObject.h"
18 #include "vm/NativeObject.h"
19 #include "vm/Runtime.h"
24 extern uint64_t NextCellUniqueId(JSRuntime
* rt
);
26 inline bool MaybeGetUniqueId(Cell
* cell
, uint64_t* 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()) {
39 *uidp
= nobj
->uniqueId();
44 // Get an existing uid, if one has been set.
45 auto p
= cell
->zone()->uniqueIds().readonlyThreadsafeLookup(cell
);
55 extern bool CreateUniqueIdForNativeObject(NativeObject
* obj
, uint64_t* uidp
);
56 extern bool CreateUniqueIdForNonNativeObject(Cell
* cell
, UniqueIdMap::AddPtr
,
59 inline bool GetOrCreateUniqueId(Cell
* cell
, uint64_t* 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();
73 return CreateUniqueIdForNativeObject(nobj
, uidp
);
77 // Get an existing uid, if one has been set.
78 auto p
= cell
->zone()->uniqueIds().lookupForAdd(cell
);
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
)) {
107 return cell
->zone()->uniqueIds().put(cell
, uid
);
110 inline uint64_t GetUniqueIdInfallible(Cell
* cell
) {
112 AutoEnterOOMUnsafeRegion oomUnsafe
;
113 if (!GetOrCreateUniqueId(cell
, &uid
)) {
114 oomUnsafe
.crash("failed to allocate 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
148 cell
->zone()->uniqueIds().remove(cell
);
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
) {
169 if (!gc::MaybeGetUniqueId(l
, &uid
)) {
173 *hashOut
= UniqueIdToHash(uid
);
177 template <typename T
>
178 /* static */ bool StableCellHasher
<T
>::ensureHash(const Lookup
& l
,
179 HashNumber
* hashOut
) {
186 if (!gc::GetOrCreateUniqueId(l
, &uid
)) {
190 *hashOut
= UniqueIdToHash(uid
);
194 template <typename T
>
195 /* static */ HashNumber StableCellHasher
<T
>::hash(const Lookup
& l
) {
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
) {
220 MOZ_ASSERT(CurrentThreadCanAccessZone(l
->zoneFromAnyThread()) ||
221 CurrentThreadIsPerformingGC());
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
)) {
229 MOZ_ASSERT(IsAboutToBeFinalizedUnbarriered(key
));
231 MOZ_ASSERT(gc::HasUniqueId(l
));
235 if (!gc::MaybeGetUniqueId(k
, &keyId
)) {
236 // Key is dead and cannot match lookup which must be live.
240 return keyId
== gc::GetUniqueIdInfallible(l
);
245 #endif // gc_StableCellHasher_inl_h