1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
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/. */
6
7 #include "gc/Barrier.h"
8
9 #include "jscompartment.h"
10 #include "jsobj.h"
11
12 #include "builtin/TypedObject.h"
13 #include "gc/Policy.h"
14 #include "gc/Zone.h"
15 #include "js/HashTable.h"
16 #include "js/Value.h"
17 #include "vm/EnvironmentObject.h"
18 #include "vm/SharedArrayObject.h"
19 #include "vm/Symbol.h"
20 #include "wasm/WasmJS.h"
21
22 namespace js {
23
24 bool
RuntimeFromMainThreadIsHeapMajorCollecting(JS::shadow::Zone * shadowZone)25 RuntimeFromMainThreadIsHeapMajorCollecting(JS::shadow::Zone* shadowZone)
26 {
27 return shadowZone->runtimeFromMainThread()->isHeapMajorCollecting();
28 }
29
30 #ifdef DEBUG
31
32 bool
IsMarkedBlack(NativeObject * obj)33 IsMarkedBlack(NativeObject* obj)
34 {
35 // Note: we assume conservatively that Nursery things will be live.
36 if (!obj->isTenured())
37 return true;
38
39 gc::TenuredCell& tenured = obj->asTenured();
40 return (tenured.isMarked(gc::BLACK) && !tenured.isMarked(gc::GRAY)) ||
41 tenured.arena()->allocatedDuringIncremental;
42 }
43
44 bool
preconditionForSet(NativeObject * owner,Kind kind,uint32_t slot) const45 HeapSlot::preconditionForSet(NativeObject* owner, Kind kind, uint32_t slot) const
46 {
47 return kind == Slot
48 ? &owner->getSlotRef(slot) == this
49 : &owner->getDenseElement(slot) == (const Value*)this;
50 }
51
52 bool
preconditionForWriteBarrierPost(NativeObject * obj,Kind kind,uint32_t slot,const Value & target) const53 HeapSlot::preconditionForWriteBarrierPost(NativeObject* obj, Kind kind, uint32_t slot,
54 const Value& target) const
55 {
56 bool isCorrectSlot = kind == Slot
57 ? obj->getSlotAddressUnchecked(slot)->get() == target
58 : static_cast<HeapSlot*>(obj->getDenseElements() + slot)->get() == target;
59 bool isBlackToGray = target.isMarkable() &&
60 IsMarkedBlack(obj) && JS::GCThingIsMarkedGray(JS::GCCellPtr(target));
61 return isCorrectSlot && !isBlackToGray;
62 }
63
64 bool
CurrentThreadIsIonCompiling()65 CurrentThreadIsIonCompiling()
66 {
67 return TlsPerThreadData.get()->ionCompiling;
68 }
69
70 bool
CurrentThreadIsIonCompilingSafeForMinorGC()71 CurrentThreadIsIonCompilingSafeForMinorGC()
72 {
73 return TlsPerThreadData.get()->ionCompilingSafeForMinorGC;
74 }
75
76 bool
CurrentThreadIsGCSweeping()77 CurrentThreadIsGCSweeping()
78 {
79 return TlsPerThreadData.get()->gcSweeping;
80 }
81
82 #endif // DEBUG
83
84 template <typename S>
85 template <typename T>
86 void
operator ()(T * t)87 ReadBarrierFunctor<S>::operator()(T* t)
88 {
89 InternalBarrierMethods<T*>::readBarrier(t);
90 }
91
92 // All GC things may be held in a Value, either publicly or as a private GC
93 // thing.
94 #define JS_EXPAND_DEF(name, type, _) \
95 template void ReadBarrierFunctor<JS::Value>::operator()<type>(type*);
96 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
97 #undef JS_EXPAND_DEF
98
99 template <typename S>
100 template <typename T>
101 void
operator ()(T * t)102 PreBarrierFunctor<S>::operator()(T* t)
103 {
104 InternalBarrierMethods<T*>::preBarrier(t);
105 }
106
107 // All GC things may be held in a Value, either publicly or as a private GC
108 // thing.
109 #define JS_EXPAND_DEF(name, type, _) \
110 template void PreBarrierFunctor<JS::Value>::operator()<type>(type*);
111 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
112 #undef JS_EXPAND_DEF
113
114 template void PreBarrierFunctor<jsid>::operator()<JS::Symbol>(JS::Symbol*);
115 template void PreBarrierFunctor<jsid>::operator()<JSString>(JSString*);
116
117 template <typename T>
118 /* static */ bool
hasHash(const Lookup & l)119 MovableCellHasher<T>::hasHash(const Lookup& l)
120 {
121 if (!l)
122 return true;
123
124 return l->zoneFromAnyThread()->hasUniqueId(l);
125 }
126
127 template <typename T>
128 /* static */ bool
ensureHash(const Lookup & l)129 MovableCellHasher<T>::ensureHash(const Lookup& l)
130 {
131 if (!l)
132 return true;
133
134 uint64_t unusedId;
135 return l->zoneFromAnyThread()->getUniqueId(l, &unusedId);
136 }
137
138 template <typename T>
139 /* static */ HashNumber
hash(const Lookup & l)140 MovableCellHasher<T>::hash(const Lookup& l)
141 {
142 if (!l)
143 return 0;
144
145 // We have to access the zone from-any-thread here: a worker thread may be
146 // cloning a self-hosted object from the main-thread-runtime-owned self-
147 // hosting zone into the off-main-thread runtime. The zone's uid lock will
148 // protect against multiple workers doing this simultaneously.
149 MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) ||
150 l->zoneFromAnyThread()->isSelfHostingZone());
151
152 return l->zoneFromAnyThread()->getHashCodeInfallible(l);
153 }
154
155 template <typename T>
156 /* static */ bool
match(const Key & k,const Lookup & l)157 MovableCellHasher<T>::match(const Key& k, const Lookup& l)
158 {
159 // Return true if both are null or false if only one is null.
160 if (!k)
161 return !l;
162 if (!l)
163 return false;
164
165 MOZ_ASSERT(k);
166 MOZ_ASSERT(l);
167 MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) ||
168 l->zoneFromAnyThread()->isSelfHostingZone());
169
170 Zone* zone = k->zoneFromAnyThread();
171 if (zone != l->zoneFromAnyThread())
172 return false;
173 MOZ_ASSERT(zone->hasUniqueId(k));
174 MOZ_ASSERT(zone->hasUniqueId(l));
175
176 // Since both already have a uid (from hash), the get is infallible.
177 return zone->getUniqueIdInfallible(k) == zone->getUniqueIdInfallible(l);
178 }
179
180 #ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING
181 #pragma GCC diagnostic push
182 #pragma GCC diagnostic ignored "-Wattributes"
183 #endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING
184
185 template struct JS_PUBLIC_API(MovableCellHasher<JSObject*>);
186 template struct JS_PUBLIC_API(MovableCellHasher<GlobalObject*>);
187 template struct JS_PUBLIC_API(MovableCellHasher<SavedFrame*>);
188 template struct JS_PUBLIC_API(MovableCellHasher<EnvironmentObject*>);
189 template struct JS_PUBLIC_API(MovableCellHasher<WasmInstanceObject*>);
190 template struct JS_PUBLIC_API(MovableCellHasher<JSScript*>);
191
192 #ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING
193 #pragma GCC diagnostic pop
194 #endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING
195
196 } // namespace js
197
JS_PUBLIC_API(void)198 JS_PUBLIC_API(void)
199 JS::HeapObjectPostBarrier(JSObject** objp, JSObject* prev, JSObject* next)
200 {
201 MOZ_ASSERT(objp);
202 js::InternalBarrierMethods<JSObject*>::postBarrier(objp, prev, next);
203 }
204
JS_PUBLIC_API(void)205 JS_PUBLIC_API(void)
206 JS::HeapValuePostBarrier(JS::Value* valuep, const Value& prev, const Value& next)
207 {
208 MOZ_ASSERT(valuep);
209 js::InternalBarrierMethods<JS::Value>::postBarrier(valuep, prev, next);
210 }
211