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