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 // GC Policy Mechanism
8 
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).
13 //
14 // The GCPolicy provides at a minimum:
15 //
16 //   static T initial()
17 //       - Construct and return an empty T.
18 //
19 //   static void trace(JSTracer, T* tp, const char* name)
20 //       - Trace the edge |*tp|, calling the edge |name|. Containers like
21 //         GCHashMap and GCHashSet use this method to trace their children.
22 //
23 //   static bool needsSweep(T* tp)
24 //       - Return true if |*tp| is about to be finalized. Otherwise, update the
25 //         edge for moving GC, and return false. Containers like GCHashMap and
26 //         GCHashSet use this method to decide when to remove an entry: if this
27 //         function returns true on a key/value/member/etc, its entry is dropped
28 //         from the container. Specializing this method is the standard way to
29 //         get custom weak behavior from a container type.
30 //
31 // The default GCPolicy<T> assumes that T has a default constructor and |trace|
32 // and |needsSweep| methods, and forwards to them. GCPolicy has appropriate
33 // specializations for pointers to GC things and pointer-like types like
34 // JS::Heap<T> and mozilla::UniquePtr<T>.
35 //
36 // There are some stock structs your specializations can inherit from.
37 // IgnoreGCPolicy<T> does nothing. StructGCPolicy<T> forwards the methods to the
38 // referent type T.
39 
40 #ifndef GCPolicyAPI_h
41 #define GCPolicyAPI_h
42 
43 #include "mozilla/UniquePtr.h"
44 
45 #include "js/TraceKind.h"
46 #include "js/TracingAPI.h"
47 
48 // Expand the given macro D for each public GC pointer.
49 #define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \
50     D(JS::Symbol*) \
51     D(JSAtom*) \
52     D(JSFunction*) \
53     D(JSObject*) \
54     D(JSScript*) \
55     D(JSString*)
56 
57 // Expand the given macro D for each public tagged GC pointer type.
58 #define FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(D) \
59     D(JS::Value) \
60     D(jsid)
61 
62 #define FOR_EACH_PUBLIC_AGGREGATE_GC_POINTER_TYPE(D) \
63     D(JSPropertyDescriptor)
64 
65 class JSAtom;
66 class JSFunction;
67 class JSObject;
68 class JSScript;
69 class JSString;
70 namespace JS {
71 class Symbol;
72 }
73 
74 namespace JS {
75 
76 // Defines a policy for container types with non-GC, i.e. C storage. This
77 // policy dispatches to the underlying struct for GC interactions.
78 template <typename T>
79 struct StructGCPolicy
80 {
initialStructGCPolicy81     static T initial() {
82         return T();
83     }
84 
traceStructGCPolicy85     static void trace(JSTracer* trc, T* tp, const char* name) {
86         tp->trace(trc);
87     }
88 
sweepStructGCPolicy89     static void sweep(T* tp) {
90         return tp->sweep();
91     }
92 
needsSweepStructGCPolicy93     static bool needsSweep(T* tp) {
94         return tp->needsSweep();
95     }
96 };
97 
98 // The default GC policy attempts to defer to methods on the underlying type.
99 // Most C++ structures that contain a default constructor, a trace function and
100 // a sweep function will work out of the box with Rooted, Handle, GCVector,
101 // and GCHash{Set,Map}.
102 template <typename T> struct GCPolicy : public StructGCPolicy<T> {};
103 
104 // This policy ignores any GC interaction, e.g. for non-GC types.
105 template <typename T>
106 struct IgnoreGCPolicy {
initialIgnoreGCPolicy107     static T initial() { return T(); }
traceIgnoreGCPolicy108     static void trace(JSTracer* trc, T* t, const char* name) {}
needsSweepIgnoreGCPolicy109     static bool needsSweep(T* v) { return false; }
110 };
111 template <> struct GCPolicy<uint32_t> : public IgnoreGCPolicy<uint32_t> {};
112 template <> struct GCPolicy<uint64_t> : public IgnoreGCPolicy<uint64_t> {};
113 
114 template <typename T>
115 struct GCPointerPolicy
116 {
117     static T initial() { return nullptr; }
118     static void trace(JSTracer* trc, T* vp, const char* name) {
119         if (*vp)
120             js::UnsafeTraceManuallyBarrieredEdge(trc, vp, name);
121     }
122     static bool needsSweep(T* vp) {
123         if (*vp)
124             return js::gc::IsAboutToBeFinalizedUnbarriered(vp);
125         return false;
126     }
127 };
128 template <> struct GCPolicy<JS::Symbol*> : public GCPointerPolicy<JS::Symbol*> {};
129 template <> struct GCPolicy<JSAtom*> : public GCPointerPolicy<JSAtom*> {};
130 template <> struct GCPolicy<JSFunction*> : public GCPointerPolicy<JSFunction*> {};
131 template <> struct GCPolicy<JSObject*> : public GCPointerPolicy<JSObject*> {};
132 template <> struct GCPolicy<JSScript*> : public GCPointerPolicy<JSScript*> {};
133 template <> struct GCPolicy<JSString*> : public GCPointerPolicy<JSString*> {};
134 
135 template <typename T>
136 struct GCPolicy<JS::Heap<T>>
137 {
138     static void trace(JSTracer* trc, JS::Heap<T>* thingp, const char* name) {
139         TraceEdge(trc, thingp, name);
140     }
141     static bool needsSweep(JS::Heap<T>* thingp) {
142         return js::gc::EdgeNeedsSweep(thingp);
143     }
144 };
145 
146 // GCPolicy<UniquePtr<T>> forwards the contained pointer to GCPolicy<T>.
147 template <typename T, typename D>
148 struct GCPolicy<mozilla::UniquePtr<T, D>>
149 {
150     static mozilla::UniquePtr<T,D> initial() { return mozilla::UniquePtr<T,D>(); }
151     static void trace(JSTracer* trc, mozilla::UniquePtr<T,D>* tp, const char* name) {
152         if (tp->get())
153             GCPolicy<T>::trace(trc, tp->get(), name);
154     }
155     static bool needsSweep(mozilla::UniquePtr<T,D>* tp) {
156         if (tp->get())
157             return GCPolicy<T>::needsSweep(tp->get());
158         return false;
159     }
160 };
161 
162 } // namespace JS
163 
164 #endif // GCPolicyAPI_h
165