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/Maybe.h" 44 #include "mozilla/UniquePtr.h" 45 46 #include "js/TraceKind.h" 47 #include "js/TracingAPI.h" 48 #include "js/TypeDecls.h" 49 50 // Expand the given macro D for each public GC pointer. 51 #define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \ 52 D(JS::Symbol*) \ 53 D(JSAtom*) \ 54 D(JSFunction*) \ 55 D(JSObject*) \ 56 D(JSScript*) \ 57 D(JSString*) 58 59 // Expand the given macro D for each public tagged GC pointer type. 60 #define FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(D) \ 61 D(JS::Value) \ 62 D(jsid) 63 64 #define FOR_EACH_PUBLIC_AGGREGATE_GC_POINTER_TYPE(D) D(JSPropertyDescriptor) 65 66 namespace JS { 67 68 // Defines a policy for container types with non-GC, i.e. C storage. This 69 // policy dispatches to the underlying struct for GC interactions. 70 template <typename T> 71 struct StructGCPolicy { initialStructGCPolicy72 static T initial() { return T(); } 73 traceStructGCPolicy74 static void trace(JSTracer* trc, T* tp, const char* name) { tp->trace(trc); } 75 sweepStructGCPolicy76 static void sweep(T* tp) { return tp->sweep(); } 77 needsSweepStructGCPolicy78 static bool needsSweep(T* tp) { return tp->needsSweep(); } 79 isValidStructGCPolicy80 static bool isValid(const T& tp) { return true; } 81 }; 82 83 // The default GC policy attempts to defer to methods on the underlying type. 84 // Most C++ structures that contain a default constructor, a trace function and 85 // a sweep function will work out of the box with Rooted, Handle, GCVector, 86 // and GCHash{Set,Map}. 87 template <typename T> 88 struct GCPolicy : public StructGCPolicy<T> {}; 89 90 // This policy ignores any GC interaction, e.g. for non-GC types. 91 template <typename T> 92 struct IgnoreGCPolicy { initialIgnoreGCPolicy93 static T initial() { return T(); } traceIgnoreGCPolicy94 static void trace(JSTracer* trc, T* t, const char* name) {} needsSweepIgnoreGCPolicy95 static bool needsSweep(T* v) { return false; } isValidIgnoreGCPolicy96 static bool isValid(const T& v) { return true; } 97 }; 98 template <> 99 struct GCPolicy<uint32_t> : public IgnoreGCPolicy<uint32_t> {}; 100 template <> 101 struct GCPolicy<uint64_t> : public IgnoreGCPolicy<uint64_t> {}; 102 103 template <typename T> 104 struct GCPointerPolicy { 105 static T initial() { return nullptr; } 106 static void trace(JSTracer* trc, T* vp, const char* name) { 107 if (*vp) js::UnsafeTraceManuallyBarrieredEdge(trc, vp, name); 108 } 109 static bool needsSweep(T* vp) { 110 if (*vp) return js::gc::IsAboutToBeFinalizedUnbarriered(vp); 111 return false; 112 } 113 static bool isValid(T v) { return js::gc::IsCellPointerValidOrNull(v); } 114 }; 115 template <> 116 struct GCPolicy<JS::Symbol*> : public GCPointerPolicy<JS::Symbol*> {}; 117 template <> 118 struct GCPolicy<JSAtom*> : public GCPointerPolicy<JSAtom*> {}; 119 template <> 120 struct GCPolicy<JSFunction*> : public GCPointerPolicy<JSFunction*> {}; 121 template <> 122 struct GCPolicy<JSObject*> : public GCPointerPolicy<JSObject*> {}; 123 template <> 124 struct GCPolicy<JSScript*> : public GCPointerPolicy<JSScript*> {}; 125 template <> 126 struct GCPolicy<JSString*> : public GCPointerPolicy<JSString*> {}; 127 128 template <typename T> 129 struct NonGCPointerPolicy { 130 static T initial() { return nullptr; } 131 static void trace(JSTracer* trc, T* vp, const char* name) { 132 if (*vp) (*vp)->trace(trc); 133 } 134 static bool needsSweep(T* vp) { 135 if (*vp) return (*vp)->needsSweep(); 136 return false; 137 } 138 static bool isValid(T v) { return true; } 139 }; 140 141 template <typename T> 142 struct GCPolicy<JS::Heap<T>> { 143 static void trace(JSTracer* trc, JS::Heap<T>* thingp, const char* name) { 144 TraceEdge(trc, thingp, name); 145 } 146 static bool needsSweep(JS::Heap<T>* thingp) { 147 return *thingp && js::gc::EdgeNeedsSweep(thingp); 148 } 149 }; 150 151 // GCPolicy<UniquePtr<T>> forwards the contained pointer to GCPolicy<T>. 152 template <typename T, typename D> 153 struct GCPolicy<mozilla::UniquePtr<T, D>> { 154 static mozilla::UniquePtr<T, D> initial() { 155 return mozilla::UniquePtr<T, D>(); 156 } 157 static void trace(JSTracer* trc, mozilla::UniquePtr<T, D>* tp, 158 const char* name) { 159 if (tp->get()) GCPolicy<T>::trace(trc, tp->get(), name); 160 } 161 static bool needsSweep(mozilla::UniquePtr<T, D>* tp) { 162 if (tp->get()) return GCPolicy<T>::needsSweep(tp->get()); 163 return false; 164 } 165 static bool isValid(const mozilla::UniquePtr<T, D>& t) { 166 if (t.get()) return GCPolicy<T>::isValid(*t.get()); 167 return true; 168 } 169 }; 170 171 // GCPolicy<Maybe<T>> forwards tracing/sweeping to GCPolicy<T*> if 172 // when the Maybe<T> is full. 173 template <typename T> 174 struct GCPolicy<mozilla::Maybe<T>> { 175 static mozilla::Maybe<T> initial() { return mozilla::Maybe<T>(); } 176 static void trace(JSTracer* trc, mozilla::Maybe<T>* tp, const char* name) { 177 if (tp->isSome()) GCPolicy<T>::trace(trc, tp->ptr(), name); 178 } 179 static bool needsSweep(mozilla::Maybe<T>* tp) { 180 if (tp->isSome()) return GCPolicy<T>::needsSweep(tp->ptr()); 181 return false; 182 } 183 static bool isValid(const mozilla::Maybe<T>& t) { 184 if (t.isSome()) return GCPolicy<T>::isValid(t.ref()); 185 return true; 186 } 187 }; 188 189 template <> 190 struct GCPolicy<JS::Realm*>; // see Realm.h 191 192 } // namespace JS 193 194 #endif // GCPolicyAPI_h 195