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