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 #ifndef js_GCVector_h
8 #define js_GCVector_h
9 
10 #include "mozilla/Vector.h"
11 
12 #include "js/GCPolicyAPI.h"
13 #include "js/RootingAPI.h"
14 #include "js/TracingAPI.h"
15 #include "js/Vector.h"
16 
17 namespace JS {
18 
19 // A GCVector is a Vector with an additional trace method that knows how
20 // to visit all of the items stored in the Vector. For vectors that contain GC
21 // things, this is usually more convenient than manually iterating and marking
22 // the contents.
23 //
24 // Most types of GC pointers as keys and values can be traced with no extra
25 // infrastructure. For structs and non-gc-pointer members, ensure that there is
26 // a specialization of GCPolicy<T> with an appropriate trace method available
27 // to handle the custom type. Generic helpers can be found in
28 // js/public/TracingAPI.h.
29 //
30 // Note that although this Vector's trace will deal correctly with moved items,
31 // it does not itself know when to barrier or trace items. To function properly
32 // it must either be used with Rooted, or barriered and traced manually.
33 template <typename T, size_t MinInlineCapacity = 0,
34           typename AllocPolicy = js::TempAllocPolicy>
35 class GCVector {
36   mozilla::Vector<T, MinInlineCapacity, AllocPolicy> vector;
37 
38  public:
vector(alloc)39   explicit GCVector(AllocPolicy alloc = AllocPolicy()) : vector(alloc) {}
40 
GCVector(GCVector && vec)41   GCVector(GCVector&& vec) : vector(mozilla::Move(vec.vector)) {}
42 
43   GCVector& operator=(GCVector&& vec) {
44     vector = mozilla::Move(vec.vector);
45     return *this;
46   }
47 
length()48   size_t length() const { return vector.length(); }
empty()49   bool empty() const { return vector.empty(); }
capacity()50   size_t capacity() const { return vector.capacity(); }
51 
begin()52   T* begin() { return vector.begin(); }
begin()53   const T* begin() const { return vector.begin(); }
54 
end()55   T* end() { return vector.end(); }
end()56   const T* end() const { return vector.end(); }
57 
58   T& operator[](size_t i) { return vector[i]; }
59   const T& operator[](size_t i) const { return vector[i]; }
60 
back()61   T& back() { return vector.back(); }
back()62   const T& back() const { return vector.back(); }
63 
initCapacity(size_t cap)64   bool initCapacity(size_t cap) { return vector.initCapacity(cap); }
reserve(size_t req)65   MOZ_MUST_USE bool reserve(size_t req) { return vector.reserve(req); }
shrinkBy(size_t amount)66   void shrinkBy(size_t amount) { return vector.shrinkBy(amount); }
growBy(size_t amount)67   MOZ_MUST_USE bool growBy(size_t amount) { return vector.growBy(amount); }
resize(size_t newLen)68   MOZ_MUST_USE bool resize(size_t newLen) { return vector.resize(newLen); }
69 
clear()70   void clear() { return vector.clear(); }
clearAndFree()71   void clearAndFree() { return vector.clearAndFree(); }
72 
73   template <typename U>
append(U && item)74   bool append(U&& item) {
75     return vector.append(mozilla::Forward<U>(item));
76   }
77 
78   template <typename... Args>
emplaceBack(Args &&...args)79   MOZ_MUST_USE bool emplaceBack(Args&&... args) {
80     return vector.emplaceBack(mozilla::Forward<Args>(args)...);
81   }
82 
83   template <typename U>
infallibleAppend(U && aU)84   void infallibleAppend(U&& aU) {
85     return vector.infallibleAppend(mozilla::Forward<U>(aU));
86   }
infallibleAppendN(const T & aT,size_t aN)87   void infallibleAppendN(const T& aT, size_t aN) {
88     return vector.infallibleAppendN(aT, aN);
89   }
90   template <typename U>
infallibleAppend(const U * aBegin,const U * aEnd)91   void infallibleAppend(const U* aBegin, const U* aEnd) {
92     return vector.infallibleAppend(aBegin, aEnd);
93   }
94   template <typename U>
infallibleAppend(const U * aBegin,size_t aLength)95   void infallibleAppend(const U* aBegin, size_t aLength) {
96     return vector.infallibleAppend(aBegin, aLength);
97   }
98 
99   template <typename U>
appendAll(const U & aU)100   MOZ_MUST_USE bool appendAll(const U& aU) {
101     return vector.append(aU.begin(), aU.end());
102   }
103 
appendN(const T & val,size_t count)104   MOZ_MUST_USE bool appendN(const T& val, size_t count) {
105     return vector.appendN(val, count);
106   }
107 
108   template <typename U>
append(const U * aBegin,const U * aEnd)109   MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) {
110     return vector.append(aBegin, aEnd);
111   }
112   template <typename U>
append(const U * aBegin,size_t aLength)113   MOZ_MUST_USE bool append(const U* aBegin, size_t aLength) {
114     return vector.append(aBegin, aLength);
115   }
116 
popBack()117   void popBack() { return vector.popBack(); }
popCopy()118   T popCopy() { return vector.popCopy(); }
119 
sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)120   size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
121     return vector.sizeOfExcludingThis(mallocSizeOf);
122   }
123 
sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)124   size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
125     return vector.sizeOfIncludingThis(mallocSizeOf);
126   }
127 
trace(GCVector * vec,JSTracer * trc)128   static void trace(GCVector* vec, JSTracer* trc) { vec->trace(trc); }
129 
trace(JSTracer * trc)130   void trace(JSTracer* trc) {
131     for (auto& elem : vector) GCPolicy<T>::trace(trc, &elem, "vector element");
132   }
133 
needsSweep()134   bool needsSweep() const { return !this->empty(); }
135 
sweep()136   void sweep() {
137     uint32_t src, dst = 0;
138     for (src = 0; src < length(); src++) {
139       if (!GCPolicy<T>::needsSweep(&vector[src])) {
140         if (dst != src) vector[dst] = vector[src].unbarrieredGet();
141         dst++;
142       }
143     }
144 
145     if (dst != length()) vector.shrinkTo(dst);
146   }
147 };
148 
149 }  // namespace JS
150 
151 namespace js {
152 
153 template <typename Wrapper, typename T, size_t Capacity, typename AllocPolicy>
154 class WrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrapper> {
155   using Vec = JS::GCVector<T, Capacity, AllocPolicy>;
vec()156   const Vec& vec() const { return static_cast<const Wrapper*>(this)->get(); }
157 
158  public:
allocPolicy()159   const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); }
length()160   size_t length() const { return vec().length(); }
empty()161   bool empty() const { return vec().empty(); }
capacity()162   size_t capacity() const { return vec().capacity(); }
begin()163   const T* begin() const { return vec().begin(); }
end()164   const T* end() const { return vec().end(); }
back()165   const T& back() const { return vec().back(); }
166 
167   JS::Handle<T> operator[](size_t aIndex) const {
168     return JS::Handle<T>::fromMarkedLocation(&vec().operator[](aIndex));
169   }
170 };
171 
172 template <typename Wrapper, typename T, size_t Capacity, typename AllocPolicy>
173 class MutableWrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>,
174                                   Wrapper>
175     : public WrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>,
176                                   Wrapper> {
177   using Vec = JS::GCVector<T, Capacity, AllocPolicy>;
vec()178   const Vec& vec() const { return static_cast<const Wrapper*>(this)->get(); }
vec()179   Vec& vec() { return static_cast<Wrapper*>(this)->get(); }
180 
181  public:
allocPolicy()182   const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); }
allocPolicy()183   AllocPolicy& allocPolicy() { return vec().allocPolicy(); }
begin()184   const T* begin() const { return vec().begin(); }
begin()185   T* begin() { return vec().begin(); }
end()186   const T* end() const { return vec().end(); }
end()187   T* end() { return vec().end(); }
back()188   const T& back() const { return vec().back(); }
back()189   T& back() { return vec().back(); }
190 
191   JS::Handle<T> operator[](size_t aIndex) const {
192     return JS::Handle<T>::fromMarkedLocation(&vec().operator[](aIndex));
193   }
194   JS::MutableHandle<T> operator[](size_t aIndex) {
195     return JS::MutableHandle<T>::fromMarkedLocation(&vec().operator[](aIndex));
196   }
197 
initCapacity(size_t aRequest)198   MOZ_MUST_USE bool initCapacity(size_t aRequest) {
199     return vec().initCapacity(aRequest);
200   }
reserve(size_t aRequest)201   MOZ_MUST_USE bool reserve(size_t aRequest) { return vec().reserve(aRequest); }
shrinkBy(size_t aIncr)202   void shrinkBy(size_t aIncr) { vec().shrinkBy(aIncr); }
growBy(size_t aIncr)203   MOZ_MUST_USE bool growBy(size_t aIncr) { return vec().growBy(aIncr); }
resize(size_t aNewLength)204   MOZ_MUST_USE bool resize(size_t aNewLength) {
205     return vec().resize(aNewLength);
206   }
growByUninitialized(size_t aIncr)207   MOZ_MUST_USE bool growByUninitialized(size_t aIncr) {
208     return vec().growByUninitialized(aIncr);
209   }
infallibleGrowByUninitialized(size_t aIncr)210   void infallibleGrowByUninitialized(size_t aIncr) {
211     vec().infallibleGrowByUninitialized(aIncr);
212   }
resizeUninitialized(size_t aNewLength)213   MOZ_MUST_USE bool resizeUninitialized(size_t aNewLength) {
214     return vec().resizeUninitialized(aNewLength);
215   }
clear()216   void clear() { vec().clear(); }
clearAndFree()217   void clearAndFree() { vec().clearAndFree(); }
218   template <typename U>
append(U && aU)219   MOZ_MUST_USE bool append(U&& aU) {
220     return vec().append(mozilla::Forward<U>(aU));
221   }
222   template <typename... Args>
emplaceBack(Args &&...aArgs)223   MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) {
224     return vec().emplaceBack(mozilla::Forward<Args...>(aArgs...));
225   }
226   template <typename U>
appendAll(const U & aU)227   MOZ_MUST_USE bool appendAll(const U& aU) {
228     return vec().appendAll(aU);
229   }
appendN(const T & aT,size_t aN)230   MOZ_MUST_USE bool appendN(const T& aT, size_t aN) {
231     return vec().appendN(aT, aN);
232   }
233   template <typename U>
append(const U * aBegin,const U * aEnd)234   MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) {
235     return vec().append(aBegin, aEnd);
236   }
237   template <typename U>
append(const U * aBegin,size_t aLength)238   MOZ_MUST_USE bool append(const U* aBegin, size_t aLength) {
239     return vec().append(aBegin, aLength);
240   }
241   template <typename U>
infallibleAppend(U && aU)242   void infallibleAppend(U&& aU) {
243     vec().infallibleAppend(mozilla::Forward<U>(aU));
244   }
infallibleAppendN(const T & aT,size_t aN)245   void infallibleAppendN(const T& aT, size_t aN) {
246     vec().infallibleAppendN(aT, aN);
247   }
248   template <typename U>
infallibleAppend(const U * aBegin,const U * aEnd)249   void infallibleAppend(const U* aBegin, const U* aEnd) {
250     vec().infallibleAppend(aBegin, aEnd);
251   }
252   template <typename U>
infallibleAppend(const U * aBegin,size_t aLength)253   void infallibleAppend(const U* aBegin, size_t aLength) {
254     vec().infallibleAppend(aBegin, aLength);
255   }
popBack()256   void popBack() { vec().popBack(); }
popCopy()257   T popCopy() { return vec().popCopy(); }
258   template <typename U>
insert(T * aP,U && aVal)259   T* insert(T* aP, U&& aVal) {
260     return vec().insert(aP, mozilla::Forward<U>(aVal));
261   }
erase(T * aT)262   void erase(T* aT) { vec().erase(aT); }
erase(T * aBegin,T * aEnd)263   void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); }
264 };
265 
266 }  // namespace js
267 
268 namespace JS {
269 
270 // An automatically rooted vector for stack use.
271 template <typename T>
272 class AutoVector : public Rooted<GCVector<T, 8>> {
273   using Vec = GCVector<T, 8>;
274   using Base = Rooted<Vec>;
275 
276  public:
AutoVector(JSContext * cx)277   explicit AutoVector(JSContext* cx) : Base(cx, Vec(cx)) {}
278 };
279 
280 }  // namespace JS
281 
282 #endif  // js_GCVector_h
283