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 #include "gc/GCInternals.h"
10 #include "vm/Runtime.h"
12 #include "gc/PrivateIterators-inl.h"
15 using namespace js::gc
;
17 static void IterateRealmsArenasCellsUnbarriered(
18 JSContext
* cx
, Zone
* zone
, void* data
,
19 JS::IterateRealmCallback realmCallback
, IterateArenaCallback arenaCallback
,
20 IterateCellCallback cellCallback
, const JS::AutoRequireNoGC
& nogc
) {
22 Rooted
<Realm
*> realm(cx
);
23 for (RealmsInZoneIter
r(zone
); !r
.done(); r
.next()) {
25 (*realmCallback
)(cx
, data
, realm
, nogc
);
29 for (auto thingKind
: AllAllocKinds()) {
30 JS::TraceKind traceKind
= MapAllocToTraceKind(thingKind
);
31 size_t thingSize
= Arena::thingSize(thingKind
);
33 for (ArenaIter
aiter(zone
, thingKind
); !aiter
.done(); aiter
.next()) {
34 Arena
* arena
= aiter
.get();
35 (*arenaCallback
)(cx
->runtime(), data
, arena
, traceKind
, thingSize
, nogc
);
36 for (ArenaCellIter
cell(arena
); !cell
.done(); cell
.next()) {
37 (*cellCallback
)(cx
->runtime(), data
, JS::GCCellPtr(cell
, traceKind
),
44 void js::IterateHeapUnbarriered(JSContext
* cx
, void* data
,
45 IterateZoneCallback zoneCallback
,
46 JS::IterateRealmCallback realmCallback
,
47 IterateArenaCallback arenaCallback
,
48 IterateCellCallback cellCallback
) {
49 AutoPrepareForTracing
prep(cx
);
50 JS::AutoSuppressGCAnalysis
nogc(cx
);
52 auto iterateZone
= [&](Zone
* zone
) -> void {
53 (*zoneCallback
)(cx
->runtime(), data
, zone
, nogc
);
54 IterateRealmsArenasCellsUnbarriered(cx
, zone
, data
, realmCallback
,
55 arenaCallback
, cellCallback
, nogc
);
58 // Include the shared atoms zone if present.
59 if (Zone
* zone
= cx
->runtime()->gc
.maybeSharedAtomsZone()) {
63 for (ZonesIter
zone(cx
->runtime(), WithAtoms
); !zone
.done(); zone
.next()) {
68 void js::IterateHeapUnbarrieredForZone(JSContext
* cx
, Zone
* zone
, void* data
,
69 IterateZoneCallback zoneCallback
,
70 JS::IterateRealmCallback realmCallback
,
71 IterateArenaCallback arenaCallback
,
72 IterateCellCallback cellCallback
) {
73 AutoPrepareForTracing
prep(cx
);
74 JS::AutoSuppressGCAnalysis
nogc(cx
);
76 (*zoneCallback
)(cx
->runtime(), data
, zone
, nogc
);
77 IterateRealmsArenasCellsUnbarriered(cx
, zone
, data
, realmCallback
,
78 arenaCallback
, cellCallback
, nogc
);
81 void js::IterateChunks(JSContext
* cx
, void* data
,
82 IterateChunkCallback chunkCallback
) {
83 AutoPrepareForTracing
prep(cx
);
84 AutoLockGC
lock(cx
->runtime());
85 JS::AutoSuppressGCAnalysis
nogc(cx
);
87 for (auto chunk
= cx
->runtime()->gc
.allNonEmptyChunks(lock
); !chunk
.done();
89 chunkCallback(cx
->runtime(), data
, chunk
, nogc
);
93 static void TraverseInnerLazyScriptsForLazyScript(
94 JSContext
* cx
, void* data
, BaseScript
* enclosingScript
,
95 IterateScriptCallback lazyScriptCallback
, const JS::AutoRequireNoGC
& nogc
) {
96 for (JS::GCCellPtr gcThing
: enclosingScript
->gcthings()) {
97 if (!gcThing
.is
<JSObject
>()) {
100 JSObject
* obj
= &gcThing
.as
<JSObject
>();
102 MOZ_ASSERT(obj
->is
<JSFunction
>(),
103 "All objects in lazy scripts should be functions");
104 JSFunction
* fun
= &obj
->as
<JSFunction
>();
106 if (!fun
->hasBaseScript()) {
110 MOZ_ASSERT(fun
->baseScript());
111 if (!fun
->baseScript()) {
112 // If the function doesn't have script, ignore it.
116 if (fun
->hasBytecode()) {
117 // Ignore non lazy function.
121 // If the function is "ghost", we shouldn't expose it to the debugger.
123 // See GHOST_FUNCTION in FunctionFlags.h for more details.
124 if (fun
->isGhost()) {
128 BaseScript
* script
= fun
->baseScript();
129 MOZ_ASSERT_IF(script
->hasEnclosingScript(),
130 script
->enclosingScript() == enclosingScript
);
132 lazyScriptCallback(cx
->runtime(), data
, script
, nogc
);
134 TraverseInnerLazyScriptsForLazyScript(cx
, data
, script
, lazyScriptCallback
,
139 static inline void DoScriptCallback(JSContext
* cx
, void* data
,
141 IterateScriptCallback callback
,
142 const JS::AutoRequireNoGC
& nogc
) {
143 // Exclude any scripts that may be the result of a failed compile. Check that
144 // script either has bytecode or is ready to delazify.
146 // This excludes lazy scripts that do not have an enclosing scope because we
147 // cannot distinguish a failed compile fragment from a lazy script with a lazy
149 if (!script
->hasBytecode() && !script
->isReadyForDelazification()) {
154 callback(cx
->runtime(), data
, script
, nogc
);
156 // The check above excluded lazy scripts with lazy parents, so explicitly
157 // visit inner scripts now if we are lazy with a successfully compiled parent.
158 if (!script
->hasBytecode()) {
159 TraverseInnerLazyScriptsForLazyScript(cx
, data
, script
, callback
, nogc
);
163 void js::IterateScripts(JSContext
* cx
, Realm
* realm
, void* data
,
164 IterateScriptCallback scriptCallback
) {
165 MOZ_ASSERT(!cx
->suppressGC
);
166 AutoEmptyNurseryAndPrepareForTracing
prep(cx
);
167 JS::AutoSuppressGCAnalysis nogc
;
170 Zone
* zone
= realm
->zone();
171 for (auto iter
= zone
->cellIter
<BaseScript
>(prep
); !iter
.done();
173 if (iter
->realm() != realm
) {
176 DoScriptCallback(cx
, data
, iter
.get(), scriptCallback
, nogc
);
179 for (ZonesIter
zone(cx
->runtime(), SkipAtoms
); !zone
.done(); zone
.next()) {
180 for (auto iter
= zone
->cellIter
<BaseScript
>(prep
); !iter
.done();
182 DoScriptCallback(cx
, data
, iter
.get(), scriptCallback
, nogc
);
188 void js::IterateGrayObjects(Zone
* zone
, IterateGCThingCallback cellCallback
,
190 MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
192 JSContext
* cx
= TlsContext
.get();
193 AutoPrepareForTracing
prep(cx
);
194 JS::AutoSuppressGCAnalysis
nogc(cx
);
196 for (auto kind
: ObjectAllocKinds()) {
197 for (GrayObjectIter
obj(zone
, kind
); !obj
.done(); obj
.next()) {
198 if (obj
->asTenured().isMarkedGray()) {
199 cellCallback(data
, JS::GCCellPtr(obj
.get()), nogc
);
205 JS_PUBLIC_API
void JS_IterateCompartments(
206 JSContext
* cx
, void* data
,
207 JSIterateCompartmentCallback compartmentCallback
) {
208 AutoTraceSession
session(cx
->runtime());
210 for (CompartmentsIter
c(cx
->runtime()); !c
.done(); c
.next()) {
211 if ((*compartmentCallback
)(cx
, data
, c
) ==
212 JS::CompartmentIterResult::Stop
) {
218 JS_PUBLIC_API
void JS_IterateCompartmentsInZone(
219 JSContext
* cx
, JS::Zone
* zone
, void* data
,
220 JSIterateCompartmentCallback compartmentCallback
) {
221 AutoTraceSession
session(cx
->runtime());
223 for (CompartmentsInZoneIter
c(zone
); !c
.done(); c
.next()) {
224 if ((*compartmentCallback
)(cx
, data
, c
) ==
225 JS::CompartmentIterResult::Stop
) {
231 JS_PUBLIC_API
void JS::IterateRealms(JSContext
* cx
, void* data
,
232 JS::IterateRealmCallback realmCallback
) {
233 AutoTraceSession
session(cx
->runtime());
234 JS::AutoSuppressGCAnalysis
nogc(cx
);
236 Rooted
<Realm
*> realm(cx
);
237 for (RealmsIter
r(cx
->runtime()); !r
.done(); r
.next()) {
239 (*realmCallback
)(cx
, data
, realm
, nogc
);
243 JS_PUBLIC_API
void JS::IterateRealmsWithPrincipals(
244 JSContext
* cx
, JSPrincipals
* principals
, void* data
,
245 JS::IterateRealmCallback realmCallback
) {
246 MOZ_ASSERT(principals
);
248 AutoTraceSession
session(cx
->runtime());
249 JS::AutoSuppressGCAnalysis
nogc(cx
);
251 Rooted
<Realm
*> realm(cx
);
252 for (RealmsIter
r(cx
->runtime()); !r
.done(); r
.next()) {
253 if (r
->principals() != principals
) {
257 (*realmCallback
)(cx
, data
, realm
, nogc
);
261 JS_PUBLIC_API
void JS::IterateRealmsInCompartment(
262 JSContext
* cx
, JS::Compartment
* compartment
, void* data
,
263 JS::IterateRealmCallback realmCallback
) {
264 AutoTraceSession
session(cx
->runtime());
265 JS::AutoSuppressGCAnalysis
nogc(cx
);
267 Rooted
<Realm
*> realm(cx
);
268 for (RealmsInCompartmentIter
r(compartment
); !r
.done(); r
.next()) {
270 (*realmCallback
)(cx
, data
, realm
, nogc
);