taskqueue.hpp 21.6 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
D
duke 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
19 20 21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
22 23 24
 *
 */

25
template <unsigned int N>
D
duke 已提交
26 27
class TaskQueueSuper: public CHeapObj {
protected:
28 29 30 31
  // Internal type for indexing the queue; also used for the tag.
  typedef NOT_LP64(uint16_t) LP64_ONLY(uint32_t) idx_t;

  // The first free element after the last one pushed (mod N).
32
  volatile uint _bottom;
D
duke 已提交
33

34
  enum { MOD_N_MASK = N - 1 };
D
duke 已提交
35

36 37 38 39 40
  class Age {
  public:
    Age(size_t data = 0)         { _data = data; }
    Age(const Age& age)          { _data = age._data; }
    Age(idx_t top, idx_t tag)    { _fields._top = top; _fields._tag = tag; }
D
duke 已提交
41

42 43
    Age   get()        const volatile { return _data; }
    void  set(Age age) volatile       { _data = age._data; }
D
duke 已提交
44

45 46
    idx_t top()        const volatile { return _fields._top; }
    idx_t tag()        const volatile { return _fields._tag; }
D
duke 已提交
47

48 49 50 51 52
    // Increment top; if it wraps, increment tag also.
    void increment() {
      _fields._top = increment_index(_fields._top);
      if (_fields._top == 0) ++_fields._tag;
    }
D
duke 已提交
53

54 55 56 57
    Age cmpxchg(const Age new_age, const Age old_age) volatile {
      return (size_t) Atomic::cmpxchg_ptr((intptr_t)new_age._data,
                                          (volatile intptr_t *)&_data,
                                          (intptr_t)old_age._data);
D
duke 已提交
58
    }
59 60 61 62 63 64 65 66 67 68 69 70

    bool operator ==(const Age& other) const { return _data == other._data; }

  private:
    struct fields {
      idx_t _top;
      idx_t _tag;
    };
    union {
      size_t _data;
      fields _fields;
    };
D
duke 已提交
71 72
  };

73
  volatile Age _age;
D
duke 已提交
74

75 76 77
  // These both operate mod N.
  static uint increment_index(uint ind) {
    return (ind + 1) & MOD_N_MASK;
D
duke 已提交
78
  }
79 80
  static uint decrement_index(uint ind) {
    return (ind - 1) & MOD_N_MASK;
D
duke 已提交
81 82
  }

83 84
  // Returns a number in the range [0..N).  If the result is "N-1", it should be
  // interpreted as 0.
85
  uint dirty_size(uint bot, uint top) const {
86
    return (bot - top) & MOD_N_MASK;
D
duke 已提交
87 88 89
  }

  // Returns the size corresponding to the given "bot" and "top".
90
  uint size(uint bot, uint top) const {
91
    uint sz = dirty_size(bot, top);
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    // Has the queue "wrapped", so that bottom is less than top?  There's a
    // complicated special case here.  A pair of threads could perform pop_local
    // and pop_global operations concurrently, starting from a state in which
    // _bottom == _top+1.  The pop_local could succeed in decrementing _bottom,
    // and the pop_global in incrementing _top (in which case the pop_global
    // will be awarded the contested queue element.)  The resulting state must
    // be interpreted as an empty queue.  (We only need to worry about one such
    // event: only the queue owner performs pop_local's, and several concurrent
    // threads attempting to perform the pop_global will all perform the same
    // CAS, and only one can succeed.)  Any stealing thread that reads after
    // either the increment or decrement will see an empty queue, and will not
    // join the competitors.  The "sz == -1 || sz == N-1" state will not be
    // modified by concurrent queues, so the owner thread can reset the state to
    // _bottom == top so subsequent pushes will be performed normally.
    return (sz == N - 1) ? 0 : sz;
D
duke 已提交
107 108 109 110 111
  }

public:
  TaskQueueSuper() : _bottom(0), _age() {}

112 113 114
  // Return true if the TaskQueue contains/does not contain any tasks.
  bool peek()     const { return _bottom != _age.top(); }
  bool is_empty() const { return size() == 0; }
D
duke 已提交
115 116 117 118

