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(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
147 cell
->zone()->uniqueIds().remove(cell
);
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
) {
168 if (!gc::MaybeGetUniqueId(l
, &uid
)) {
172 *hashOut
= UniqueIdToHash(uid
);
176 template <typename T
>
177 /* static */ bool StableCellHasher
<T
>::ensureHash(const Lookup
& l
,
178 HashNumber
* hashOut
) {
185 if (!gc::GetOrCreateUniqueId(l
, &uid
)) {
189 *hashOut
= UniqueIdToHash(uid
);
193 template <typename T
>
194 /* static */ HashNumber StableCellHasher
<T
>::hash(const Lookup
& l
) {
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
) {
219 MOZ_ASSERT(CurrentThreadCanAccessZone(l
->zoneFromAnyThread()) ||
220 CurrentThreadIsPerformingGC());
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
)) {
228 MOZ_ASSERT(key
->zoneFromAnyThread()->needsIncrementalBarrier() &&
229 !key
->isMarkedAny());
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