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_TraceableFifo_h
8 #define js_TraceableFifo_h
9 
10 #include "ds/Fifo.h"
11 #include "js/RootingAPI.h"
12 #include "js/TracingAPI.h"
13 
14 namespace js {
15 
16 // A TraceableFifo is a Fifo with an additional trace method that knows how to
17 // visit all of the items stored in the Fifo. For Fifos that contain GC things,
18 // this is usually more convenient than manually iterating and marking the
19 // contents.
20 //
21 // Most types of GC pointers as keys and values can be traced with no extra
22 // infrastructure. For structs and non-gc-pointer members, ensure that there is
23 // a specialization of GCPolicy<T> with an appropriate trace method available
24 // to handle the custom type. Generic helpers can be found in
25 // js/public/TracingAPI.h. Generic helpers can be found in
26 // js/public/TracingAPI.h.
27 //
28 // Note that although this Fifo's trace will deal correctly with moved items, it
29 // does not itself know when to barrier or trace items. To function properly it
30 // must either be used with Rooted, or barriered and traced manually.
31 template <typename T,
32           size_t MinInlineCapacity = 0,
33           typename AllocPolicy = TempAllocPolicy>
34 class TraceableFifo : public js::Fifo<T, MinInlineCapacity, AllocPolicy>
35 {
36     using Base = js::Fifo<T, MinInlineCapacity, AllocPolicy>;
37 
38   public:
Base(alloc)39     explicit TraceableFifo(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {}
40 
TraceableFifo(TraceableFifo && rhs)41     TraceableFifo(TraceableFifo&& rhs) : Base(mozilla::Move(rhs)) { }
42     TraceableFifo& operator=(TraceableFifo&& rhs) { return Base::operator=(mozilla::Move(rhs)); }
43 
44     TraceableFifo(const TraceableFifo&) = delete;
45     TraceableFifo& operator=(const TraceableFifo&) = delete;
46 
trace(JSTracer * trc)47     void trace(JSTracer* trc) {
48         for (size_t i = 0; i < this->front_.length(); ++i)
49             JS::GCPolicy<T>::trace(trc, &this->front_[i], "fifo element");
50         for (size_t i = 0; i < this->rear_.length(); ++i)
51             JS::GCPolicy<T>::trace(trc, &this->rear_[i], "fifo element");
52     }
53 };
54 
55 template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
56 class TraceableFifoOperations
57 {
58     using TF = TraceableFifo<T, Capacity, AllocPolicy>;
fifo()59     const TF& fifo() const { return static_cast<const Outer*>(this)->extract(); }
60 
61   public:
length()62     size_t length() const { return fifo().length(); }
empty()63     bool empty() const { return fifo().empty(); }
front()64     const T& front() const { return fifo().front(); }
65 };
66 
67 template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
68 class MutableTraceableFifoOperations
69   : public TraceableFifoOperations<Outer, T, Capacity, AllocPolicy>
70 {
71     using TF = TraceableFifo<T, Capacity, AllocPolicy>;
fifo()72     TF& fifo() { return static_cast<Outer*>(this)->extract(); }
73 
74   public:
front()75     T& front() { return fifo().front(); }
76 
pushBack(U && u)77     template<typename U> bool pushBack(U&& u) { return fifo().pushBack(mozilla::Forward<U>(u)); }
emplaceBack(Args &&...args)78     template<typename... Args> bool emplaceBack(Args&&... args) {
79         return fifo().emplaceBack(mozilla::Forward<Args...>(args...));
80     }
81 
popFront()82     bool popFront() { return fifo().popFront(); }
clear()83     void clear() { fifo().clear(); }
84 };
85 
86 template <typename A, size_t B, typename C>
87 class RootedBase<TraceableFifo<A,B,C>>
88   : public MutableTraceableFifoOperations<JS::Rooted<TraceableFifo<A,B,C>>, A,B,C>
89 {
90     using TF = TraceableFifo<A,B,C>;
91 
92     friend class TraceableFifoOperations<JS::Rooted<TF>, A,B,C>;
extract()93     const TF& extract() const { return *static_cast<const JS::Rooted<TF>*>(this)->address(); }
94 
95     friend class MutableTraceableFifoOperations<JS::Rooted<TF>, A,B,C>;
extract()96     TF& extract() { return *static_cast<JS::Rooted<TF>*>(this)->address(); }
97 };
98 
99 template <typename A, size_t B, typename C>
100 class MutableHandleBase<TraceableFifo<A,B,C>>
101   : public MutableTraceableFifoOperations<JS::MutableHandle<TraceableFifo<A,B,C>>, A,B,C>
102 {
103     using TF = TraceableFifo<A,B,C>;
104 
105     friend class TraceableFifoOperations<JS::MutableHandle<TF>, A,B,C>;
extract()106     const TF& extract() const {
107         return *static_cast<const JS::MutableHandle<TF>*>(this)->address();
108     }
109 
110     friend class MutableTraceableFifoOperations<JS::MutableHandle<TF>, A,B,C>;
extract()111     TF& extract() { return *static_cast<JS::MutableHandle<TF>*>(this)->address(); }
112 };
113 
114 template <typename A, size_t B, typename C>
115 class HandleBase<TraceableFifo<A,B,C>>
116   : public TraceableFifoOperations<JS::Handle<TraceableFifo<A,B,C>>, A,B,C>
117 {
118     using TF = TraceableFifo<A,B,C>;
119 
120     friend class TraceableFifoOperations<JS::Handle<TF>, A,B,C>;
extract()121     const TF& extract() const {
122         return *static_cast<const JS::Handle<TF>*>(this)->address();
123     }
124 };
125 
126 } // namespace js
127 
128 #endif // js_TraceableFifo_h
129