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