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;