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