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/. */
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
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"
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.
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}.
78 struct GCPolicy
: public StructGCPolicy
<T
> {};
80 // This policy ignores any GC interaction, e.g. for non-GC types.
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; }
88 struct GCPolicy
<uint32_t> : public IgnoreGCPolicy
<uint32_t> {};
90 struct GCPolicy
<uint64_t> : public IgnoreGCPolicy
<uint64_t> {};
92 struct GCPolicy
<bool> : public IgnoreGCPolicy
<bool> {};
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) \
110 struct GCPolicy<Type> : public GCPointerPolicy<Type> {}; \
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
) {
123 static bool traceWeak(JSTracer
* trc
, T
* vp
) {
125 return (*vp
)->traceWeak(trc
);
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
,
149 GCPolicy
<T
>::trace(trc
, tp
->get(), name
);
152 static bool traceWeak(JSTracer
* trc
, mozilla::UniquePtr
<T
, D
>* tp
) {
154 return GCPolicy
<T
>::traceWeak(trc
, tp
->get());
158 static bool isValid(const mozilla::UniquePtr
<T
, D
>& t
) {
160 return GCPolicy
<T
>::isValid(*t
.get());
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
) {
175 GCPolicy
<T
>::trace(trc
, tp
->ptr(), name
);
178 static bool traceWeak(JSTracer
* trc
, mozilla::Maybe
<T
>* tp
) {
180 return GCPolicy
<T
>::traceWeak(trc
, tp
->ptr());
184 static bool isValid(const mozilla::Maybe
<T
>& t
) {
186 return GCPolicy
<T
>::isValid(t
.ref());
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
);
208 struct GCPolicy
<JS::Realm
*>; // see Realm.h
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
,
218 V tmp
= tp
->unwrap();
219 JS::GCPolicy
<V
>::trace(trc
, &tmp
, "Result value");
220 tp
->updateAfterTracing(std::move(tmp
));
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; }
235 #endif // GCPolicyAPI_h