Line data Source code
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 : #ifndef gc_GCInternals_h
8 : #define gc_GCInternals_h
9 :
10 : #include "mozilla/ArrayUtils.h"
11 : #include "mozilla/Maybe.h"
12 : #include "mozilla/PodOperations.h"
13 :
14 : #include "jscntxt.h"
15 :
16 : #include "gc/Zone.h"
17 : #include "vm/HelperThreads.h"
18 : #include "vm/Runtime.h"
19 :
20 : namespace js {
21 : namespace gc {
22 :
23 : void FinishGC(JSContext* cx);
24 :
25 : /*
26 : * This class should be used by any code that needs to exclusive access to the
27 : * heap in order to trace through it...
28 : */
29 : class MOZ_RAII AutoTraceSession
30 : {
31 : public:
32 : explicit AutoTraceSession(JSRuntime* rt, JS::HeapState state = JS::HeapState::Tracing);
33 : ~AutoTraceSession();
34 :
35 : // Threads with an exclusive context can hit refillFreeList while holding
36 : // the exclusive access lock. To avoid deadlocking when we try to acquire
37 : // this lock during GC and the other thread is waiting, make sure we hold
38 : // the exclusive access lock during GC sessions.
39 : AutoLockForExclusiveAccess lock;
40 :
41 : protected:
42 : JSRuntime* runtime;
43 :
44 : private:
45 : AutoTraceSession(const AutoTraceSession&) = delete;
46 : void operator=(const AutoTraceSession&) = delete;
47 :
48 : JS::HeapState prevState;
49 : AutoGeckoProfilerEntry pseudoFrame;
50 : };
51 :
52 0 : class MOZ_RAII AutoPrepareForTracing
53 : {
54 : mozilla::Maybe<AutoTraceSession> session_;
55 :
56 : public:
57 : AutoPrepareForTracing(JSContext* cx, ZoneSelector selector);
58 0 : AutoTraceSession& session() { return session_.ref(); }
59 : };
60 :
61 : AbortReason
62 : IsIncrementalGCUnsafe(JSRuntime* rt);
63 :
64 : #ifdef JS_GC_ZEAL
65 :
66 : class MOZ_RAII AutoStopVerifyingBarriers
67 : {
68 : GCRuntime* gc;
69 : bool restartPreVerifier;
70 :
71 : public:
72 24 : AutoStopVerifyingBarriers(JSRuntime* rt, bool isShutdown)
73 24 : : gc(&rt->gc)
74 : {
75 24 : if (gc->isVerifyPreBarriersEnabled()) {
76 0 : gc->endVerifyPreBarriers();
77 0 : restartPreVerifier = !isShutdown;
78 : } else {
79 24 : restartPreVerifier = false;
80 : }
81 24 : }
82 :
83 48 : ~AutoStopVerifyingBarriers() {
84 : // Nasty special case: verification runs a minor GC, which *may* nest
85 : // inside of an outer minor GC. This is not allowed by the
86 : // gc::Statistics phase tree. So we pause the "real" GC, if in fact one
87 : // is in progress.
88 24 : gcstats::PhaseKind outer = gc->stats().currentPhaseKind();
89 24 : if (outer != gcstats::PhaseKind::NONE)
90 21 : gc->stats().endPhase(outer);
91 24 : MOZ_ASSERT(gc->stats().currentPhaseKind() == gcstats::PhaseKind::NONE);
92 :
93 24 : if (restartPreVerifier)
94 0 : gc->startVerifyPreBarriers();
95 :
96 24 : if (outer != gcstats::PhaseKind::NONE)
97 21 : gc->stats().beginPhase(outer);
98 24 : }
99 : };
100 : #else
101 : struct MOZ_RAII AutoStopVerifyingBarriers
102 : {
103 : AutoStopVerifyingBarriers(JSRuntime*, bool) {}
104 : };
105 : #endif /* JS_GC_ZEAL */
106 :
107 : #ifdef JSGC_HASH_TABLE_CHECKS
108 : void CheckHashTablesAfterMovingGC(JSRuntime* rt);
109 : void CheckHeapAfterGC(JSRuntime* rt);
110 : #endif
111 :
112 : struct MovingTracer : JS::CallbackTracer
113 : {
114 0 : explicit MovingTracer(JSRuntime* rt) : CallbackTracer(rt, TraceWeakMapKeysValues) {}
115 :
116 : void onObjectEdge(JSObject** objp) override;
117 : void onShapeEdge(Shape** shapep) override;
118 : void onStringEdge(JSString** stringp) override;
119 : void onScriptEdge(JSScript** scriptp) override;
120 : void onLazyScriptEdge(LazyScript** lazyp) override;
121 : void onBaseShapeEdge(BaseShape** basep) override;
122 : void onScopeEdge(Scope** basep) override;
123 : void onRegExpSharedEdge(RegExpShared** sharedp) override;
124 0 : void onChild(const JS::GCCellPtr& thing) override {
125 0 : MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell()));
126 0 : }
127 :
128 : #ifdef DEBUG
129 0 : TracerKind getTracerKind() const override { return TracerKind::Moving; }
130 : #endif
131 :
132 : private:
133 : template <typename T>
134 : void updateEdge(T** thingp);
135 : };
136 :
137 : // Structure for counting how many times objects in a particular group have
138 : // been tenured during a minor collection.
139 : struct TenureCount
140 : {
141 : ObjectGroup* group;
142 : int count;
143 : };
144 :
145 : // Keep rough track of how many times we tenure objects in particular groups
146 : // during minor collections, using a fixed size hash for efficiency at the cost
147 : // of potential collisions.
148 : struct TenureCountCache
149 : {
150 : static const size_t EntryShift = 4;
151 : static const size_t EntryCount = 1 << EntryShift;
152 :
153 : TenureCount entries[EntryCount];
154 :
155 24 : TenureCountCache() { mozilla::PodZero(this); }
156 :
157 22681 : HashNumber hash(ObjectGroup* group) {
158 : #if JS_BITS_PER_WORD == 32
159 : static const size_t ZeroBits = 3;
160 : #else
161 : static const size_t ZeroBits = 4;
162 : #endif
163 :
164 22681 : uintptr_t word = uintptr_t(group);
165 22681 : MOZ_ASSERT((word & ((1 << ZeroBits) - 1)) == 0);
166 22681 : word >>= ZeroBits;
167 22681 : return HashNumber((word >> EntryShift) ^ word);
168 : }
169 :
170 22681 : TenureCount& findEntry(ObjectGroup* group) {
171 22681 : return entries[hash(group) % EntryCount];
172 : }
173 : };
174 :
175 : } /* namespace gc */
176 : } /* namespace js */
177 :
178 : #endif /* gc_GCInternals_h */
|