blob: 43c9e0fd372a1a9b6f4e114f455d7305ee6bab27 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef gc_GCInternals_h
#define gc_GCInternals_h
#include "mozilla/ArrayUtils.h"
#include "mozilla/Maybe.h"
#include "jscntxt.h"
#include "gc/Zone.h"
#include "vm/HelperThreads.h"
#include "vm/Runtime.h"
namespace js {
namespace gc {
void FinishGC(JSContext* cx);
/*
* This class should be used by any code that needs to exclusive access to the
* heap in order to trace through it...
*/
class MOZ_RAII AutoTraceSession
{
public:
explicit AutoTraceSession(JSRuntime* rt, JS::HeapState state = JS::HeapState::Tracing);
~AutoTraceSession();
// Threads with an exclusive context can hit refillFreeList while holding
// the exclusive access lock. To avoid deadlocking when we try to acquire
// this lock during GC and the other thread is waiting, make sure we hold
// the exclusive access lock during GC sessions.
AutoLockForExclusiveAccess lock;
protected:
JSRuntime* runtime;
private:
AutoTraceSession(const AutoTraceSession&) = delete;
void operator=(const AutoTraceSession&) = delete;
JS::HeapState prevState;
AutoSPSEntry pseudoFrame;
};
class MOZ_RAII AutoPrepareForTracing
{
mozilla::Maybe<AutoTraceSession> session_;
public:
AutoPrepareForTracing(JSContext* cx, ZoneSelector selector);
AutoTraceSession& session() { return session_.ref(); }
};
AbortReason
IsIncrementalGCUnsafe(JSRuntime* rt);
#ifdef JSGC_HASH_TABLE_CHECKS
void CheckHashTablesAfterMovingGC(JSRuntime* rt);
void CheckHeapAfterGC(JSRuntime* rt);
#endif
struct MovingTracer : JS::CallbackTracer
{
explicit MovingTracer(JSRuntime* rt) : CallbackTracer(rt, TraceWeakMapKeysValues) {}
void onObjectEdge(JSObject** objp) override;
void onShapeEdge(Shape** shapep) override;
void onStringEdge(JSString** stringp) override;
void onScriptEdge(JSScript** scriptp) override;
void onLazyScriptEdge(LazyScript** lazyp) override;
void onBaseShapeEdge(BaseShape** basep) override;
void onScopeEdge(Scope** basep) override;
void onChild(const JS::GCCellPtr& thing) override {
MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell()));
}
#ifdef DEBUG
TracerKind getTracerKind() const override { return TracerKind::Moving; }
#endif
};
// Structure for counting how many times objects in a particular group have
// been tenured during a minor collection.
struct TenureCount
{
ObjectGroup* group;
int count;
};
// Keep rough track of how many times we tenure objects in particular groups
// during minor collections, using a fixed size hash for efficiency at the cost
// of potential collisions.
struct TenureCountCache
{
static const size_t EntryShift = 4;
static const size_t EntryCount = 1 << EntryShift;
TenureCount entries[EntryCount] = {}; // zeroes
TenureCountCache() = default;
HashNumber hash(ObjectGroup* group) {
#if JS_BITS_PER_WORD == 32
static const size_t ZeroBits = 3;
#else
static const size_t ZeroBits = 4;
#endif
uintptr_t word = uintptr_t(group);
MOZ_ASSERT((word & ((1 << ZeroBits) - 1)) == 0);
word >>= ZeroBits;
return HashNumber((word >> EntryShift) ^ word);
}
TenureCount& findEntry(ObjectGroup* group) {
return entries[hash(group) % EntryCount];
}
};
} /* namespace gc */
} /* namespace js */
#endif /* gc_GCInternals_h */
|