1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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 jit_InlineList_h
8 #define jit_InlineList_h
9 
10 #include "mozilla/Assertions.h"
11 
12 namespace js {
13 
14 template <typename T>
15 class InlineForwardList;
16 template <typename T>
17 class InlineForwardListIterator;
18 
19 template <typename T>
20 class InlineForwardListNode {
21  public:
InlineForwardListNode()22   InlineForwardListNode() : next(nullptr) {}
InlineForwardListNode(InlineForwardListNode<T> * n)23   explicit InlineForwardListNode(InlineForwardListNode<T>* n) : next(n) {}
24 
25   InlineForwardListNode(const InlineForwardListNode<T>&) = delete;
26 
27  protected:
28   friend class InlineForwardList<T>;
29   friend class InlineForwardListIterator<T>;
30 
31   InlineForwardListNode<T>* next;
32 };
33 
34 template <typename T>
35 class InlineForwardList : protected InlineForwardListNode<T> {
36   friend class InlineForwardListIterator<T>;
37 
38   using Node = InlineForwardListNode<T>;
39 
40   Node* tail_;
41 #ifdef DEBUG
42   int modifyCount_;
43 #endif
44 
thisFromConstructor()45   InlineForwardList<T>* thisFromConstructor() { return this; }
46 
47  public:
InlineForwardList()48   InlineForwardList() : tail_(thisFromConstructor()) {
49 #ifdef DEBUG
50     modifyCount_ = 0;
51 #endif
52   }
53 
54  public:
55   using iterator = InlineForwardListIterator<T>;
56 
57  public:
begin()58   iterator begin() const { return iterator(this); }
begin(Node * item)59   iterator begin(Node* item) const { return iterator(this, item); }
end()60   iterator end() const { return iterator(nullptr); }
removeAt(iterator where)61   void removeAt(iterator where) { removeAfter(where.prev, where.iter); }
pushFront(Node * t)62   void pushFront(Node* t) { insertAfter(this, t); }
pushBack(Node * t)63   void pushBack(Node* t) {
64     MOZ_ASSERT(t->next == nullptr);
65 #ifdef DEBUG
66     modifyCount_++;
67 #endif
68     tail_->next = t;
69     tail_ = t;
70   }
popFront()71   T* popFront() {
72     MOZ_ASSERT(!empty());
73     T* result = static_cast<T*>(this->next);
74     removeAfter(this, result);
75     return result;
76   }
back()77   T* back() const {
78     MOZ_ASSERT(!empty());
79     return static_cast<T*>(tail_);
80   }
insertAfter(Node * at,Node * item)81   void insertAfter(Node* at, Node* item) {
82     MOZ_ASSERT(item->next == nullptr);
83 #ifdef DEBUG
84     modifyCount_++;
85 #endif
86     if (at == tail_) {
87       tail_ = item;
88     }
89     item->next = at->next;
90     at->next = item;
91   }
removeAfter(Node * at,Node * item)92   void removeAfter(Node* at, Node* item) {
93 #ifdef DEBUG
94     modifyCount_++;
95 #endif
96     if (item == tail_) {
97       tail_ = at;
98     }
99     MOZ_ASSERT(at->next == item);
100     at->next = item->next;
101     item->next = nullptr;
102   }
removeAndIncrement(iterator & where)103   void removeAndIncrement(iterator& where) {
104     // Do not change modifyCount_ here. The iterator can still be used
105     // after calling this method, unlike the other methods that modify
106     // the list.
107     Node* item = where.iter;
108     where.iter = item->next;
109     if (item == tail_) {
110       tail_ = where.prev;
111     }
112     MOZ_ASSERT(where.prev->next == item);
113     where.prev->next = where.iter;
114     item->next = nullptr;
115   }
splitAfter(Node * at,InlineForwardList<T> * to)116   void splitAfter(Node* at, InlineForwardList<T>* to) {
117     MOZ_ASSERT(to->empty());
118     if (!at) {
119       at = this;
120     }
121     if (at == tail_) {
122       return;
123     }
124 #ifdef DEBUG
125     modifyCount_++;
126 #endif
127     to->next = at->next;
128     to->tail_ = tail_;
129     tail_ = at;
130     at->next = nullptr;
131   }
empty()132   bool empty() const { return tail_ == this; }
clear()133   void clear() {
134     this->next = nullptr;
135     tail_ = this;
136 #ifdef DEBUG
137     modifyCount_ = 0;
138 #endif
139   }
140 };
141 
142 template <typename T>
143 class InlineForwardListIterator {
144  private:
145   friend class InlineForwardList<T>;
146 
147   using Node = InlineForwardListNode<T>;
148 
InlineForwardListIterator(const InlineForwardList<T> * owner)149   explicit InlineForwardListIterator(const InlineForwardList<T>* owner)
150       : prev(const_cast<Node*>(static_cast<const Node*>(owner))),
151         iter(owner ? owner->next : nullptr)
152 #ifdef DEBUG
153         ,
154         owner_(owner),
155         modifyCount_(owner ? owner->modifyCount_ : 0)
156 #endif
157   {
158   }
159 
InlineForwardListIterator(const InlineForwardList<T> * owner,Node * node)160   InlineForwardListIterator(const InlineForwardList<T>* owner, Node* node)
161       : prev(nullptr),
162         iter(node)
163 #ifdef DEBUG
164         ,
165         owner_(owner),
166         modifyCount_(owner ? owner->modifyCount_ : 0)
167 #endif
168   {
169   }
170 
171  public:
172   InlineForwardListIterator<T>& operator++() {
173     MOZ_ASSERT(modifyCount_ == owner_->modifyCount_);
174     prev = iter;
175     iter = iter->next;
176     return *this;
177   }
178   InlineForwardListIterator<T> operator++(int) {
179     InlineForwardListIterator<T> old(*this);
180     operator++();
181     return old;
182   }
183   T* operator*() const {
184     MOZ_ASSERT(modifyCount_ == owner_->modifyCount_);
185     return static_cast<T*>(iter);
186   }
187   T* operator->() const {
188     MOZ_ASSERT(modifyCount_ == owner_->modifyCount_);
189     return static_cast<T*>(iter);
190   }
191   bool operator!=(const InlineForwardListIterator<T>& where) const {
192     return iter != where.iter;
193   }
194   bool operator==(const InlineForwardListIterator<T>& where) const {
195     return iter == where.iter;
196   }
197   explicit operator bool() const { return iter != nullptr; }
198 
199  private:
200   Node* prev;
201   Node* iter;
202 
203 #ifdef DEBUG
204   const InlineForwardList<T>* owner_;
205   int modifyCount_;
206 #endif
207 };
208 
209 template <typename T>
210 class InlineList;
211 template <typename T>
212 class InlineListIterator;
213 template <typename T>
214 class InlineListReverseIterator;
215 
216 template <typename T>
217 class InlineListNode : public InlineForwardListNode<T> {
218  public:
InlineListNode()219   InlineListNode() : InlineForwardListNode<T>(nullptr), prev(nullptr) {}
InlineListNode(InlineListNode<T> * n,InlineListNode<T> * p)220   InlineListNode(InlineListNode<T>* n, InlineListNode<T>* p)
221       : InlineForwardListNode<T>(n), prev(p) {}
222 
223   // Move constructor. Nodes may be moved without being removed from their
224   // containing lists. For example, this allows list nodes to be safely
225   // stored in a resizable Vector -- when the Vector resizes, the new storage
226   // is initialized by this move constructor. |other| is a reference to the
227   // old node which the |this| node here is replacing.
InlineListNode(InlineListNode<T> && other)228   InlineListNode(InlineListNode<T>&& other)
229       : InlineForwardListNode<T>(other.next) {
230     InlineListNode<T>* newNext = static_cast<InlineListNode<T>*>(other.next);
231     InlineListNode<T>* newPrev = other.prev;
232     prev = newPrev;
233 
234     // Update the pointers in the adjacent nodes to point to this node's new
235     // location.
236     newNext->prev = this;
237     newPrev->next = this;
238   }
239 
240   InlineListNode(const InlineListNode<T>&) = delete;
241   void operator=(const InlineListNode<T>&) = delete;
242 
isInList()243   bool isInList() { return prev != nullptr && this->next != nullptr; }
244 
245  protected:
246   friend class InlineList<T>;
247   friend class InlineListIterator<T>;
248   friend class InlineListReverseIterator<T>;
249 
250   InlineListNode<T>* prev;
251 };
252 
253 template <typename T>
254 class InlineList : protected InlineListNode<T> {
255   using Node = InlineListNode<T>;
256 
257  public:
InlineList()258   InlineList() : InlineListNode<T>(this, this) {}
259 
260  public:
261   using iterator = InlineListIterator<T>;
262   using reverse_iterator = InlineListReverseIterator<T>;
263 
264  public:
begin()265   iterator begin() const { return iterator(static_cast<Node*>(this->next)); }
begin(Node * t)266   iterator begin(Node* t) const { return iterator(t); }
end()267   iterator end() const { return iterator(this); }
rbegin()268   reverse_iterator rbegin() const { return reverse_iterator(this->prev); }
rbegin(Node * t)269   reverse_iterator rbegin(Node* t) const { return reverse_iterator(t); }
rend()270   reverse_iterator rend() const { return reverse_iterator(this); }
pushFront(Node * t)271   void pushFront(Node* t) { insertAfter(this, t); }
pushFrontUnchecked(Node * t)272   void pushFrontUnchecked(Node* t) { insertAfterUnchecked(this, t); }
pushBack(Node * t)273   void pushBack(Node* t) { insertBefore(this, t); }
pushBackUnchecked(Node * t)274   void pushBackUnchecked(Node* t) { insertBeforeUnchecked(this, t); }
popFront()275   T* popFront() {
276     MOZ_ASSERT(!empty());
277     T* t = static_cast<T*>(this->next);
278     remove(t);
279     return t;
280   }
popBack()281   T* popBack() {
282     MOZ_ASSERT(!empty());
283     T* t = static_cast<T*>(this->prev);
284     remove(t);
285     return t;
286   }
peekBack()287   T* peekBack() const {
288     iterator iter = end();
289     iter--;
290     return *iter;
291   }
insertBefore(Node * at,Node * item)292   void insertBefore(Node* at, Node* item) {
293     MOZ_ASSERT(item->prev == nullptr);
294     MOZ_ASSERT(item->next == nullptr);
295     insertBeforeUnchecked(at, item);
296   }
insertBeforeUnchecked(Node * at,Node * item)297   void insertBeforeUnchecked(Node* at, Node* item) {
298     Node* atPrev = at->prev;
299     item->next = at;
300     item->prev = atPrev;
301     atPrev->next = item;
302     at->prev = item;
303   }
insertAfter(Node * at,Node * item)304   void insertAfter(Node* at, Node* item) {
305     MOZ_ASSERT(item->prev == nullptr);
306     MOZ_ASSERT(item->next == nullptr);
307     insertAfterUnchecked(at, item);
308   }
insertAfterUnchecked(Node * at,Node * item)309   void insertAfterUnchecked(Node* at, Node* item) {
310     Node* atNext = static_cast<Node*>(at->next);
311     item->next = atNext;
312     item->prev = at;
313     atNext->prev = item;
314     at->next = item;
315   }
remove(Node * t)316   void remove(Node* t) {
317     Node* tNext = static_cast<Node*>(t->next);
318     Node* tPrev = t->prev;
319     tPrev->next = tNext;
320     tNext->prev = tPrev;
321     t->next = nullptr;
322     t->prev = nullptr;
323   }
324   // Remove |old| from the list and insert |now| in its place.
replace(Node * old,Node * now)325   void replace(Node* old, Node* now) {
326     MOZ_ASSERT(now->next == nullptr && now->prev == nullptr);
327     Node* listNext = static_cast<Node*>(old->next);
328     Node* listPrev = old->prev;
329     listPrev->next = now;
330     listNext->prev = now;
331     now->next = listNext;
332     now->prev = listPrev;
333     old->next = nullptr;
334     old->prev = nullptr;
335   }
clear()336   void clear() { this->next = this->prev = this; }
empty()337   bool empty() const { return begin() == end(); }
takeElements(InlineList & l)338   void takeElements(InlineList& l) {
339     MOZ_ASSERT(&l != this, "cannot takeElements from this");
340     Node* lprev = l.prev;
341     static_cast<Node*>(l.next)->prev = this;
342     lprev->next = this->next;
343     static_cast<Node*>(this->next)->prev = l.prev;
344     this->next = l.next;
345     l.clear();
346   }
347 };
348 
349 template <typename T>
350 class InlineListIterator {
351  private:
352   friend class InlineList<T>;
353 
354   using Node = InlineListNode<T>;
355 
InlineListIterator(const Node * iter)356   explicit InlineListIterator(const Node* iter)
357       : iter(const_cast<Node*>(iter)) {}
358 
359  public:
360   InlineListIterator<T>& operator++() {
361     iter = static_cast<Node*>(iter->next);
362     return *this;
363   }
364   InlineListIterator<T> operator++(int) {
365     InlineListIterator<T> old(*this);
366     operator++();
367     return old;
368   }
369   InlineListIterator<T>& operator--() {
370     iter = iter->prev;
371     return *this;
372   }
373   InlineListIterator<T> operator--(int) {
374     InlineListIterator<T> old(*this);
375     operator--();
376     return old;
377   }
378   T* operator*() const { return static_cast<T*>(iter); }
379   T* operator->() const { return static_cast<T*>(iter); }
380   bool operator!=(const InlineListIterator<T>& where) const {
381     return iter != where.iter;
382   }
383   bool operator==(const InlineListIterator<T>& where) const {
384     return iter == where.iter;
385   }
386 
387  private:
388   Node* iter;
389 };
390 
391 template <typename T>
392 class InlineListReverseIterator {
393  private:
394   friend class InlineList<T>;
395 
396   using Node = InlineListNode<T>;
397 
InlineListReverseIterator(const Node * iter)398   explicit InlineListReverseIterator(const Node* iter)
399       : iter(const_cast<Node*>(iter)) {}
400 
401  public:
402   InlineListReverseIterator<T>& operator++() {
403     iter = iter->prev;
404     return *this;
405   }
406   InlineListReverseIterator<T> operator++(int) {
407     InlineListReverseIterator<T> old(*this);
408     operator++();
409     return old;
410   }
411   InlineListReverseIterator<T>& operator--() {
412     iter = static_cast<Node*>(iter->next);
413     return *this;
414   }
415   InlineListReverseIterator<T> operator--(int) {
416     InlineListReverseIterator<T> old(*this);
417     operator--();
418     return old;
419   }
420   T* operator*() { return static_cast<T*>(iter); }
421   T* operator->() { return static_cast<T*>(iter); }
422   bool operator!=(const InlineListReverseIterator<T>& where) const {
423     return iter != where.iter;
424   }
425   bool operator==(const InlineListReverseIterator<T>& where) const {
426     return iter == where.iter;
427   }
428 
429  private:
430   Node* iter;
431 };
432 
433 // This list type is more or less exactly an InlineForwardList without a
434 // sentinel node. It is useful in cases where you are doing algorithms that deal
435 // with many merging singleton lists, rather than often empty ones.
436 template <typename T>
437 class InlineConcatListIterator;
438 template <typename T>
439 class InlineConcatList {
440  private:
441   using Node = InlineConcatList<T>;
442 
thisFromConstructor()443   InlineConcatList<T>* thisFromConstructor() { return this; }
444 
445  public:
InlineConcatList()446   InlineConcatList() : next(nullptr), tail(thisFromConstructor()) {}
447 
448   using iterator = InlineConcatListIterator<T>;
449 
begin()450   iterator begin() const { return iterator(this); }
451 
end()452   iterator end() const { return iterator(nullptr); }
453 
append(InlineConcatList<T> * adding)454   void append(InlineConcatList<T>* adding) {
455     MOZ_ASSERT(tail);
456     MOZ_ASSERT(!tail->next);
457     MOZ_ASSERT(adding->tail);
458     MOZ_ASSERT(!adding->tail->next);
459 
460     tail->next = adding;
461     tail = adding->tail;
462     adding->tail = nullptr;
463   }
464 
465  protected:
466   friend class InlineConcatListIterator<T>;
467   Node* next;
468   Node* tail;
469 };
470 
471 template <typename T>
472 class InlineConcatListIterator {
473  private:
474   friend class InlineConcatList<T>;
475 
476   using Node = InlineConcatList<T>;
477 
InlineConcatListIterator(const Node * iter)478   explicit InlineConcatListIterator(const Node* iter)
479       : iter(const_cast<Node*>(iter)) {}
480 
481  public:
482   InlineConcatListIterator<T>& operator++() {
483     iter = static_cast<Node*>(iter->next);
484     return *this;
485   }
486   InlineConcatListIterator<T> operator++(int) {
487     InlineConcatListIterator<T> old(*this);
488     operator++();
489     return old;
490   }
491   T* operator*() const { return static_cast<T*>(iter); }
492   T* operator->() const { return static_cast<T*>(iter); }
493   bool operator!=(const InlineConcatListIterator<T>& where) const {
494     return iter != where.iter;
495   }
496   bool operator==(const InlineConcatListIterator<T>& where) const {
497     return iter == where.iter;
498   }
499 
500  private:
501   Node* iter;
502 };
503 
504 template <typename T>
505 class InlineSpaghettiStack;
506 template <typename T>
507 class InlineSpaghettiStackNode;
508 template <typename T>
509 class InlineSpaghettiStackIterator;
510 
511 template <typename T>
512 class InlineSpaghettiStackNode : public InlineForwardListNode<T> {
513   using Parent = InlineForwardListNode<T>;
514 
515  public:
InlineSpaghettiStackNode()516   InlineSpaghettiStackNode() : Parent() {}
517 
InlineSpaghettiStackNode(InlineSpaghettiStackNode<T> * n)518   explicit InlineSpaghettiStackNode(InlineSpaghettiStackNode<T>* n)
519       : Parent(n) {}
520 
521   InlineSpaghettiStackNode(const InlineSpaghettiStackNode<T>&) = delete;
522 
523  protected:
524   friend class InlineSpaghettiStack<T>;
525   friend class InlineSpaghettiStackIterator<T>;
526 };
527 
528 template <typename T>
529 class InlineSpaghettiStack : protected InlineSpaghettiStackNode<T> {
530   friend class InlineSpaghettiStackIterator<T>;
531 
532   using Node = InlineSpaghettiStackNode<T>;
533 
534  public:
535   InlineSpaghettiStack() = default;
536 
537  public:
538   using iterator = InlineSpaghettiStackIterator<T>;
539 
540  public:
begin()541   iterator begin() const { return iterator(this); }
end()542   iterator end() const { return iterator(nullptr); }
543 
push(Node * t)544   void push(Node* t) {
545     MOZ_ASSERT(t->next == nullptr);
546     t->next = this->next;
547     this->next = t;
548   }
549 
copy(const InlineSpaghettiStack<T> & stack)550   void copy(const InlineSpaghettiStack<T>& stack) { this->next = stack.next; }
551 
empty()552   bool empty() const { return this->next == nullptr; }
553 };
554 
555 template <typename T>
556 class InlineSpaghettiStackIterator {
557  private:
558   friend class InlineSpaghettiStack<T>;
559 
560   using Node = InlineSpaghettiStackNode<T>;
561 
InlineSpaghettiStackIterator(const InlineSpaghettiStack<T> * owner)562   explicit InlineSpaghettiStackIterator(const InlineSpaghettiStack<T>* owner)
563       : iter(owner ? static_cast<Node*>(owner->next) : nullptr) {}
564 
565  public:
566   InlineSpaghettiStackIterator<T>& operator++() {
567     iter = static_cast<Node*>(iter->next);
568     return *this;
569   }
570   InlineSpaghettiStackIterator<T> operator++(int) {
571     InlineSpaghettiStackIterator<T> old(*this);
572     operator++();
573     return old;
574   }
575   T* operator*() const { return static_cast<T*>(iter); }
576   T* operator->() const { return static_cast<T*>(iter); }
577   bool operator!=(const InlineSpaghettiStackIterator<T>& where) const {
578     return iter != where.iter;
579   }
580   bool operator==(const InlineSpaghettiStackIterator<T>& where) const {
581     return iter == where.iter;
582   }
583 
584  private:
585   Node* iter;
586 };
587 
588 }  // namespace js
589 
590 #endif /* jit_InlineList_h */
591