  // Return an estimate of the number of elements in the queue.
  // The "careful" version admits the possibility of pop_local/pop_global
  // races.
119
  uint size() const {
120
    return size(_bottom, _age.top());
D
duke 已提交
121 122
  }

123
  uint dirty_size() const {
124
    return dirty_size(_bottom, _age.top());
D
duke 已提交
125 126
  }

127 128
  void set_empty() {
    _bottom = 0;
129
    _age.set(0);
130 131
  }

D
duke 已提交
132 133
  // Maximum number of elements allowed in the queue.  This is two less
  // than the actual queue size, for somewhat complicated reasons.
134
  uint max_elems() const { return N - 2; }
135 136 137

  // Total size of queue.
  static const uint total_size() { return N; }
D
duke 已提交
138 139
};

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
template<class E, unsigned int N = TASKQUEUE_SIZE>
class GenericTaskQueue: public TaskQueueSuper<N> {
protected:
  typedef typename TaskQueueSuper<N>::Age Age;
  typedef typename TaskQueueSuper<N>::idx_t idx_t;

  using TaskQueueSuper<N>::_bottom;
  using TaskQueueSuper<N>::_age;
  using TaskQueueSuper<N>::increment_index;
  using TaskQueueSuper<N>::decrement_index;
  using TaskQueueSuper<N>::dirty_size;

public:
  using TaskQueueSuper<N>::max_elems;
  using TaskQueueSuper<N>::size;

D
duke 已提交
156 157
private:
  // Slow paths for push, pop_local.  (pop_global has no fast path.)
158 159
  bool push_slow(E t, uint dirty_n_elems);
  bool pop_local_slow(uint localBot, Age oldAge);
D
duke 已提交
160 161

public:
162 163
  typedef E element_type;

D
duke 已提交
164 165 166 167 168
  // Initializes the queue to empty.
  GenericTaskQueue();

  void initialize();

169
  // Push the task "t" on the queue.  Returns "false" iff the queue is full.
D
duke 已提交
170 171
  inline bool push(E t);

172 173 174
  // Attempts to claim a task from the "local" end of the queue (the most
  // recently pushed).  If successful, returns true and sets t to the task;
  // otherwise, returns false (the queue is empty).
D
duke 已提交
175 176
  inline bool pop_local(E& t);

177 178
  // Like pop_local(), but uses the "global" end of the queue (the least
  // recently pushed).
D
duke 已提交
179 180 181 182 183
  bool pop_global(E& t);

  // Delete any resource associated with the queue.
  ~GenericTaskQueue();

184 185 186
  // apply the closure to all elements in the task queue
  void oops_do(OopClosure* f);

D
duke 已提交
187 188 189 190 191
private:
  // Element array.
  volatile E* _elems;
};

192 193
template<class E, unsigned int N>
GenericTaskQueue<E, N>::GenericTaskQueue() {
194
  assert(sizeof(Age) == sizeof(size_t), "Depends on this.");
D
duke 已提交
195 196
}

197 198
template<class E, unsigned int N>
void GenericTaskQueue<E, N>::initialize() {
199
  _elems = NEW_C_HEAP_ARRAY(E, N);
D
duke 已提交
200 201
}

202 203
template<class E, unsigned int N>
void GenericTaskQueue<E, N>::oops_do(OopClosure* f) {
204
  // tty->print_cr("START OopTaskQueue::oops_do");
205 206 207
  uint iters = size();
  uint index = _bottom;
  for (uint i = 0; i < iters; ++i) {
208 209 210 211 212 213 214 215 216 217 218
    index = decrement_index(index);
    // tty->print_cr("  doing entry %d," INTPTR_T " -> " INTPTR_T,
    //            index, &_elems[index], _elems[index]);
    E* t = (E*)&_elems[index];      // cast away volatility
    oop* p = (oop*)t;
    assert((*t)->is_oop_or_null(), "Not an oop or null");
    f->do_oop(p);
  }
  // tty->print_cr("END OopTaskQueue::oops_do");
}

