001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.mmtk.plan;
014
015import org.mmtk.utility.Log;
016import org.mmtk.utility.options.Options;
017import org.mmtk.utility.statistics.Timer;
018import org.mmtk.vm.VM;
019
020import org.vmmagic.pragma.*;
021
022/**
023 * A garbage collection proceeds as a sequence of phases. Each
024 * phase is either simple (singular) or complex (an array).<p>
025 *
026 * The context an individual phase executes in may be global, mutator,
027 * or collector.<p>
028 *
029 * Phases are executed within a stack and all synchronization between
030 * parallel GC threads is managed from within this class.
031 *
032 * @see MutatorContext#collectionPhase
033 */
034@Uninterruptible
035public abstract class Phase {
036  /***********************************************************************
037  *
038  * Phase allocation and storage.
039  */
040
041  /** The maximum number of phases */
042  private static final int MAX_PHASES = 64;
043  /** The array of phase instances. Zero is unused. */
044  private static final Phase[] phases = new Phase[MAX_PHASES];
045  /** The id to be allocated for the next phase */
046  private static short nextPhaseId = 1;
047
048  /** Run the phase globally. */
049  protected static final short SCHEDULE_GLOBAL = 1;
050  /** Run the phase on collectors. */
051  protected static final short SCHEDULE_COLLECTOR = 2;
052  /** Run the phase on mutators. */
053  protected static final short SCHEDULE_MUTATOR = 3;
054  /** Run this phase concurrently with the mutators */
055  protected static final short SCHEDULE_CONCURRENT = 4;
056  /** Don't run this phase. */
057  protected static final short SCHEDULE_PLACEHOLDER = 100;
058  /** This is a complex phase. */
059  protected static final short SCHEDULE_COMPLEX = 101;
060
061  /**
062   * Retrieve a phase by the unique phase identifier.
063   *
064   * @param id The phase identifier.
065   * @return The Phase instance.
066   */
067  public static Phase getPhase(short id) {
068    if (VM.VERIFY_ASSERTIONS) {
069      VM.assertions._assert(id < nextPhaseId, "Phase ID unknown");
070      VM.assertions._assert(phases[id] != null, "Uninitialised phase");
071    }
072    return phases[id];
073  }
074
075  /**
076   * @param scheduledPhase an encoded phase
077   * @return the phase id component of an encoded phase
078   */
079  protected static short getPhaseId(int scheduledPhase) {
080    short phaseId = (short)(scheduledPhase & 0x0000FFFF);
081    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(phaseId > 0);
082    return phaseId;
083  }
084
085  /**
086   * @param phaseId The unique phase identifier.
087   * @return The name of the phase.
088   */
089  public static String getName(short phaseId) {
090    return phases[phaseId].name;
091  }
092
093  /**
094   * @param scheduledPhase an encoded phase
095   * @return the ordering component of an encoded phase
096   */
097  protected static short getSchedule(int scheduledPhase) {
098    short ordering = (short)((scheduledPhase >> 16) & 0x0000FFFF);
099    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(ordering > 0);
100    return ordering;
101  }
102
103  /**
104   * @param ordering the ordering component of a phase
105   * @return human-readable name for the schedule
106   */
107  protected static String getScheduleName(short ordering) {
108    switch (ordering) {
109      case SCHEDULE_GLOBAL:      return "Global";
110      case SCHEDULE_COLLECTOR:   return "Collector";
111      case SCHEDULE_MUTATOR:     return "Mutator";
112      case SCHEDULE_CONCURRENT:  return "Concurrent";
113      case SCHEDULE_PLACEHOLDER: return "Placeholder";
114      case SCHEDULE_COMPLEX:     return "Complex";
115      default:                   return "UNKNOWN!";
116    }
117  }
118
119  /**
120   * Constructs a phase.
121   *
122   * @param name Display name of the phase
123   * @return the id of the simple phase
124   */
125  @Interruptible
126  public static short createSimple(String name) {
127    return new SimplePhase(name).getId();
128  }
129
130  /**
131   * Constructs a phase, re-using a specified timer.
132   *
133   * @param name Display name of the phase
134   * @param timer the time to re-use
135   * @return the id of the simple phase
136   */
137  @Interruptible
138  public static short createSimple(String name, Timer timer) {
139    return new SimplePhase(name, timer).getId();
140  }
141
142  /**
143   * Constructs a complex phase.
144   *
145   * @param name Display name of the phase
146   * @param scheduledPhases The phases in this complex phase.
147   * @return the phase's id
148   */
149  @Interruptible
150  public static short createComplex(String name,int... scheduledPhases) {
151    return new ComplexPhase(name, scheduledPhases).getId();
152  }
153
154  /**
155   * Constructs a complex phase, re-using a specified timer.
156   *
157   * @param name Display name of the phase
158   * @param timer Timer for this phase to contribute to
159   * @param scheduledPhases The phases in this complex phase.
160   * @return the phase's id
161   */
162  @Interruptible
163  public static short createComplex(String name, Timer timer, int... scheduledPhases) {
164    return new ComplexPhase(name, timer, scheduledPhases).getId();
165  }
166
167  /**
168   * Constructs a phase.
169   *
170   * @param name Display name of the phase
171   * @param atomicScheduledPhase The corresponding atomic phase to run in a stop the world collection
172   * @return the phase's id
173   */
174  @Interruptible
175  public static final short createConcurrent(String name, int atomicScheduledPhase) {
176    return new ConcurrentPhase(name, atomicScheduledPhase).getId();
177  }
178
179  /**
180   * Construct a phase, re-using a specified timer.
181   *
182   * @param name Display name of the phase
183   * @param timer Timer for this phase to contribute to
184   * @param atomicScheduledPhase The corresponding atomic phase to run in a stop the world collection
185   * @return the phase's id
186   */
187  @Interruptible
188  public static final short createConcurrent(String name, Timer timer, int atomicScheduledPhase) {
189    return new ConcurrentPhase(name, timer, atomicScheduledPhase).getId();
190  }
191
192  /**
193   * Take the passed phase and return an encoded phase to
194   * run that phase as a complex phase.
195   *
196   * @param phaseId The phase to run as complex
197   * @return The encoded phase value.
198   */
199  public static int scheduleComplex(short phaseId) {
200    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof ComplexPhase);
201    return (SCHEDULE_COMPLEX << 16) + phaseId;
202  }
203
204  /**
205   * Take the passed phase and return an encoded phase to
206   * run that phase as a concurrent phase.
207   *
208   * @param phaseId The phase to run as concurrent
209   * @return The encoded phase value.
210   */
211  public static int scheduleConcurrent(short phaseId) {
212    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof ConcurrentPhase);
213    return (SCHEDULE_CONCURRENT << 16) + phaseId;
214  }
215
216  /**
217   * Take the passed phase and return an encoded phase to
218   * run that phase in a global context;
219   *
220   * @param phaseId The phase to run globally
221   * @return The encoded phase value.
222   */
223  public static int scheduleGlobal(short phaseId) {
224    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase);
225    return (SCHEDULE_GLOBAL << 16) + phaseId;
226  }
227
228  /**
229   * Take the passed phase and return an encoded phase to
230   * run that phase in a collector context;
231   *
232   * @param phaseId The phase to run on collectors
233   * @return The encoded phase value.
234   */
235  public static int scheduleCollector(short phaseId) {
236    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase);
237    return (SCHEDULE_COLLECTOR << 16) + phaseId;
238  }
239
240  /**
241   * Take the passed phase and return an encoded phase to
242   * run that phase in a mutator context;
243   *
244   * @param phaseId The phase to run on mutators
245   * @return The encoded phase value.
246   */
247  public static int scheduleMutator(short phaseId) {
248    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase);
249    return (SCHEDULE_MUTATOR << 16) + phaseId;
250  }
251
252  /**
253   * Take the passed phase and return an encoded phase to
254   * run that phase in a mutator context;
255   *
256   * @param phaseId The phase to run on mutators
257   * @return The encoded phase value.
258   */
259  public static int schedulePlaceholder(short phaseId) {
260    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase);
261    return (SCHEDULE_PLACEHOLDER << 16) + phaseId;
262  }
263
264  /***********************************************************************
265   *
266   * Phase instance fields/methods.
267   */
268
269  /**
270   * The unique phase identifier.
271   */
272  protected final short id;
273
274  /**
275   * The name of the phase.
276   */
277  protected final String name;
278
279  /**
280   * The Timer that is started and stopped around the execution of this
281   * phase.
282   */
283  protected final Timer timer;
284
285  /**
286   * Create a new Phase. This involves creating a corresponding Timer
287   * instance, allocating a unique identifier, and registering the
288   * Phase.
289   *
290   * @param name The name for the phase.
291   */
292  protected Phase(String name) {
293    this(name, new Timer(name, false, true));
294  }
295
296  /**
297   * Create a new phase. This involves setting the corresponding Timer
298   * instance, allocating a unique identifier, and registering the Phase.
299   *
300   * @param name The name of the phase.
301   * @param timer The timer, or null if this is an untimed phase.
302   */
303  protected Phase(String name, Timer timer) {
304    this.name = name;
305    this.timer = timer;
306    this.id = nextPhaseId++;
307    phases[this.id] = this;
308  }
309
310  /**
311   * @return The unique identifier for this phase.
312   */
313  public final short getId() {
314    return this.id;
315  }
316
317  /**
318   * Display a description of this phase, for debugging purposes.
319   */
320  protected abstract void logPhase();
321
322  /***********************************************************************
323   *
324   * Phase stack
325   */
326
327  /** The maximum stack depth for the phase stack. */
328  private static final int MAX_PHASE_STACK_DEPTH = MAX_PHASES;
329
330  /** Stores the current sub phase for a complex phase. Each entry corresponds to a phase stack entry */
331  private static int[] complexPhaseCursor = new int[MAX_PHASE_STACK_DEPTH];
332
333  /** The phase stack. Stores the current nesting of phases */
334  private static int[] phaseStack = new int[MAX_PHASE_STACK_DEPTH];
335
336  /** The current stack pointer */
337  private static int phaseStackPointer = -1;
338
339  /**
340   * The current even (0 mod 2) scheduled phase.
341   * As we only sync at the end of a phase we need this to ensure that
342   * the primary thread setting the phase does not race with the other
343   * threads reading it.
344   */
345  private static int evenScheduledPhase;
346
347  /**
348   * The current odd (1 mod 2) scheduled phase.
349   * As we only sync at the end of a phase we need this to ensure that
350   * the primary thread setting the phase does not race with the other
351   * threads reading it.
352   */
353  private static int oddScheduledPhase;
354
355  /**
356   * Do we need to add a sync point to reset the mutator count. This
357   * is necessary for consecutive mutator phases and unnecessary
358   * otherwise. Again we separate in even and odd to ensure that there
359   * is no race between the primary thread setting and the helper
360   * threads reading.
361   */
362  private static boolean evenMutatorResetRendezvous;
363
364  /**
365   * Do we need to add a sync point to reset the mutator count. This
366   * is necessary for consecutive mutator phases and unnecessary
367   * otherwise. Again we separate in even and odd to ensure that there
368   * is no race between the primary thread setting and the helper
369   * threads reading.
370   */
371  private static boolean oddMutatorResetRendezvous;
372
373  /**
374   * The complex phase whose timer should be started after the next
375   * rendezvous. We can not start the timer at the point we determine
376   * the next complex phase as we determine the next phase at the
377   * end of the previous phase before the sync point.
378   */
379  private static short startComplexTimer;
380
381  /**
382   * The complex phase whose timer should be stopped after the next
383   * rendezvous. We can not start the timer at the point we determine
384   * the next complex phase as we determine the next phase at the
385   * end of the previous phase before the sync point.
386   */
387  private static short stopComplexTimer;
388
389  /**
390   * Place a phase on the phase stack and begin processing.
391   *
392   * @param scheduledPhase The phase to execute
393   */
394  public static void beginNewPhaseStack(int scheduledPhase) {
395    int order = ((ParallelCollector)VM.activePlan.collector()).rendezvous();
396
397    if (order == 0) {
398      pushScheduledPhase(scheduledPhase);
399    }
400    processPhaseStack(false);
401  }
402
403  /**
404   * Continue the execution of a phase stack. Used for incremental
405   * and concurrent collection.
406   */
407  public static void continuePhaseStack() {
408    processPhaseStack(true);
409  }
410
411  /**
412   * Processes the phase stack. This method is called by multiple threads.
413   *
414   * @param resume whether to resume garbage collection. If set to {@code true},
415   *  GC status will be set to {@link Plan#GC_PROPER} when the first phase
416   *  is processed.
417   */
418  private static void processPhaseStack(boolean resume) {
419    /* Global and Collector instances used in phases */
420    Plan plan = VM.activePlan.global();
421    ParallelCollector collector = (ParallelCollector)VM.activePlan.collector();
422
423    int order = collector.rendezvous();
424    final boolean primary = order == 0;
425
426    boolean log = Options.verbose.getValue() >= 6;
427    boolean logDetails = Options.verbose.getValue() >= 7;
428
429    if (primary && resume) {
430      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Phase.isPhaseStackEmpty());
431      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Plan.gcInProgress());
432      Plan.setGCStatus(Plan.GC_PROPER);
433    }
434
435    /* In order to reduce the need for synchronization, we keep an odd or even
436     * counter for the number of phases processed. As each phase has a single
437     * rendezvous it is only possible to be out by one so the odd or even counter
438     * protects us. */
439    boolean isEvenPhase = true;
440
441    if (primary) {
442      /* Only allow concurrent collection if we are not collecting due to resource exhaustion */
443      allowConcurrentPhase = Plan.isInternalTriggeredCollection() && !Plan.isEmergencyCollection();
444
445      /* First phase will be even, so we say we are odd here so that the next phase set is even*/
446      setNextPhase(false, getNextPhase(), false);
447    }
448
449    /* Make sure everyone sees the first phase */
450    collector.rendezvous();
451
452    /* The main phase execution loop */
453    int scheduledPhase;
454    while ((scheduledPhase = getCurrentPhase(isEvenPhase)) > 0) {
455      short schedule = getSchedule(scheduledPhase);
456      short phaseId = getPhaseId(scheduledPhase);
457      Phase p = getPhase(phaseId);
458
459      /* Start the timer(s) */
460      if (primary) {
461        if (resume) {
462          resumeComplexTimers();
463        }
464        if (p.timer != null) p.timer.start();
465        if (startComplexTimer > 0) {
466          Phase.getPhase(startComplexTimer).timer.start();
467          startComplexTimer = 0;
468        }
469      }
470
471      if (log) {
472        Log.write("Execute ");
473        p.logPhase();
474      }
475
476      /* Execute a single simple scheduled phase */
477      switch (schedule) {
478        /* Global phase */
479        case SCHEDULE_GLOBAL: {
480          if (logDetails) Log.writeln(" as Global...");
481          if (primary) {
482            if (VM.DEBUG) VM.debugging.globalPhase(phaseId,true);
483            plan.collectionPhase(phaseId);
484            if (VM.DEBUG) VM.debugging.globalPhase(phaseId,false);
485          }
486          break;
487        }
488
489        /* Collector phase */
490        case SCHEDULE_COLLECTOR: {
491          if (logDetails) Log.writeln(" as Collector...");
492          if (VM.DEBUG) VM.debugging.collectorPhase(phaseId,order,true);
493          collector.collectionPhase(phaseId, primary);
494          if (VM.DEBUG) VM.debugging.collectorPhase(phaseId,order,false);
495          break;
496        }
497
498        /* Mutator phase */
499        case SCHEDULE_MUTATOR: {
500          if (logDetails) Log.writeln(" as Mutator...");
501          /* Iterate through all mutator contexts */
502          MutatorContext mutator;
503          while ((mutator = VM.activePlan.getNextMutator()) != null) {
504            if (VM.DEBUG) VM.debugging.mutatorPhase(phaseId,mutator.getId(),true);
505            mutator.collectionPhase(phaseId, primary);
506            if (VM.DEBUG) VM.debugging.mutatorPhase(phaseId,mutator.getId(),false);
507          }
508          break;
509        }
510
511        /* Concurrent phase */
512        case SCHEDULE_CONCURRENT: {
513          /* We are yielding to a concurrent collection phase */
514          if (logDetails) Log.writeln(" as Concurrent, yielding...");
515          if (primary) {
516            concurrentPhaseId = phaseId;
517            /* Concurrent phase, we need to stop gc */
518            Plan.setGCStatus(Plan.NOT_IN_GC);
519            Plan.controlCollectorContext.requestConcurrentCollection();
520          }
521          collector.rendezvous();
522          if (primary) {
523            pauseComplexTimers();
524          }
525          return;
526        }
527
528        default: {
529          /* getNextPhase has done the wrong thing */
530          VM.assertions.fail("Invalid schedule in Phase.processPhaseStack");
531          break;
532        }
533      }
534
535      if (primary) {
536        /* Set the next phase by processing the stack */
537        int next = getNextPhase();
538        boolean needsResetRendezvous = (next > 0) && (schedule == SCHEDULE_MUTATOR && getSchedule(next) == SCHEDULE_MUTATOR);
539        setNextPhase(isEvenPhase, next, needsResetRendezvous);
540      }
541
542      /* Sync point after execution of a phase */
543      collector.rendezvous();
544
545      /* Mutator phase reset */
546      if (primary && schedule == SCHEDULE_MUTATOR) {
547        VM.activePlan.resetMutatorIterator();
548      }
549
550      /* At this point, in the case of consecutive phases with mutator
551       * scheduling, we have to double-synchronize to ensure all
552       * collector threads see the reset mutator counter. */
553      if (needsMutatorResetRendezvous(isEvenPhase)) {
554        collector.rendezvous();
555      }
556
557      /* Stop the timer(s) */
558      if (primary) {
559        if (p.timer != null) p.timer.stop();
560        if (stopComplexTimer > 0) {
561          Phase.getPhase(stopComplexTimer).timer.stop();
562          stopComplexTimer = 0;
563        }
564      }
565
566      /* Flip the even / odd phase sense */
567      isEvenPhase = !isEvenPhase;
568      resume = false;
569    }
570  }
571
572  /**
573   * @param isEvenPhase whether an even or odd phase will be returned
574   * @return the next phase
575   */
576  private static int getCurrentPhase(boolean isEvenPhase) {
577    return isEvenPhase ? evenScheduledPhase : oddScheduledPhase;
578  }
579
580  /**
581   * @param isEvenPhase whether the phase is even or odd
582   * @return whether we need a mutator reset rendezvous in this phase
583   */
584  private static boolean needsMutatorResetRendezvous(boolean isEvenPhase) {
585    return isEvenPhase ? evenMutatorResetRendezvous : oddMutatorResetRendezvous;
586  }
587  /**
588   * Sets the next phase. If we are in an even phase the next phase is odd.
589   *
590   * @param isEvenPhase whether the phase is even
591   * @param scheduledPhase the scheduled phase
592   * @param needsResetRendezvous whether it's necessary to rendezvous. This is
593   *  only necessary for consecutive mutator phases.
594   */
595  private static void setNextPhase(boolean isEvenPhase, int scheduledPhase, boolean needsResetRendezvous) {
596    if (isEvenPhase) {
597      oddScheduledPhase = scheduledPhase;
598      evenMutatorResetRendezvous = needsResetRendezvous;
599    } else {
600      evenScheduledPhase = scheduledPhase;
601      oddMutatorResetRendezvous = needsResetRendezvous;
602    }
603  }
604
605  /**
606   * Pull the next scheduled phase off the stack. This may involve
607   * processing several complex phases and skipping placeholders, etc.
608   *
609   * @return The next phase to run, or -1 if no phases are left.
610   */
611  private static int getNextPhase() {
612    while (phaseStackPointer >= 0) {
613      int scheduledPhase = peekScheduledPhase();
614      short schedule = getSchedule(scheduledPhase);
615      short phaseId = getPhaseId(scheduledPhase);
616
617      switch(schedule) {
618        case SCHEDULE_PLACEHOLDER: {
619          /* Placeholders are ignored and we continue looking */
620          popScheduledPhase();
621          continue;
622        }
623
624        case SCHEDULE_GLOBAL:
625        case SCHEDULE_COLLECTOR:
626        case SCHEDULE_MUTATOR: {
627          /* Simple phases are just popped off the stack and executed */
628          popScheduledPhase();
629          return scheduledPhase;
630        }
631
632        case SCHEDULE_CONCURRENT: {
633          /* Concurrent phases are either popped off or we forward to
634           * an associated non-concurrent phase. */
635          if (!allowConcurrentPhase) {
636            popScheduledPhase();
637            ConcurrentPhase cp = (ConcurrentPhase)getPhase(phaseId);
638            int alternateScheduledPhase = cp.getAtomicScheduledPhase();
639            if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(getSchedule(alternateScheduledPhase) != SCHEDULE_CONCURRENT);
640            pushScheduledPhase(alternateScheduledPhase);
641            continue;
642          }
643          if (VM.VERIFY_ASSERTIONS) {
644            /* Concurrent phases can not have a timer */
645            VM.assertions._assert(getPhase(getPhaseId(scheduledPhase)).timer == null);
646          }
647          return scheduledPhase;
648        }
649
650        case SCHEDULE_COMPLEX: {
651          /* A complex phase may either be a newly pushed complex phase,
652           * or a complex phase we are in the process of executing in
653           * which case we move to the next subphase. */
654          ComplexPhase p = (ComplexPhase)getPhase(phaseId);
655          int cursor = incrementComplexPhaseCursor();
656          if (cursor == 0 && p.timer != null) {
657            /* Tell the primary thread to start the timer after the next sync. */
658            startComplexTimer = phaseId;
659          }
660          if (cursor < p.count()) {
661            /* There are more entries, we push the next one and continue */
662            pushScheduledPhase(p.get(cursor));
663            continue;
664          }
665
666          /* We have finished this complex phase */
667          popScheduledPhase();
668          if (p.timer != null) {
669            /* Tell the primary thread to stop the timer after the next sync. */
670            stopComplexTimer = phaseId;
671          }
672          continue;
673        }
674
675        default: {
676          VM.assertions.fail("Invalid phase type encountered");
677        }
678      }
679    }
680    return -1;
681  }
682
683  /**
684   * Pause all of the timers for the complex phases sitting in the stack.
685   */
686  private static void pauseComplexTimers() {
687    for (int i = phaseStackPointer; i >= 0; i--) {
688      Phase p = getPhase(getPhaseId(phaseStack[i]));
689      if (p.timer != null) p.timer.stop();
690    }
691  }
692
693  /**
694   * Resume all of the timers for the complex phases sitting in the stack.
695   */
696  private static void resumeComplexTimers() {
697    for (int i = phaseStackPointer; i >= 0; i--) {
698      Phase p = getPhase(getPhaseId(phaseStack[i]));
699      if (p.timer != null) p.timer.start();
700    }
701  }
702
703  /**
704   * Return true if phase stack is empty, false otherwise.
705   *
706   * @return true if phase stack is empty, false otherwise.
707   */
708  @Inline
709  public static boolean isPhaseStackEmpty() {
710    return phaseStackPointer < 0;
711  }
712
713  /**
714   * Clears the scheduled phase stack.
715   */
716  @Inline
717  public static void resetPhaseStack() {
718    phaseStackPointer = -1;
719  }
720
721  /**
722   * Push a scheduled phase onto the top of the work stack.
723   *
724   * @param scheduledPhase The scheduled phase.
725   */
726  @Inline
727  public static void pushScheduledPhase(int scheduledPhase) {
728    phaseStack[++phaseStackPointer] = scheduledPhase;
729    complexPhaseCursor[phaseStackPointer] = 0;
730  }
731
732  /**
733   * Increment the cursor associated with the current phase
734   * stack entry. This is used to remember the current sub phase
735   * when executing a complex phase.
736   *
737   * @return The old value of the cursor.
738   */
739  @Inline
740  private static int incrementComplexPhaseCursor() {
741    return complexPhaseCursor[phaseStackPointer]++;
742  }
743
744  /**
745   * Pop off the scheduled phase at the top of the work stack.
746   * @return the scheduled phase at the top of the work stack
747   */
748  @Inline
749  private static int popScheduledPhase() {
750    return phaseStack[phaseStackPointer--];
751  }
752
753  /**
754   * Peek the scheduled phase at the top of the work stack.
755   * @return the scheduled phase at the top of the work stack
756   */
757  @Inline
758  private static int peekScheduledPhase() {
759    return phaseStack[phaseStackPointer];
760  }
761
762  /** The concurrent phase being executed */
763  private static short concurrentPhaseId;
764  /** Do we want to allow new concurrent workers to become active */
765  private static boolean allowConcurrentPhase;
766
767  /**
768   * @return the current phase Id.
769   */
770  public static short getConcurrentPhaseId() {
771    return concurrentPhaseId;
772  }
773
774  /**
775   * Clear the current phase Id.
776   */
777  public static void clearConcurrentPhase() {
778    concurrentPhaseId = 0;
779  }
780
781  /**
782   * @return {@code true}if there is an active concurrent phase.
783   */
784  public static boolean concurrentPhaseActive() {
785    return (concurrentPhaseId > 0);
786  }
787
788  /**
789   * Notify that the concurrent phase has completed successfully. This must
790   * only be called by a single thread after it has determined that the
791   * phase has been completed successfully.
792   *
793   * @return {@code true} if more concurrent work needs to be done right now,
794   * {@code false} otherwise
795   */
796  @Unpreemptible
797  public static boolean notifyConcurrentPhaseComplete() {
798    if (Options.verbose.getValue() >= 2) {
799      Log.write("< Concurrent phase ");
800      Log.write(getName(concurrentPhaseId));
801      Log.writeln(" complete >");
802    }
803    /* Concurrent phase is complete*/
804    concurrentPhaseId = 0;
805    /* Remove it from the stack */
806    popScheduledPhase();
807    /* Pop the next phase off the stack */
808    int nextScheduledPhase = getNextPhase();
809
810    if (nextScheduledPhase > 0) {
811      short schedule = getSchedule(nextScheduledPhase);
812
813      /* A concurrent phase, lets wake up and do it all again */
814      if (schedule == SCHEDULE_CONCURRENT) {
815        concurrentPhaseId = getPhaseId(nextScheduledPhase);
816        return true;
817      }
818
819      /* Push phase back on and resume atomic collection */
820      pushScheduledPhase(nextScheduledPhase);
821      Plan.triggerInternalCollectionRequest();
822    }
823    return false;
824  }
825
826  /**
827   * Notify that the concurrent phase has not finished, and must be
828   * re-attempted.
829   */
830  public static void notifyConcurrentPhaseIncomplete() {
831    if (Options.verbose.getValue() >= 2) {
832      Log.write("< Concurrent phase ");
833      Log.write(getName(concurrentPhaseId));
834      Log.writeln(" incomplete >");
835    }
836  }
837}