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