219 220
template<class E, unsigned int N>
bool GenericTaskQueue<E, N>::push_slow(E t, uint dirty_n_elems) {
221
  if (dirty_n_elems == N - 1) {
D
duke 已提交
222
    // Actually means 0, so do the push.
223
    uint localBot = _bottom;
224 225
    // g++ complains if the volatile result of the assignment is unused.
    const_cast<E&>(_elems[localBot] = t);
226
    OrderAccess::release_store(&_bottom, increment_index(localBot));
D
duke 已提交
227
    return true;
228 229
  }
  return false;
D
duke 已提交
230 231
}

232 233
template<class E, unsigned int N>
bool GenericTaskQueue<E, N>::
234
pop_local_slow(uint localBot, Age oldAge) {
D
duke 已提交
235 236 237 238 239 240 241 242 243
  // This queue was observed to contain exactly one element; either this
  // thread will claim it, or a competing "pop_global".  In either case,
  // the queue will be logically empty afterwards.  Create a new Age value
  // that represents the empty queue for the given value of "_bottom".  (We
  // must also increment "tag" because of the case where "bottom == 1",
  // "top == 0".  A pop_global could read the queue element in that case,
  // then have the owner thread do a pop followed by another push.  Without
  // the incrementing of "tag", the pop_global's CAS could succeed,
  // allowing it to believe it has claimed the stale element.)
244
  Age newAge((idx_t)localBot, oldAge.tag() + 1);
D
duke 已提交
245 246 247 248 249
  // Perhaps a competing pop_global has already incremented "top", in which
  // case it wins the element.
  if (localBot == oldAge.top()) {
    // No competing pop_global has yet incremented "top"; we'll try to
    // install new_age, thus claiming the element.
250
    Age tempAge = _age.cmpxchg(newAge, oldAge);
D
duke 已提交
251 252
    if (tempAge == oldAge) {
      // We win.
253
      assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
D
duke 已提交
254 255 256
      return true;
    }
  }
257 258 259 260 261
  // We lose; a completing pop_global gets the element.  But the queue is empty
  // and top is greater than bottom.  Fix this representation of the empty queue
  // to become the canonical one.
  _age.set(newAge);
  assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
D
duke 已提交
262 263 264
  return false;
}

265 266
template<class E, unsigned int N>
bool GenericTaskQueue<E, N>::pop_global(E& t) {
267
  Age oldAge = _age.get();
268 269
  uint localBot = _bottom;
  uint n_elems = size(localBot, oldAge.top());
D
duke 已提交
270 271 272
  if (n_elems == 0) {
    return false;
  }
273

274
  const_cast<E&>(t = _elems[oldAge.top()]);
275 276 277 278
  Age newAge(oldAge);
  newAge.increment();
  Age resAge = _age.cmpxchg(newAge, oldAge);

D
duke 已提交
279 280
  // Note that using "_bottom" here might fail, since a pop_local might
  // have decremented it.
281 282
  assert(dirty_size(localBot, newAge.top()) != N - 1, "sanity");
  return resAge == oldAge;
D
duke 已提交
283 284
}

