Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / js / public / GCPolicyAPI.h
blobeef7ee76236faf1f4cdd5d7cde0c84c19f17b7de
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 // GC Policy Mechanism
9 // A GCPolicy controls how the GC interacts with both direct pointers to GC
10 // things (e.g. JSObject* or JSString*), tagged and/or optional pointers to GC
11 // things (e.g. Value or jsid), and C++ container types (e.g.
12 // JSPropertyDescriptor or GCHashMap).
14 // The GCPolicy provides at a minimum:
16 // static void trace(JSTracer, T* tp, const char* name)
17 // - Trace the edge |*tp|, calling the edge |name|. Containers like
18 // GCHashMap and GCHashSet use this method to trace their children.
20 // static bool traceWeak(T* tp)
21 // - Return false if |*tp| has been set to nullptr. Otherwise, update the
22 // edge for moving GC, and return true. Containers like GCHashMap and
23 // GCHashSet use this method to decide when to remove an entry: if this
24 // function returns false on a key/value/member/etc, its entry is
25 // dropped from the container. Specializing this method is the standard
26 // way to get custom weak behavior from a container type.
28 // static bool isValid(const T& t)
29 // - Return false only if |t| is corrupt in some way. The built-in GC
30 // types do some memory layout checks. For debugging only; it is ok
31 // to always return true or even to omit this member entirely.
33 // The default GCPolicy<T> assumes that T has a default constructor and |trace|
34 // and |traceWeak| methods, and forwards to them. GCPolicy has appropriate
35 // specializations for pointers to GC things and pointer-like types like
36 // JS::Heap<T> and mozilla::UniquePtr<T>.
38 // There are some stock structs your specializations can inherit from.
39 // IgnoreGCPolicy<T> does nothing. StructGCPolicy<T> forwards the methods to the
40 // referent type T.
42 #ifndef GCPolicyAPI_h
43 #define GCPolicyAPI_h
45 #include "mozilla/Maybe.h"
46 #include "mozilla/UniquePtr.h"
48 #include <type_traits>
50 #include "js/GCTypeMacros.h" // JS_FOR_EACH_PUBLIC_GC_POINTER_TYPE
51 #include "js/TraceKind.h"
52 #include "js/TracingAPI.h"
53 #include "js/TypeDecls.h"
55 namespace JS {
57 // Defines a policy for container types with non-GC, i.e. C storage. This
58 // policy dispatches to the underlying struct for GC interactions. Note that
59 // currently a type can define only the subset of the methods (trace and/or
60 // traceWeak) if it is never used in a context that requires the other.
61 template <typename T>
62 struct StructGCPolicy {
63 static_assert(!std::is_pointer_v<T>,
64 "Pointer type not allowed for StructGCPolicy");
66 static void trace(JSTracer* trc, T* tp, const char* name) { tp->trace(trc); }
68 static bool traceWeak(JSTracer* trc, T* tp) { return tp->traceWeak(trc); }
70 static bool isValid(const T& tp) { return true; }
73 // The default GC policy attempts to defer to methods on the underlying type.
74 // Most C++ structures that contain a default constructor, a trace function and
75 // a sweep function will work out of the box with Rooted, Handle, GCVector,
76 // and GCHash{Set,Map}.
77 template <typename T>
78 struct GCPolicy : public StructGCPolicy<T> {};
80 // This policy ignores any GC interaction, e.g. for non-GC types.
81 template <typename T>
82 struct IgnoreGCPolicy {
83 static void trace(JSTracer* trc, T* t, const char* name) {}
84 static bool traceWeak(JSTracer*, T* v) { return true; }
85 static bool isValid(const T& v) { return true; }
87 template <>
88 struct GCPolicy<uint32_t> : public IgnoreGCPolicy<uint32_t> {};
89 template <>
90 struct GCPolicy<uint64_t> : public IgnoreGCPolicy<uint64_t> {};
91 template <>
92 struct GCPolicy<bool> : public IgnoreGCPolicy<bool> {};
94 template <typename T>
95 struct GCPointerPolicy {
96 static_assert(std::is_pointer_v<T>,
97 "Non-pointer type not allowed for GCPointerPolicy");
99 static void trace(JSTracer* trc, T* vp, const char* name) {
100 // This should only be called as part of root marking since that's the only
101 // time we should trace unbarriered GC thing pointers. This will assert if
102 // called at other times.
103 TraceRoot(trc, vp, name);
105 static bool isTenured(T v) { return !v || !js::gc::IsInsideNursery(v); }
106 static bool isValid(T v) { return js::gc::IsCellPointerValidOrNull(v); }
108 #define EXPAND_SPECIALIZE_GCPOLICY(Type) \
109 template <> \
110 struct GCPolicy<Type> : public GCPointerPolicy<Type> {}; \
111 template <> \
112 struct GCPolicy<Type const> : public GCPointerPolicy<Type const> {};
113 JS_FOR_EACH_PUBLIC_GC_POINTER_TYPE(EXPAND_SPECIALIZE_GCPOLICY)
114 #undef EXPAND_SPECIALIZE_GCPOLICY
116 template <typename T>
117 struct NonGCPointerPolicy {
118 static void trace(JSTracer* trc, T* vp, const char* name) {
119 if (*vp) {
120 (*vp)->trace(trc);
123 static bool traceWeak(JSTracer* trc, T* vp) {
124 if (*vp) {
125 return (*vp)->traceWeak(trc);
127 return true;
130 static bool isValid(T v) { return true; }
133 template <typename T>
134 struct GCPolicy<JS::Heap<T>> {
135 static void trace(JSTracer* trc, JS::Heap<T>* thingp, const char* name) {
136 TraceEdge(trc, thingp, name);
138 static bool traceWeak(JSTracer* trc, JS::Heap<T>* thingp) {
139 return !*thingp || js::gc::TraceWeakEdge(trc, thingp);
143 // GCPolicy<UniquePtr<T>> forwards the contained pointer to GCPolicy<T>.
144 template <typename T, typename D>
145 struct GCPolicy<mozilla::UniquePtr<T, D>> {
146 static void trace(JSTracer* trc, mozilla::UniquePtr<T, D>* tp,
147 const char* name) {
148 if (tp->get()) {
149 GCPolicy<T>::trace(trc, tp->get(), name);
152 static bool traceWeak(JSTracer* trc, mozilla::UniquePtr<T, D>* tp) {
153 if (tp->get()) {
154 return GCPolicy<T>::traceWeak(trc, tp->get());
156 return true;
158 static bool isValid(const mozilla::UniquePtr<T, D>& t) {
159 if (t.get()) {
160 return GCPolicy<T>::isValid(*t.get());
162 return true;
166 template <>
167 struct GCPolicy<mozilla::Nothing> : public IgnoreGCPolicy<mozilla::Nothing> {};
169 // GCPolicy<Maybe<T>> forwards tracing/sweeping to GCPolicy<T*> if
170 // the Maybe<T> is filled and T* can be traced via GCPolicy<T*>.
171 template <typename T>
172 struct GCPolicy<mozilla::Maybe<T>> {
173 static void trace(JSTracer* trc, mozilla::Maybe<T>* tp, const char* name) {
174 if (tp->isSome()) {
175 GCPolicy<T>::trace(trc, tp->ptr(), name);
178 static bool traceWeak(JSTracer* trc, mozilla::Maybe<T>* tp) {
179 if (tp->isSome()) {
180 return GCPolicy<T>::traceWeak(trc, tp->ptr());
182 return true;
184 static bool isValid(const mozilla::Maybe<T>& t) {
185 if (t.isSome()) {
186 return GCPolicy<T>::isValid(t.ref());
188 return true;
192 template <typename T1, typename T2>
193 struct GCPolicy<std::pair<T1, T2>> {
194 static void trace(JSTracer* trc, std::pair<T1, T2>* tp, const char* name) {
195 GCPolicy<T1>::trace(trc, &tp->first, name);
196 GCPolicy<T2>::trace(trc, &tp->second, name);
198 static bool traceWeak(JSTracer* trc, std::pair<T1, T2>* tp) {
199 return GCPolicy<T1>::traceWeak(trc, &tp->first) &&
200 GCPolicy<T2>::traceWeak(trc, &tp->second);
202 static bool isValid(const std::pair<T1, T2>& t) {
203 return GCPolicy<T1>::isValid(t.first) && GCPolicy<T2>::isValid(t.second);
207 template <>
208 struct GCPolicy<JS::Realm*>; // see Realm.h
210 template <>
211 struct GCPolicy<mozilla::Ok> : public IgnoreGCPolicy<mozilla::Ok> {};
213 template <typename V, typename E>
214 struct GCPolicy<mozilla::Result<V, E>> {
215 static void trace(JSTracer* trc, mozilla::Result<V, E>* tp,
216 const char* name) {
217 if (tp->isOk()) {
218 V tmp = tp->unwrap();
219 JS::GCPolicy<V>::trace(trc, &tmp, "Result value");
220 tp->updateAfterTracing(std::move(tmp));
223 if (tp->isErr()) {
224 E tmp = tp->unwrapErr();
225 JS::GCPolicy<E>::trace(trc, &tmp, "Result error");
226 tp->updateErrorAfterTracing(std::move(tmp));
230 static bool isValid(const mozilla::Result<V, E>& t) { return true; }
233 } // namespace JS
235 #endif // GCPolicyAPI_h