23 */ |
23 */ |
24 |
24 |
25 #ifndef SHARE_VM_UTILITIES_STACK_HPP |
25 #ifndef SHARE_VM_UTILITIES_STACK_HPP |
26 #define SHARE_VM_UTILITIES_STACK_HPP |
26 #define SHARE_VM_UTILITIES_STACK_HPP |
27 |
27 |
|
28 #include "memory/allocation.hpp" |
28 #include "memory/allocation.inline.hpp" |
29 #include "memory/allocation.inline.hpp" |
29 |
30 |
30 // Class Stack (below) grows and shrinks by linking together "segments" which |
31 // Class Stack (below) grows and shrinks by linking together "segments" which |
31 // are allocated on demand. Segments are arrays of the element type (E) plus an |
32 // are allocated on demand. Segments are arrays of the element type (E) plus an |
32 // extra pointer-sized field to store the segment link. Recently emptied |
33 // extra pointer-sized field to store the segment link. Recently emptied |
49 // |
50 // |
50 // The alloc() method must return storage aligned for any use. The |
51 // The alloc() method must return storage aligned for any use. The |
51 // implementation in class Stack assumes that alloc() will terminate the process |
52 // implementation in class Stack assumes that alloc() will terminate the process |
52 // if the allocation fails. |
53 // if the allocation fails. |
53 |
54 |
54 template <class E> class StackIterator; |
55 template <class E, MEMFLAGS F> class StackIterator; |
55 |
56 |
56 // StackBase holds common data/methods that don't depend on the element type, |
57 // StackBase holds common data/methods that don't depend on the element type, |
57 // factored out to reduce template code duplication. |
58 // factored out to reduce template code duplication. |
58 class StackBase |
59 template <MEMFLAGS F> class StackBase |
59 { |
60 { |
60 public: |
61 public: |
61 size_t segment_size() const { return _seg_size; } // Elements per segment. |
62 size_t segment_size() const { return _seg_size; } // Elements per segment. |
62 size_t max_size() const { return _max_size; } // Max elements allowed. |
63 size_t max_size() const { return _max_size; } // Max elements allowed. |
63 size_t max_cache_size() const { return _max_cache_size; } // Max segments |
64 size_t max_cache_size() const { return _max_cache_size; } // Max segments |
87 |
88 |
88 #ifdef __GNUC__ |
89 #ifdef __GNUC__ |
89 #define inline |
90 #define inline |
90 #endif // __GNUC__ |
91 #endif // __GNUC__ |
91 |
92 |
92 template <class E> |
93 template <class E, MEMFLAGS F> |
93 class Stack: public StackBase |
94 class Stack: public StackBase<F> |
94 { |
95 { |
95 public: |
96 public: |
96 friend class StackIterator<E>; |
97 friend class StackIterator<E, F>; |
97 |
98 |
98 // segment_size: number of items per segment |
99 // segment_size: number of items per segment |
99 // max_cache_size: maxmium number of *segments* to cache |
100 // max_cache_size: maxmium number of *segments* to cache |
100 // max_size: maximum number of items allowed, rounded to a multiple of |
101 // max_size: maximum number of items allowed, rounded to a multiple of |
101 // the segment size (0 == unlimited) |
102 // the segment size (0 == unlimited) |
102 inline Stack(size_t segment_size = default_segment_size(), |
103 inline Stack(size_t segment_size = default_segment_size(), |
103 size_t max_cache_size = 4, size_t max_size = 0); |
104 size_t max_cache_size = 4, size_t max_size = 0); |
104 inline ~Stack() { clear(true); } |
105 inline ~Stack() { clear(true); } |
105 |
106 |
106 inline bool is_empty() const { return _cur_seg == NULL; } |
107 inline bool is_empty() const { return this->_cur_seg == NULL; } |
107 inline bool is_full() const { return _full_seg_size >= max_size(); } |
108 inline bool is_full() const { return this->_full_seg_size >= this->max_size(); } |
108 |
109 |
109 // Performance sensitive code should use is_empty() instead of size() == 0 and |
110 // Performance sensitive code should use is_empty() instead of size() == 0 and |
110 // is_full() instead of size() == max_size(). Using a conditional here allows |
111 // is_full() instead of size() == max_size(). Using a conditional here allows |
111 // just one var to be updated when pushing/popping elements instead of two; |
112 // just one var to be updated when pushing/popping elements instead of two; |
112 // _full_seg_size is updated only when pushing/popping segments. |
113 // _full_seg_size is updated only when pushing/popping segments. |
113 inline size_t size() const { |
114 inline size_t size() const { |
114 return is_empty() ? 0 : _full_seg_size + _cur_seg_size; |
115 return is_empty() ? 0 : this->_full_seg_size + this->_cur_seg_size; |
115 } |
116 } |
116 |
117 |
117 inline void push(E elem); |
118 inline void push(E elem); |
118 inline E pop(); |
119 inline E pop(); |
119 |
120 |
159 private: |
160 private: |
160 E* _cur_seg; // Current segment. |
161 E* _cur_seg; // Current segment. |
161 E* _cache; // Segment cache to avoid ping-ponging. |
162 E* _cache; // Segment cache to avoid ping-ponging. |
162 }; |
163 }; |
163 |
164 |
164 template <class E> class ResourceStack: public Stack<E>, public ResourceObj |
165 template <class E, MEMFLAGS F> class ResourceStack: public Stack<E, F>, public ResourceObj |
165 { |
166 { |
166 public: |
167 public: |
167 // If this class becomes widely used, it may make sense to save the Thread |
168 // If this class becomes widely used, it may make sense to save the Thread |
168 // and use it when allocating segments. |
169 // and use it when allocating segments. |
169 ResourceStack(size_t segment_size = Stack<E>::default_segment_size()): |
170 // ResourceStack(size_t segment_size = Stack<E, F>::default_segment_size()): |
170 Stack<E>(segment_size, max_uintx) |
171 ResourceStack(size_t segment_size): Stack<E, F>(segment_size, max_uintx) |
171 { } |
172 { } |
172 |
173 |
173 // Set the segment pointers to NULL so the parent dtor does not free them; |
174 // Set the segment pointers to NULL so the parent dtor does not free them; |
174 // that must be done by the ResourceMark code. |
175 // that must be done by the ResourceMark code. |
175 ~ResourceStack() { Stack<E>::reset(true); } |
176 ~ResourceStack() { Stack<E, F>::reset(true); } |
176 |
177 |
177 protected: |
178 protected: |
178 virtual E* alloc(size_t bytes); |
179 virtual E* alloc(size_t bytes); |
179 virtual void free(E* addr, size_t bytes); |
180 virtual void free(E* addr, size_t bytes); |
180 |
181 |
181 private: |
182 private: |
182 void clear(bool clear_cache = false); |
183 void clear(bool clear_cache = false); |
183 }; |
184 }; |
184 |
185 |
185 template <class E> |
186 template <class E, MEMFLAGS F> |
186 class StackIterator: public StackObj |
187 class StackIterator: public StackObj |
187 { |
188 { |
188 public: |
189 public: |
189 StackIterator(Stack<E>& stack): _stack(stack) { sync(); } |
190 StackIterator(Stack<E, F>& stack): _stack(stack) { sync(); } |
190 |
191 |
191 Stack<E>& stack() const { return _stack; } |
192 Stack<E, F>& stack() const { return _stack; } |
192 |
193 |
193 bool is_empty() const { return _cur_seg == NULL; } |
194 bool is_empty() const { return _cur_seg == NULL; } |
194 |
195 |
195 E next() { return *next_addr(); } |
196 E next() { return *next_addr(); } |
196 E* next_addr(); |
197 E* next_addr(); |
197 |
198 |
198 void sync(); // Sync the iterator's state to the stack's current state. |
199 void sync(); // Sync the iterator's state to the stack's current state. |
199 |
200 |
200 private: |
201 private: |
201 Stack<E>& _stack; |
202 Stack<E, F>& _stack; |
202 size_t _cur_seg_size; |
203 size_t _cur_seg_size; |
203 E* _cur_seg; |
204 E* _cur_seg; |
204 size_t _full_seg_size; |
205 size_t _full_seg_size; |
205 }; |
206 }; |
206 |
207 |