285 286
template<class E, unsigned int N>
GenericTaskQueue<E, N>::~GenericTaskQueue() {
D
duke 已提交
287 288 289
  FREE_C_HEAP_ARRAY(E, _elems);
}

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
// OverflowTaskQueue is a TaskQueue that also includes an overflow stack for
// elements that do not fit in the TaskQueue.
//
// Three methods from super classes are overridden:
//
// initialize() - initialize the super classes and create the overflow stack
// push() - push onto the task queue or, if that fails, onto the overflow stack
// is_empty() - return true if both the TaskQueue and overflow stack are empty
//
// Note that size() is not overridden--it returns the number of elements in the
// TaskQueue, and does not include the size of the overflow stack.  This
// simplifies replacement of GenericTaskQueues with OverflowTaskQueues.
template<class E, unsigned int N = TASKQUEUE_SIZE>
class OverflowTaskQueue: public GenericTaskQueue<E, N>
{
public:
  typedef GrowableArray<E>       overflow_t;
  typedef GenericTaskQueue<E, N> taskqueue_t;

  OverflowTaskQueue();
  ~OverflowTaskQueue();
  void initialize();

  inline overflow_t* overflow_stack() const { return _overflow_stack; }

  // Push task t onto the queue or onto the overflow stack.  Return true.
  inline bool push(E t);

  // Attempt to pop from the overflow stack; return true if anything was popped.
  inline bool pop_overflow(E& t);

  inline bool taskqueue_empty() const { return taskqueue_t::is_empty(); }
  inline bool overflow_empty()  const { return overflow_stack()->is_empty(); }
  inline bool is_empty()        const {
    return taskqueue_empty() && overflow_empty();
  }

private:
  overflow_t* _overflow_stack;
};

template <class E, unsigned int N>
OverflowTaskQueue<E, N>::OverflowTaskQueue()
{
  _overflow_stack = NULL;
}

template <class E, unsigned int N>
OverflowTaskQueue<E, N>::~OverflowTaskQueue()
{
  if (_overflow_stack != NULL) {
    delete _overflow_stack;
    _overflow_stack = NULL;
  }
}

template <class E, unsigned int N>
void OverflowTaskQueue<E, N>::initialize()
{
  taskqueue_t::initialize();
  assert(_overflow_stack == NULL, "memory leak");
  _overflow_stack = new (ResourceObj::C_HEAP) GrowableArray<E>(10, true);
}

template <class E, unsigned int N>
bool OverflowTaskQueue<E, N>::push(E t)
{
  if (!taskqueue_t::push(t)) {
    overflow_stack()->push(t);
  }
  return true;
}

template <class E, unsigned int N>
bool OverflowTaskQueue<E, N>::pop_overflow(E& t)
{
  if (overflow_empty()) return false;
  t = overflow_stack()->pop();
  return true;
}

D
duke 已提交
371 372 373 374 375 376 377 378
class TaskQueueSetSuper: public CHeapObj {
protected:
  static int randomParkAndMiller(int* seed0);
public:
  // Returns "true" if some TaskQueue in the set contains a task.
  virtual bool peek() = 0;
};

379 380
template<class T>
class GenericTaskQueueSet: public TaskQueueSetSuper {
D
duke 已提交
381
private:
382
  uint _n;
383
  T** _queues;
D
duke 已提交
384 385

public:
386 387
  typedef typename T::element_type E;

D
duke 已提交
388
  GenericTaskQueueSet(int n) : _n(n) {
389
    typedef T* GenericTaskQueuePtr;
D
duke 已提交
390 391 392 393 394 395
    _queues = NEW_C_HEAP_ARRAY(GenericTaskQueuePtr, n);
    for (int i = 0; i < n; i++) {
      _queues[i] = NULL;
    }
  }

396 397 398
  bool steal_1_random(uint queue_num, int* seed, E& t);
  bool steal_best_of_2(uint queue_num, int* seed, E& t);
  bool steal_best_of_all(uint queue_num, int* seed, E& t);
D
duke 已提交
399

400
  void register_queue(uint i, T* q);
D
duke 已提交
401

402
  T* queue(uint n);
D
duke 已提交
403

404 405 406 407 408
  // The thread with queue number "queue_num" (and whose random number seed is
  // at "seed") is trying to steal a task from some other queue.  (It may try
  // several queues, according to some configuration parameter.)  If some steal
  // succeeds, returns "true" and sets "t" to the stolen task, otherwise returns
  // false.
409
  bool steal(uint queue_num, int* seed, E& t);
D
duke 已提交
410 411 412 413

