Mercurial > hg > truffle
comparison src/share/vm/utilities/taskqueue.hpp @ 1311:2a1472c30599
4396719: Mark Sweep stack overflow on deeply nested Object arrays
Summary: Use an explicit stack for object arrays and process them in chunks.
Reviewed-by: iveresov, apetrusenko
author | jcoomes |
---|---|
date | Wed, 03 Mar 2010 14:48:26 -0800 |
parents | 5f1f51edaff6 |
children | c18cbe5936b8 |
comparison
equal
deleted
inserted
replaced
1289:d47555d7aca8 | 1311:2a1472c30599 |
---|---|
20 * CA 95054 USA or visit www.sun.com if you need additional information or | 20 * CA 95054 USA or visit www.sun.com if you need additional information or |
21 * have any questions. | 21 * have any questions. |
22 * | 22 * |
23 */ | 23 */ |
24 | 24 |
25 template <unsigned int N> | |
25 class TaskQueueSuper: public CHeapObj { | 26 class TaskQueueSuper: public CHeapObj { |
26 protected: | 27 protected: |
27 // Internal type for indexing the queue; also used for the tag. | 28 // Internal type for indexing the queue; also used for the tag. |
28 typedef NOT_LP64(uint16_t) LP64_ONLY(uint32_t) idx_t; | 29 typedef NOT_LP64(uint16_t) LP64_ONLY(uint32_t) idx_t; |
29 | 30 |
30 // The first free element after the last one pushed (mod N). | 31 // The first free element after the last one pushed (mod N). |
31 volatile uint _bottom; | 32 volatile uint _bottom; |
32 | 33 |
33 enum { | 34 enum { MOD_N_MASK = N - 1 }; |
34 N = 1 << NOT_LP64(14) LP64_ONLY(17), // Queue size: 16K or 128K | |
35 MOD_N_MASK = N - 1 // To compute x mod N efficiently. | |
36 }; | |
37 | 35 |
38 class Age { | 36 class Age { |
39 public: | 37 public: |
40 Age(size_t data = 0) { _data = data; } | 38 Age(size_t data = 0) { _data = data; } |
41 Age(const Age& age) { _data = age._data; } | 39 Age(const Age& age) { _data = age._data; } |
82 return (ind - 1) & MOD_N_MASK; | 80 return (ind - 1) & MOD_N_MASK; |
83 } | 81 } |
84 | 82 |
85 // Returns a number in the range [0..N). If the result is "N-1", it should be | 83 // Returns a number in the range [0..N). If the result is "N-1", it should be |
86 // interpreted as 0. | 84 // interpreted as 0. |
87 uint dirty_size(uint bot, uint top) { | 85 uint dirty_size(uint bot, uint top) const { |
88 return (bot - top) & MOD_N_MASK; | 86 return (bot - top) & MOD_N_MASK; |
89 } | 87 } |
90 | 88 |
91 // Returns the size corresponding to the given "bot" and "top". | 89 // Returns the size corresponding to the given "bot" and "top". |
92 uint size(uint bot, uint top) { | 90 uint size(uint bot, uint top) const { |
93 uint sz = dirty_size(bot, top); | 91 uint sz = dirty_size(bot, top); |
94 // Has the queue "wrapped", so that bottom is less than top? There's a | 92 // Has the queue "wrapped", so that bottom is less than top? There's a |
95 // complicated special case here. A pair of threads could perform pop_local | 93 // complicated special case here. A pair of threads could perform pop_local |
96 // and pop_global operations concurrently, starting from a state in which | 94 // and pop_global operations concurrently, starting from a state in which |
97 // _bottom == _top+1. The pop_local could succeed in decrementing _bottom, | 95 // _bottom == _top+1. The pop_local could succeed in decrementing _bottom, |
109 } | 107 } |
110 | 108 |
111 public: | 109 public: |
112 TaskQueueSuper() : _bottom(0), _age() {} | 110 TaskQueueSuper() : _bottom(0), _age() {} |
113 | 111 |
114 // Return "true" if the TaskQueue contains any tasks. | 112 // Return true if the TaskQueue contains any tasks. |
115 bool peek(); | 113 bool peek() { return _bottom != _age.top(); } |
116 | 114 |
117 // Return an estimate of the number of elements in the queue. | 115 // Return an estimate of the number of elements in the queue. |
118 // The "careful" version admits the possibility of pop_local/pop_global | 116 // The "careful" version admits the possibility of pop_local/pop_global |
119 // races. | 117 // races. |
120 uint size() { | 118 uint size() const { |
121 return size(_bottom, _age.top()); | 119 return size(_bottom, _age.top()); |
122 } | 120 } |
123 | 121 |
124 uint dirty_size() { | 122 uint dirty_size() const { |
125 return dirty_size(_bottom, _age.top()); | 123 return dirty_size(_bottom, _age.top()); |
126 } | 124 } |
127 | 125 |
128 void set_empty() { | 126 void set_empty() { |
129 _bottom = 0; | 127 _bottom = 0; |
130 _age.set(0); | 128 _age.set(0); |
131 } | 129 } |
132 | 130 |
133 // Maximum number of elements allowed in the queue. This is two less | 131 // Maximum number of elements allowed in the queue. This is two less |
134 // than the actual queue size, for somewhat complicated reasons. | 132 // than the actual queue size, for somewhat complicated reasons. |
135 uint max_elems() { return N - 2; } | 133 uint max_elems() const { return N - 2; } |
136 | 134 |
137 // Total size of queue. | 135 // Total size of queue. |
138 static const uint total_size() { return N; } | 136 static const uint total_size() { return N; } |
139 }; | 137 }; |
140 | 138 |
141 template<class E> class GenericTaskQueue: public TaskQueueSuper { | 139 template<class E, unsigned int N = TASKQUEUE_SIZE> |
140 class GenericTaskQueue: public TaskQueueSuper<N> { | |
141 protected: | |
142 typedef typename TaskQueueSuper<N>::Age Age; | |
143 typedef typename TaskQueueSuper<N>::idx_t idx_t; | |
144 | |
145 using TaskQueueSuper<N>::_bottom; | |
146 using TaskQueueSuper<N>::_age; | |
147 using TaskQueueSuper<N>::increment_index; | |
148 using TaskQueueSuper<N>::decrement_index; | |
149 using TaskQueueSuper<N>::dirty_size; | |
150 | |
151 public: | |
152 using TaskQueueSuper<N>::max_elems; | |
153 using TaskQueueSuper<N>::size; | |
154 | |
142 private: | 155 private: |
143 // Slow paths for push, pop_local. (pop_global has no fast path.) | 156 // Slow paths for push, pop_local. (pop_global has no fast path.) |
144 bool push_slow(E t, uint dirty_n_elems); | 157 bool push_slow(E t, uint dirty_n_elems); |
145 bool pop_local_slow(uint localBot, Age oldAge); | 158 bool pop_local_slow(uint localBot, Age oldAge); |
146 | 159 |
147 public: | 160 public: |
161 typedef E element_type; | |
162 | |
148 // Initializes the queue to empty. | 163 // Initializes the queue to empty. |
149 GenericTaskQueue(); | 164 GenericTaskQueue(); |
150 | 165 |
151 void initialize(); | 166 void initialize(); |
152 | 167 |
173 private: | 188 private: |
174 // Element array. | 189 // Element array. |
175 volatile E* _elems; | 190 volatile E* _elems; |
176 }; | 191 }; |
177 | 192 |
178 template<class E> | 193 template<class E, unsigned int N> |
179 GenericTaskQueue<E>::GenericTaskQueue():TaskQueueSuper() { | 194 GenericTaskQueue<E, N>::GenericTaskQueue() { |
180 assert(sizeof(Age) == sizeof(size_t), "Depends on this."); | 195 assert(sizeof(Age) == sizeof(size_t), "Depends on this."); |
181 } | 196 } |
182 | 197 |
183 template<class E> | 198 template<class E, unsigned int N> |
184 void GenericTaskQueue<E>::initialize() { | 199 void GenericTaskQueue<E, N>::initialize() { |
185 _elems = NEW_C_HEAP_ARRAY(E, N); | 200 _elems = NEW_C_HEAP_ARRAY(E, N); |
186 guarantee(_elems != NULL, "Allocation failed."); | 201 guarantee(_elems != NULL, "Allocation failed."); |
187 } | 202 } |
188 | 203 |
189 template<class E> | 204 template<class E, unsigned int N> |
190 void GenericTaskQueue<E>::oops_do(OopClosure* f) { | 205 void GenericTaskQueue<E, N>::oops_do(OopClosure* f) { |
191 // tty->print_cr("START OopTaskQueue::oops_do"); | 206 // tty->print_cr("START OopTaskQueue::oops_do"); |
192 uint iters = size(); | 207 uint iters = size(); |
193 uint index = _bottom; | 208 uint index = _bottom; |
194 for (uint i = 0; i < iters; ++i) { | 209 for (uint i = 0; i < iters; ++i) { |
195 index = decrement_index(index); | 210 index = decrement_index(index); |
201 f->do_oop(p); | 216 f->do_oop(p); |
202 } | 217 } |
203 // tty->print_cr("END OopTaskQueue::oops_do"); | 218 // tty->print_cr("END OopTaskQueue::oops_do"); |
204 } | 219 } |
205 | 220 |
206 | 221 template<class E, unsigned int N> |
207 template<class E> | 222 bool GenericTaskQueue<E, N>::push_slow(E t, uint dirty_n_elems) { |
208 bool GenericTaskQueue<E>::push_slow(E t, uint dirty_n_elems) { | |
209 if (dirty_n_elems == N - 1) { | 223 if (dirty_n_elems == N - 1) { |
210 // Actually means 0, so do the push. | 224 // Actually means 0, so do the push. |
211 uint localBot = _bottom; | 225 uint localBot = _bottom; |
212 _elems[localBot] = t; | 226 // g++ complains if the volatile result of the assignment is unused. |
227 const_cast<E&>(_elems[localBot] = t); | |
213 OrderAccess::release_store(&_bottom, increment_index(localBot)); | 228 OrderAccess::release_store(&_bottom, increment_index(localBot)); |
214 return true; | 229 return true; |
215 } | 230 } |
216 return false; | 231 return false; |
217 } | 232 } |
218 | 233 |
219 template<class E> | 234 template<class E, unsigned int N> |
220 bool GenericTaskQueue<E>:: | 235 bool GenericTaskQueue<E, N>:: |
221 pop_local_slow(uint localBot, Age oldAge) { | 236 pop_local_slow(uint localBot, Age oldAge) { |
222 // This queue was observed to contain exactly one element; either this | 237 // This queue was observed to contain exactly one element; either this |
223 // thread will claim it, or a competing "pop_global". In either case, | 238 // thread will claim it, or a competing "pop_global". In either case, |
224 // the queue will be logically empty afterwards. Create a new Age value | 239 // the queue will be logically empty afterwards. Create a new Age value |
225 // that represents the empty queue for the given value of "_bottom". (We | 240 // that represents the empty queue for the given value of "_bottom". (We |
247 _age.set(newAge); | 262 _age.set(newAge); |
248 assert(dirty_size(localBot, _age.top()) != N - 1, "sanity"); | 263 assert(dirty_size(localBot, _age.top()) != N - 1, "sanity"); |
249 return false; | 264 return false; |
250 } | 265 } |
251 | 266 |
252 template<class E> | 267 template<class E, unsigned int N> |
253 bool GenericTaskQueue<E>::pop_global(E& t) { | 268 bool GenericTaskQueue<E, N>::pop_global(E& t) { |
254 Age oldAge = _age.get(); | 269 Age oldAge = _age.get(); |
255 uint localBot = _bottom; | 270 uint localBot = _bottom; |
256 uint n_elems = size(localBot, oldAge.top()); | 271 uint n_elems = size(localBot, oldAge.top()); |
257 if (n_elems == 0) { | 272 if (n_elems == 0) { |
258 return false; | 273 return false; |
259 } | 274 } |
260 | 275 |
261 t = _elems[oldAge.top()]; | 276 const_cast<E&>(t = _elems[oldAge.top()]); |
262 Age newAge(oldAge); | 277 Age newAge(oldAge); |
263 newAge.increment(); | 278 newAge.increment(); |
264 Age resAge = _age.cmpxchg(newAge, oldAge); | 279 Age resAge = _age.cmpxchg(newAge, oldAge); |
265 | 280 |
266 // Note that using "_bottom" here might fail, since a pop_local might | 281 // Note that using "_bottom" here might fail, since a pop_local might |
267 // have decremented it. | 282 // have decremented it. |
268 assert(dirty_size(localBot, newAge.top()) != N - 1, "sanity"); | 283 assert(dirty_size(localBot, newAge.top()) != N - 1, "sanity"); |
269 return resAge == oldAge; | 284 return resAge == oldAge; |
270 } | 285 } |
271 | 286 |
272 template<class E> | 287 template<class E, unsigned int N> |
273 GenericTaskQueue<E>::~GenericTaskQueue() { | 288 GenericTaskQueue<E, N>::~GenericTaskQueue() { |
274 FREE_C_HEAP_ARRAY(E, _elems); | 289 FREE_C_HEAP_ARRAY(E, _elems); |
275 } | 290 } |
276 | 291 |
277 // Inherits the typedef of "Task" from above. | 292 // Inherits the typedef of "Task" from above. |
278 class TaskQueueSetSuper: public CHeapObj { | 293 class TaskQueueSetSuper: public CHeapObj { |
281 public: | 296 public: |
282 // Returns "true" if some TaskQueue in the set contains a task. | 297 // Returns "true" if some TaskQueue in the set contains a task. |
283 virtual bool peek() = 0; | 298 virtual bool peek() = 0; |
284 }; | 299 }; |
285 | 300 |
286 template<class E> class GenericTaskQueueSet: public TaskQueueSetSuper { | 301 template<class T> |
302 class GenericTaskQueueSet: public TaskQueueSetSuper { | |
287 private: | 303 private: |
288 uint _n; | 304 uint _n; |
289 GenericTaskQueue<E>** _queues; | 305 T** _queues; |
290 | 306 |
291 public: | 307 public: |
308 typedef typename T::element_type E; | |
309 | |
292 GenericTaskQueueSet(int n) : _n(n) { | 310 GenericTaskQueueSet(int n) : _n(n) { |
293 typedef GenericTaskQueue<E>* GenericTaskQueuePtr; | 311 typedef T* GenericTaskQueuePtr; |
294 _queues = NEW_C_HEAP_ARRAY(GenericTaskQueuePtr, n); | 312 _queues = NEW_C_HEAP_ARRAY(GenericTaskQueuePtr, n); |
295 guarantee(_queues != NULL, "Allocation failure."); | |
296 for (int i = 0; i < n; i++) { | 313 for (int i = 0; i < n; i++) { |
297 _queues[i] = NULL; | 314 _queues[i] = NULL; |
298 } | 315 } |
299 } | 316 } |
300 | 317 |
301 bool steal_1_random(uint queue_num, int* seed, E& t); | 318 bool steal_1_random(uint queue_num, int* seed, E& t); |
302 bool steal_best_of_2(uint queue_num, int* seed, E& t); | 319 bool steal_best_of_2(uint queue_num, int* seed, E& t); |
303 bool steal_best_of_all(uint queue_num, int* seed, E& t); | 320 bool steal_best_of_all(uint queue_num, int* seed, E& t); |
304 | 321 |
305 void register_queue(uint i, GenericTaskQueue<E>* q); | 322 void register_queue(uint i, T* q); |
306 | 323 |
307 GenericTaskQueue<E>* queue(uint n); | 324 T* queue(uint n); |
308 | 325 |
309 // The thread with queue number "queue_num" (and whose random number seed | 326 // The thread with queue number "queue_num" (and whose random number seed |
310 // is at "seed") is trying to steal a task from some other queue. (It | 327 // is at "seed") is trying to steal a task from some other queue. (It |
311 // may try several queues, according to some configuration parameter.) | 328 // may try several queues, according to some configuration parameter.) |
312 // If some steal succeeds, returns "true" and sets "t" the stolen task, | 329 // If some steal succeeds, returns "true" and sets "t" the stolen task, |
314 bool steal(uint queue_num, int* seed, E& t); | 331 bool steal(uint queue_num, int* seed, E& t); |
315 | 332 |
316 bool peek(); | 333 bool peek(); |
317 }; | 334 }; |
318 | 335 |
319 template<class E> | 336 template<class T> void |
320 void GenericTaskQueueSet<E>::register_queue(uint i, GenericTaskQueue<E>* q) { | 337 GenericTaskQueueSet<T>::register_queue(uint i, T* q) { |
321 assert(i < _n, "index out of range."); | 338 assert(i < _n, "index out of range."); |
322 _queues[i] = q; | 339 _queues[i] = q; |
323 } | 340 } |
324 | 341 |
325 template<class E> | 342 template<class T> T* |
326 GenericTaskQueue<E>* GenericTaskQueueSet<E>::queue(uint i) { | 343 GenericTaskQueueSet<T>::queue(uint i) { |
327 return _queues[i]; | 344 return _queues[i]; |
328 } | 345 } |
329 | 346 |
330 template<class E> | 347 template<class T> bool |
331 bool GenericTaskQueueSet<E>::steal(uint queue_num, int* seed, E& t) { | 348 GenericTaskQueueSet<T>::steal(uint queue_num, int* seed, E& t) { |
332 for (uint i = 0; i < 2 * _n; i++) | 349 for (uint i = 0; i < 2 * _n; i++) |
333 if (steal_best_of_2(queue_num, seed, t)) | 350 if (steal_best_of_2(queue_num, seed, t)) |
334 return true; | 351 return true; |
335 return false; | 352 return false; |
336 } | 353 } |
337 | 354 |
338 template<class E> | 355 template<class T> bool |
339 bool GenericTaskQueueSet<E>::steal_best_of_all(uint queue_num, int* seed, E& t) { | 356 GenericTaskQueueSet<T>::steal_best_of_all(uint queue_num, int* seed, E& t) { |
340 if (_n > 2) { | 357 if (_n > 2) { |
341 int best_k; | 358 int best_k; |
342 uint best_sz = 0; | 359 uint best_sz = 0; |
343 for (uint k = 0; k < _n; k++) { | 360 for (uint k = 0; k < _n; k++) { |
344 if (k == queue_num) continue; | 361 if (k == queue_num) continue; |
357 assert(_n == 1, "can't be zero."); | 374 assert(_n == 1, "can't be zero."); |
358 return false; | 375 return false; |
359 } | 376 } |
360 } | 377 } |
361 | 378 |
362 template<class E> | 379 template<class T> bool |
363 bool GenericTaskQueueSet<E>::steal_1_random(uint queue_num, int* seed, E& t) { | 380 GenericTaskQueueSet<T>::steal_1_random(uint queue_num, int* seed, E& t) { |
364 if (_n > 2) { | 381 if (_n > 2) { |
365 uint k = queue_num; | 382 uint k = queue_num; |
366 while (k == queue_num) k = randomParkAndMiller(seed) % _n; | 383 while (k == queue_num) k = randomParkAndMiller(seed) % _n; |
367 return _queues[2]->pop_global(t); | 384 return _queues[2]->pop_global(t); |
368 } else if (_n == 2) { | 385 } else if (_n == 2) { |
373 assert(_n == 1, "can't be zero."); | 390 assert(_n == 1, "can't be zero."); |
374 return false; | 391 return false; |
375 } | 392 } |
376 } | 393 } |
377 | 394 |
378 template<class E> | 395 template<class T> bool |
379 bool GenericTaskQueueSet<E>::steal_best_of_2(uint queue_num, int* seed, E& t) { | 396 GenericTaskQueueSet<T>::steal_best_of_2(uint queue_num, int* seed, E& t) { |
380 if (_n > 2) { | 397 if (_n > 2) { |
381 uint k1 = queue_num; | 398 uint k1 = queue_num; |
382 while (k1 == queue_num) k1 = randomParkAndMiller(seed) % _n; | 399 while (k1 == queue_num) k1 = randomParkAndMiller(seed) % _n; |
383 uint k2 = queue_num; | 400 uint k2 = queue_num; |
384 while (k2 == queue_num || k2 == k1) k2 = randomParkAndMiller(seed) % _n; | 401 while (k2 == queue_num || k2 == k1) k2 = randomParkAndMiller(seed) % _n; |
395 assert(_n == 1, "can't be zero."); | 412 assert(_n == 1, "can't be zero."); |
396 return false; | 413 return false; |
397 } | 414 } |
398 } | 415 } |
399 | 416 |
400 template<class E> | 417 template<class T> |
401 bool GenericTaskQueueSet<E>::peek() { | 418 bool GenericTaskQueueSet<T>::peek() { |
402 // Try all the queues. | 419 // Try all the queues. |
403 for (uint j = 0; j < _n; j++) { | 420 for (uint j = 0; j < _n; j++) { |
404 if (_queues[j]->peek()) | 421 if (_queues[j]->peek()) |
405 return true; | 422 return true; |
406 } | 423 } |
466 static uint total_peeks() { return _total_peeks; } | 483 static uint total_peeks() { return _total_peeks; } |
467 static void print_termination_counts(); | 484 static void print_termination_counts(); |
468 #endif | 485 #endif |
469 }; | 486 }; |
470 | 487 |
471 template<class E> inline bool GenericTaskQueue<E>::push(E t) { | 488 template<class E, unsigned int N> inline bool |
489 GenericTaskQueue<E, N>::push(E t) { | |
472 uint localBot = _bottom; | 490 uint localBot = _bottom; |
473 assert((localBot >= 0) && (localBot < N), "_bottom out of range."); | 491 assert((localBot >= 0) && (localBot < N), "_bottom out of range."); |
474 idx_t top = _age.top(); | 492 idx_t top = _age.top(); |
475 uint dirty_n_elems = dirty_size(localBot, top); | 493 uint dirty_n_elems = dirty_size(localBot, top); |
476 assert((dirty_n_elems >= 0) && (dirty_n_elems < N), "n_elems out of range."); | 494 assert(dirty_n_elems < N, "n_elems out of range."); |
477 if (dirty_n_elems < max_elems()) { | 495 if (dirty_n_elems < max_elems()) { |
478 _elems[localBot] = t; | 496 // g++ complains if the volatile result of the assignment is unused. |
497 const_cast<E&>(_elems[localBot] = t); | |
479 OrderAccess::release_store(&_bottom, increment_index(localBot)); | 498 OrderAccess::release_store(&_bottom, increment_index(localBot)); |
480 return true; | 499 return true; |
481 } else { | 500 } else { |
482 return push_slow(t, dirty_n_elems); | 501 return push_slow(t, dirty_n_elems); |
483 } | 502 } |
484 } | 503 } |
485 | 504 |
486 template<class E> inline bool GenericTaskQueue<E>::pop_local(E& t) { | 505 template<class E, unsigned int N> inline bool |
506 GenericTaskQueue<E, N>::pop_local(E& t) { | |
487 uint localBot = _bottom; | 507 uint localBot = _bottom; |
488 // This value cannot be N-1. That can only occur as a result of | 508 // This value cannot be N-1. That can only occur as a result of |
489 // the assignment to bottom in this method. If it does, this method | 509 // the assignment to bottom in this method. If it does, this method |
490 // resets the size( to 0 before the next call (which is sequential, | 510 // resets the size( to 0 before the next call (which is sequential, |
491 // since this is pop_local.) | 511 // since this is pop_local.) |
495 localBot = decrement_index(localBot); | 515 localBot = decrement_index(localBot); |
496 _bottom = localBot; | 516 _bottom = localBot; |
497 // This is necessary to prevent any read below from being reordered | 517 // This is necessary to prevent any read below from being reordered |
498 // before the store just above. | 518 // before the store just above. |
499 OrderAccess::fence(); | 519 OrderAccess::fence(); |
500 t = _elems[localBot]; | 520 const_cast<E&>(t = _elems[localBot]); |
501 // This is a second read of "age"; the "size()" above is the first. | 521 // This is a second read of "age"; the "size()" above is the first. |
502 // If there's still at least one element in the queue, based on the | 522 // If there's still at least one element in the queue, based on the |
503 // "_bottom" and "age" we've read, then there can be no interference with | 523 // "_bottom" and "age" we've read, then there can be no interference with |
504 // a "pop_global" operation, and we're done. | 524 // a "pop_global" operation, and we're done. |
505 idx_t tp = _age.top(); // XXX | 525 idx_t tp = _age.top(); // XXX |
512 return pop_local_slow(localBot, _age.get()); | 532 return pop_local_slow(localBot, _age.get()); |
513 } | 533 } |
514 } | 534 } |
515 | 535 |
516 typedef oop Task; | 536 typedef oop Task; |
517 typedef GenericTaskQueue<Task> OopTaskQueue; | 537 typedef GenericTaskQueue<Task> OopTaskQueue; |
518 typedef GenericTaskQueueSet<Task> OopTaskQueueSet; | 538 typedef GenericTaskQueueSet<OopTaskQueue> OopTaskQueueSet; |
519 | 539 |
520 | 540 #ifdef _MSC_VER |
521 #define COMPRESSED_OOP_MASK 1 | 541 #pragma warning(push) |
542 // warning C4522: multiple assignment operators specified | |
543 #pragma warning(disable:4522) | |
544 #endif | |
522 | 545 |
523 // This is a container class for either an oop* or a narrowOop*. | 546 // This is a container class for either an oop* or a narrowOop*. |
524 // Both are pushed onto a task queue and the consumer will test is_narrow() | 547 // Both are pushed onto a task queue and the consumer will test is_narrow() |
525 // to determine which should be processed. | 548 // to determine which should be processed. |
526 class StarTask { | 549 class StarTask { |
527 void* _holder; // either union oop* or narrowOop* | 550 void* _holder; // either union oop* or narrowOop* |
551 | |
552 enum { COMPRESSED_OOP_MASK = 1 }; | |
553 | |
528 public: | 554 public: |
529 StarTask(narrowOop* p) { | 555 StarTask(narrowOop* p) { |
530 assert(((uintptr_t)p & COMPRESSED_OOP_MASK) == 0, "Information loss!"); | 556 assert(((uintptr_t)p & COMPRESSED_OOP_MASK) == 0, "Information loss!"); |
531 _holder = (void *)((uintptr_t)p | COMPRESSED_OOP_MASK); | 557 _holder = (void *)((uintptr_t)p | COMPRESSED_OOP_MASK); |
532 } | 558 } |
538 operator oop*() { return (oop*)_holder; } | 564 operator oop*() { return (oop*)_holder; } |
539 operator narrowOop*() { | 565 operator narrowOop*() { |
540 return (narrowOop*)((uintptr_t)_holder & ~COMPRESSED_OOP_MASK); | 566 return (narrowOop*)((uintptr_t)_holder & ~COMPRESSED_OOP_MASK); |
541 } | 567 } |
542 | 568 |
543 // Operators to preserve const/volatile in assignments required by gcc | 569 StarTask& operator=(const StarTask& t) { |
544 void operator=(const volatile StarTask& t) volatile { _holder = t._holder; } | 570 _holder = t._holder; |
571 return *this; | |
572 } | |
573 volatile StarTask& operator=(const volatile StarTask& t) volatile { | |
574 _holder = t._holder; | |
575 return *this; | |
576 } | |
545 | 577 |
546 bool is_narrow() const { | 578 bool is_narrow() const { |
547 return (((uintptr_t)_holder & COMPRESSED_OOP_MASK) != 0); | 579 return (((uintptr_t)_holder & COMPRESSED_OOP_MASK) != 0); |
548 } | 580 } |
549 }; | 581 }; |
550 | 582 |
551 typedef GenericTaskQueue<StarTask> OopStarTaskQueue; | 583 class ObjArrayTask |
552 typedef GenericTaskQueueSet<StarTask> OopStarTaskQueueSet; | 584 { |
585 public: | |
586 ObjArrayTask(oop o = NULL, int idx = 0): _obj(o), _index(idx) { } | |
587 ObjArrayTask(oop o, size_t idx): _obj(o), _index(int(idx)) { | |
588 assert(idx <= size_t(max_jint), "too big"); | |
589 } | |
590 ObjArrayTask(const ObjArrayTask& t): _obj(t._obj), _index(t._index) { } | |
591 | |
592 ObjArrayTask& operator =(const ObjArrayTask& t) { | |
593 _obj = t._obj; | |
594 _index = t._index; | |
595 return *this; | |
596 } | |
597 volatile ObjArrayTask& | |
598 operator =(const volatile ObjArrayTask& t) volatile { | |
599 _obj = t._obj; | |
600 _index = t._index; | |
601 return *this; | |
602 } | |
603 | |
604 inline oop obj() const { return _obj; } | |
605 inline int index() const { return _index; } | |
606 | |
607 DEBUG_ONLY(bool is_valid() const); // Tasks to be pushed/popped must be valid. | |
608 | |
609 private: | |
610 oop _obj; | |
611 int _index; | |
612 }; | |
613 | |
614 #ifdef _MSC_VER | |
615 #pragma warning(pop) | |
616 #endif | |
617 | |
618 typedef GenericTaskQueue<StarTask> OopStarTaskQueue; | |
619 typedef GenericTaskQueueSet<OopStarTaskQueue> OopStarTaskQueueSet; | |
553 | 620 |
554 typedef size_t RegionTask; // index for region | 621 typedef size_t RegionTask; // index for region |
555 typedef GenericTaskQueue<RegionTask> RegionTaskQueue; | 622 typedef GenericTaskQueue<RegionTask> RegionTaskQueue; |
556 typedef GenericTaskQueueSet<RegionTask> RegionTaskQueueSet; | 623 typedef GenericTaskQueueSet<RegionTaskQueue> RegionTaskQueueSet; |
557 | 624 |
558 class RegionTaskQueueWithOverflow: public CHeapObj { | 625 class RegionTaskQueueWithOverflow: public CHeapObj { |
559 protected: | 626 protected: |
560 RegionTaskQueue _region_queue; | 627 RegionTaskQueue _region_queue; |
561 GrowableArray<RegionTask>* _overflow_stack; | 628 GrowableArray<RegionTask>* _overflow_stack; |