  bool peek();
};

414 415
template<class T> void
GenericTaskQueueSet<T>::register_queue(uint i, T* q) {
416
  assert(i < _n, "index out of range.");
D
duke 已提交
417 418 419
  _queues[i] = q;
}

420 421
template<class T> T*
GenericTaskQueueSet<T>::queue(uint i) {
D
duke 已提交
422 423 424
  return _queues[i];
}

425 426
template<class T> bool
GenericTaskQueueSet<T>::steal(uint queue_num, int* seed, E& t) {
427
  for (uint i = 0; i < 2 * _n; i++)
D
duke 已提交
428 429 430 431 432
    if (steal_best_of_2(queue_num, seed, t))
      return true;
  return false;
}

433 434
template<class T> bool
GenericTaskQueueSet<T>::steal_best_of_all(uint queue_num, int* seed, E& t) {
D
duke 已提交
435 436
  if (_n > 2) {
    int best_k;
437 438
    uint best_sz = 0;
    for (uint k = 0; k < _n; k++) {
D
duke 已提交
439
      if (k == queue_num) continue;
440
      uint sz = _queues[k]->size();
D
duke 已提交
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
      if (sz > best_sz) {
        best_sz = sz;
        best_k = k;
      }
    }
    return best_sz > 0 && _queues[best_k]->pop_global(t);
  } else if (_n == 2) {
    // Just try the other one.
    int k = (queue_num + 1) % 2;
    return _queues[k]->pop_global(t);
  } else {
    assert(_n == 1, "can't be zero.");
    return false;
  }
}

457 458
template<class T> bool
GenericTaskQueueSet<T>::steal_1_random(uint queue_num, int* seed, E& t) {
D
duke 已提交
459
  if (_n > 2) {
460
    uint k = queue_num;
D
duke 已提交
461 462 463 464 465 466 467 468 469 470 471 472
    while (k == queue_num) k = randomParkAndMiller(seed) % _n;
    return _queues[2]->pop_global(t);
  } else if (_n == 2) {
    // Just try the other one.
    int k = (queue_num + 1) % 2;
    return _queues[k]->pop_global(t);
  } else {
    assert(_n == 1, "can't be zero.");
    return false;
  }
}

473 474
template<class T> bool
GenericTaskQueueSet<T>::steal_best_of_2(uint queue_num, int* seed, E& t) {
D
duke 已提交
475
  if (_n > 2) {
476
    uint k1 = queue_num;
D
duke 已提交
477
    while (k1 == queue_num) k1 = randomParkAndMiller(seed) % _n;
478
    uint k2 = queue_num;
D
duke 已提交
479 480
    while (k2 == queue_num || k2 == k1) k2 = randomParkAndMiller(seed) % _n;
    // Sample both and try the larger.
481 482
    uint sz1 = _queues[k1]->size();
    uint sz2 = _queues[k2]->size();
D
duke 已提交
483 484 485 486
    if (sz2 > sz1) return _queues[k2]->pop_global(t);
    else return _queues[k1]->pop_global(t);
  } else if (_n == 2) {
    // Just try the other one.
487
    uint k = (queue_num + 1) % 2;
D
duke 已提交
488 489 490 491 492 493 494
    return _queues[k]->pop_global(t);
  } else {
    assert(_n == 1, "can't be zero.");
    return false;
  }
}

495 496
template<class T>
bool GenericTaskQueueSet<T>::peek() {
D
duke 已提交
497
  // Try all the queues.
498
  for (uint j = 0; j < _n; j++) {
D
duke 已提交
499 500 501 502 503 504
    if (_queues[j]->peek())
      return true;
  }
  return false;
}

505 506 507 508 509 510
// When to terminate from the termination protocol.
class TerminatorTerminator: public CHeapObj {
public:
  virtual bool should_exit_termination() = 0;
};

D
duke 已提交
511 512 513
// A class to aid in the termination of a set of parallel tasks using
// TaskQueueSet's for work stealing.

514 515
#undef TRACESPINNING

D
duke 已提交
516 517 518 519
class ParallelTaskTerminator: public StackObj {
private:
  int _n_threads;
  TaskQueueSetSuper* _queue_set;
520
  int _offered_termination;
D
duke 已提交
521

522 523 524 525 526 527
#ifdef TRACESPINNING
  static uint _total_yields;
  static uint _total_spins;
  static uint _total_peeks;
#endif

D
duke 已提交
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
  bool peek_in_queue_set();
protected:
  virtual void yield();
  void sleep(uint millis);

public:

  // "n_threads" is the number of threads to be terminated.  "queue_set" is a
  // queue sets of work queues of other threads.
  ParallelTaskTerminator(int n_threads, TaskQueueSetSuper* queue_set);

  // The current thread has no work, and is ready to terminate if everyone
  // else is.  If returns "true", all threads are terminated.  If returns
  // "false", available work has been observed in one of the task queues,
  // so the global task is not complete.
543 544 545 546
  bool offer_termination() {
    return offer_termination(NULL);
  }

547
  // As above, but it also terminates if the should_exit_termination()
548 549 550
  // method of the terminator parameter returns true. If terminator is
  // NULL, then it is ignored.
  bool offer_termination(TerminatorTerminator* terminator);
D
duke 已提交
551 552 553 554 555 556 557

  // Reset the terminator, so that it may be reused again.
  // The caller is responsible for ensuring that this is done
  // in an MT-safe manner, once the previous round of use of
  // the terminator is finished.
  void reset_for_reuse();

558 559 560 561 562 563
#ifdef TRACESPINNING
  static uint total_yields() { return _total_yields; }
  static uint total_spins() { return _total_spins; }
  static uint total_peeks() { return _total_peeks; }
  static void print_termination_counts();
#endif
D
duke 已提交
564 565
};

566 567
template<class E, unsigned int N> inline bool
GenericTaskQueue<E, N>::push(E t) {
568
  uint localBot = _bottom;
569 570
  assert((localBot >= 0) && (localBot < N), "_bottom out of range.");
  idx_t top = _age.top();
571
  uint dirty_n_elems = dirty_size(localBot, top);
572
  assert(dirty_n_elems < N, "n_elems out of range.");
D
duke 已提交
573
  if (dirty_n_elems < max_elems()) {
574 575
    // g++ complains if the volatile result of the assignment is unused.
    const_cast<E&>(_elems[localBot] = t);
576
    OrderAccess::release_store(&_bottom, increment_index(localBot));
D
duke 已提交
577 578 579 580 581 582
    return true;
  } else {
    return push_slow(t, dirty_n_elems);
  }
}

583 584
template<class E, unsigned int N> inline bool
GenericTaskQueue<E, N>::pop_local(E& t) {
585
  uint localBot = _bottom;
586
  // This value cannot be N-1.  That can only occur as a result of
D
duke 已提交
587
  // the assignment to bottom in this method.  If it does, this method
588
  // resets the size to 0 before the next call (which is sequential,
D
duke 已提交
589
  // since this is pop_local.)
590 591
  uint dirty_n_elems = dirty_size(localBot, _age.top());
  assert(dirty_n_elems != N - 1, "Shouldn't be possible...");
D
duke 已提交
592 593 594 595 596 597
  if (dirty_n_elems == 0) return false;
  localBot = decrement_index(localBot);
  _bottom = localBot;
  // This is necessary to prevent any read below from being reordered
  // before the store just above.
  OrderAccess::fence();
598
  const_cast<E&>(t = _elems[localBot]);
D
duke 已提交
599 600 601 602
  // This is a second read of "age"; the "size()" above is the first.
  // If there's still at least one element in the queue, based on the
  // "_bottom" and "age" we've read, then there can be no interference with
  // a "pop_global" operation, and we're done.
603
  idx_t tp = _age.top();    // XXX
D
duke 已提交
604
  if (size(localBot, tp) > 0) {
605
    assert(dirty_size(localBot, tp) != N - 1, "sanity");
D
duke 已提交
606 607 608 609
    return true;
  } else {
    // Otherwise, the queue contained exactly one element; we take the slow
    // path.
610
    return pop_local_slow(localBot, _age.get());
D
duke 已提交
611 612 613
  }
}

614
typedef GenericTaskQueue<oop>             OopTaskQueue;
615
typedef GenericTaskQueueSet<OopTaskQueue> OopTaskQueueSet;
D
duke 已提交
616

617 618 619 620 621
#ifdef _MSC_VER
#pragma warning(push)
// warning C4522: multiple assignment operators specified
#pragma warning(disable:4522)
#endif
622 623 624 625 626 627

// This is a container class for either an oop* or a narrowOop*.
// Both are pushed onto a task queue and the consumer will test is_narrow()
// to determine which should be processed.
class StarTask {
  void*  _holder;        // either union oop* or narrowOop*
628 629 630

  enum { COMPRESSED_OOP_MASK = 1 };

631
 public:
632 633 634 635 636 637 638 639
  StarTask(narrowOop* p) {
    assert(((uintptr_t)p & COMPRESSED_OOP_MASK) == 0, "Information loss!");
    _holder = (void *)((uintptr_t)p | COMPRESSED_OOP_MASK);
  }
  StarTask(oop* p)       {
    assert(((uintptr_t)p & COMPRESSED_OOP_MASK) == 0, "Information loss!");
    _holder = (void*)p;
  }
640 641 642 643 644 645
  StarTask()             { _holder = NULL; }
  operator oop*()        { return (oop*)_holder; }
  operator narrowOop*()  {
    return (narrowOop*)((uintptr_t)_holder & ~COMPRESSED_OOP_MASK);
  }

646 647 648 649 650 651 652 653
  StarTask& operator=(const StarTask& t) {
    _holder = t._holder;
    return *this;
  }
  volatile StarTask& operator=(const volatile StarTask& t) volatile {
    _holder = t._holder;
    return *this;
  }
654 655 656 657 658 659

  bool is_narrow() const {
    return (((uintptr_t)_holder & COMPRESSED_OOP_MASK) != 0);
  }
};

660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
class ObjArrayTask
{
public:
  ObjArrayTask(oop o = NULL, int idx = 0): _obj(o), _index(idx) { }
  ObjArrayTask(oop o, size_t idx): _obj(o), _index(int(idx)) {
    assert(idx <= size_t(max_jint), "too big");
  }
  ObjArrayTask(const ObjArrayTask& t): _obj(t._obj), _index(t._index) { }

  ObjArrayTask& operator =(const ObjArrayTask& t) {
    _obj = t._obj;
    _index = t._index;
    return *this;
  }
  volatile ObjArrayTask&
  operator =(const volatile ObjArrayTask& t) volatile {
    _obj = t._obj;
    _index = t._index;
    return *this;
  }

  inline oop obj()   const { return _obj; }
  inline int index() const { return _index; }

  DEBUG_ONLY(bool is_valid() const); // Tasks to be pushed/popped must be valid.

private:
  oop _obj;
  int _index;
};

#ifdef _MSC_VER
#pragma warning(pop)
#endif

695
typedef OverflowTaskQueue<StarTask>           OopStarTaskQueue;
696
typedef GenericTaskQueueSet<OopStarTaskQueue> OopStarTaskQueueSet;
D
duke 已提交
697

698 699
typedef OverflowTaskQueue<size_t>             RegionTaskQueue;
typedef GenericTaskQueueSet<RegionTaskQueue>  RegionTaskQueueSet;