Beispiel #1
0
 // private creator methods for the streams
 @Interruptible
 private ShortStream createRemsetStream() {
   return VM.newGCspyShortStream(
       this,
       "Remembered set stream",
       (short) 0,
       // Say, typical size = 4 * typical scalar size?
       (short) (maxObjectsPerBlock(blockSize) / 8),
       (short) 0,
       (short) 0,
       "Remset references: ",
       " references",
       StreamConstants.PRESENTATION_PLUS,
       StreamConstants.PAINT_STYLE_ZERO,
       0,
       Color.Cyan,
       true);
 }
 /**
  * Constructor
  *
  * @param space The space to which this resource is attached
  */
 private PageResource(Space space, boolean contiguous) {
   this.contiguous = contiguous;
   this.space = space;
   lock = VM.newLock(space.getName() + ".lock");
 }
Beispiel #3
0
/**
 * A garbage collection proceeds as a sequence of phases. Each phase is either simple (singular) or
 * complex (an array).
 *
 * <p>The context an individual phase executes in may be global, mutator, or collector.
 *
 * <p>Phases are executed within a stack and all synchronization between parallel GC threads is
 * managed from within this class.
 *
 * @see CollectorContext#collectionPhase
 * @see MutatorContext#collectionPhase
 * @see Plan#collectionPhase
 */
@Uninterruptible
public abstract class Phase implements Constants {
  /**
   * *********************************************************************
   *
   * <p>Phase allocation and storage.
   */

  /** The maximum number of phases */
  private static final int MAX_PHASES = 64;
  /** The array of phase instances. Zero is unused. */
  private static final Phase[] phases = new Phase[MAX_PHASES];
  /** The id to be allocated for the next phase */
  private static short nextPhaseId = 1;

  /** Run the phase globally. */
  protected static final short SCHEDULE_GLOBAL = 1;
  /** Run the phase on collectors. */
  protected static final short SCHEDULE_COLLECTOR = 2;
  /** Run the phase on mutators. */
  protected static final short SCHEDULE_MUTATOR = 3;
  /** Run this phase concurrently with the mutators */
  protected static final short SCHEDULE_CONCURRENT = 4;
  /** Don't run this phase. */
  protected static final short SCHEDULE_PLACEHOLDER = 100;
  /** This is a complex phase. */
  protected static final short SCHEDULE_COMPLEX = 101;

  /**
   * Retrieve a phase by the unique phase identifier.
   *
   * @param id The phase identifier.
   * @return The Phase instance.
   */
  public static Phase getPhase(short id) {
    if (VM.VERIFY_ASSERTIONS) {
      VM.assertions._assert(id < nextPhaseId, "Phase ID unknown");
      VM.assertions._assert(phases[id] != null, "Uninitialised phase");
    }
    return phases[id];
  }

  /** Get the phase id component of an encoded phase */
  protected static short getPhaseId(int scheduledPhase) {
    short phaseId = (short) (scheduledPhase & 0x0000FFFF);
    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(phaseId > 0);
    return phaseId;
  }

  /**
   * @param phaseId The unique phase identifier.
   * @return The name of the phase.
   */
  public static String getName(short phaseId) {
    return phases[phaseId].name;
  }

  /** Get the ordering component of an encoded phase */
  protected static short getSchedule(int scheduledPhase) {
    short ordering = (short) ((scheduledPhase >> 16) & 0x0000FFFF);
    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(ordering > 0);
    return ordering;
  }

  /** Get the ordering component of an encoded phase */
  protected static String getScheduleName(short ordering) {
    switch (ordering) {
      case SCHEDULE_GLOBAL:
        return "Global";
      case SCHEDULE_COLLECTOR:
        return "Collector";
      case SCHEDULE_MUTATOR:
        return "Mutator";
      case SCHEDULE_CONCURRENT:
        return "Concurrent";
      case SCHEDULE_PLACEHOLDER:
        return "Placeholder";
      case SCHEDULE_COMPLEX:
        return "Complex";
      default:
        return "UNKNOWN!";
    }
  }

  /**
   * Construct a phase.
   *
   * @param name Display name of the phase
   */
  @Interruptible
  public static short createSimple(String name) {
    return new SimplePhase(name).getId();
  }

  /**
   * Construct a phase, re-using a specified timer.
   *
   * @param name Display name of the phase
   */
  @Interruptible
  public static short createSimple(String name, Timer timer) {
    return new SimplePhase(name, timer).getId();
  }

  /**
   * Construct a complex phase.
   *
   * @param name Display name of the phase
   * @param scheduledPhases The phases in this complex phase.
   */
  @Interruptible
  public static short createComplex(String name, int... scheduledPhases) {
    return new ComplexPhase(name, scheduledPhases).getId();
  }

  /**
   * Construct a complex phase, re-using a specified timer.
   *
   * @param name Display name of the phase
   * @param timer Timer for this phase to contribute to
   * @param scheduledPhases The phases in this complex phase.
   */
  @Interruptible
  public static short createComplex(String name, Timer timer, int... scheduledPhases) {
    return new ComplexPhase(name, timer, scheduledPhases).getId();
  }

  /**
   * Construct a phase.
   *
   * @param name Display name of the phase
   * @param atomicScheduledPhase The corresponding atomic phase to run in a stop the world
   *     collection
   */
  @Interruptible
  public static final short createConcurrent(String name, int atomicScheduledPhase) {
    return new ConcurrentPhase(name, atomicScheduledPhase).getId();
  }

  /**
   * Construct a phase, re-using a specified timer.
   *
   * @param name Display name of the phase
   * @param timer Timer for this phase to contribute to
   * @param atomicScheduledPhase The corresponding atomic phase to run in a stop the world
   *     collection
   */
  @Interruptible
  public static final short createConcurrent(String name, Timer timer, int atomicScheduledPhase) {
    return new ConcurrentPhase(name, timer, atomicScheduledPhase).getId();
  }

  /**
   * Take the passed phase and return an encoded phase to run that phase as a complex phase.
   *
   * @param phaseId The phase to run as complex
   * @return The encoded phase value.
   */
  public static int scheduleComplex(short phaseId) {
    if (VM.VERIFY_ASSERTIONS)
      VM.assertions._assert(Phase.getPhase(phaseId) instanceof ComplexPhase);
    return (SCHEDULE_COMPLEX << 16) + phaseId;
  }

  /**
   * Take the passed phase and return an encoded phase to run that phase as a concurrent phase.
   *
   * @param phaseId The phase to run as concurrent
   * @return The encoded phase value.
   */
  public static int scheduleConcurrent(short phaseId) {
    if (VM.VERIFY_ASSERTIONS)
      VM.assertions._assert(Phase.getPhase(phaseId) instanceof ConcurrentPhase);
    return (SCHEDULE_CONCURRENT << 16) + phaseId;
  }

  /**
   * Take the passed phase and return an encoded phase to run that phase in a global context;
   *
   * @param phaseId The phase to run globally
   * @return The encoded phase value.
   */
  public static int scheduleGlobal(short phaseId) {
    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase);
    return (SCHEDULE_GLOBAL << 16) + phaseId;
  }

  /**
   * Take the passed phase and return an encoded phase to run that phase in a collector context;
   *
   * @param phaseId The phase to run on collectors
   * @return The encoded phase value.
   */
  public static int scheduleCollector(short phaseId) {
    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase);
    return (SCHEDULE_COLLECTOR << 16) + phaseId;
  }

  /**
   * Take the passed phase and return an encoded phase to run that phase in a mutator context;
   *
   * @param phaseId The phase to run on mutators
   * @return The encoded phase value.
   */
  public static int scheduleMutator(short phaseId) {
    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase);
    return (SCHEDULE_MUTATOR << 16) + phaseId;
  }

  /**
   * Take the passed phase and return an encoded phase to run that phase in a mutator context;
   *
   * @param phaseId The phase to run on mutators
   * @return The encoded phase value.
   */
  public static int schedulePlaceholder(short phaseId) {
    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Phase.getPhase(phaseId) instanceof SimplePhase);
    return (SCHEDULE_PLACEHOLDER << 16) + phaseId;
  }

  /**
   * *********************************************************************
   *
   * <p>Phase instance fields/methods.
   */

  /** The unique phase identifier. */
  protected final short id;

  /** The name of the phase. */
  protected final String name;

  /** The Timer that is started and stopped around the execution of this phase. */
  protected final Timer timer;

  /**
   * Create a new Phase. This involves creating a corresponding Timer instance, allocating a unique
   * identifier, and registering the Phase.
   *
   * @param name The name for the phase.
   */
  protected Phase(String name) {
    this(name, new Timer(name, false, true));
  }

  /**
   * Create a new phase. This involves setting the corresponding Timer instance, allocating a unique
   * identifier, and registering the Phase.
   *
   * @param name The name of the phase.
   * @param timer The timer, or null if this is an untimed phase.
   */
  protected Phase(String name, Timer timer) {
    this.name = name;
    this.timer = timer;
    this.id = nextPhaseId++;
    phases[this.id] = this;
  }

  /** @return The unique identifier for this phase. */
  public final short getId() {
    return this.id;
  }

  /** Display a phase for debugging purposes. */
  protected abstract void logPhase();

  /**
   * *********************************************************************
   *
   * <p>Phase stack
   */

  /** The maximum stack depth for the phase stack. */
  private static final int MAX_PHASE_STACK_DEPTH = MAX_PHASES;

  /**
   * Stores the current sub phase for a complex phase. Each entry corresponds to a phase stack entry
   */
  private static int[] complexPhaseCursor = new int[MAX_PHASE_STACK_DEPTH];

  /** The phase stack. Stores the current nesting of phases */
  private static int[] phaseStack = new int[MAX_PHASE_STACK_DEPTH];

  /** The current stack pointer */
  private static int phaseStackPointer = -1;

  /**
   * The current even (0 mod 2) scheduled phase. As we only sync at the end of a phase we need this
   * to ensure that the primary thread setting the phase does not race with the other threads
   * reading it.
   */
  private static int evenScheduledPhase;

  /**
   * The current odd (1 mod 2) scheduled phase. As we only sync at the end of a phase we need this
   * to ensure that the primary thread setting the phase does not race with the other threads
   * reading it.
   */
  private static int oddScheduledPhase;

  /**
   * Do we need to add a sync point to reset the mutator count. This is necessary for consecutive
   * mutator phases and unneccessary otherwise. Again we separate in even and odd to ensure that
   * there is no race between the primary thread setting and the helper threads reading.
   */
  private static boolean evenMutatorResetRendezvous;

  /**
   * Do we need to add a sync point to reset the mutator count. This is necessary for consecutive
   * mutator phases and unneccessary otherwise. Again we separate in even and odd to ensure that
   * there is no race between the primary thread setting and the helper threads reading.
   */
  private static boolean oddMutatorResetRendezvous;

  /**
   * The complex phase whose timer should be started after the next rendezvous. We can not start the
   * timer at the point we determine the next complex phase as we determine the next phase at the
   * end of the previous phase before the sync point.
   */
  private static short startComplexTimer;

  /**
   * The complex phase whose timer should be stopped after the next rendezvous. We can not start the
   * timer at the point we determine the next complex phase as we determine the next phase at the
   * end of the previous phase before the sync point.
   */
  private static short stopComplexTimer;

  /**
   * Place a phase on the phase stack and begin processing.
   *
   * @param scheduledPhase The phase to execute
   * @return True if the phase stack is exhausted.
   */
  public static boolean beginNewPhaseStack(int scheduledPhase) {
    int order = VM.collection.rendezvous(1001);

    if (order == 1) {
      pushScheduledPhase(scheduledPhase);
    }
    return processPhaseStack(false);
  }

  /**
   * Continue the execution of a phase stack. Used for incremental and concurrent collection.
   *
   * @return True if the phase stack is exhausted.
   */
  public static boolean continuePhaseStack() {
    if (concurrentPhaseActive() && Plan.collectionTrigger != Collection.INTERNAL_PHASE_GC_TRIGGER) {
      resetConcurrentWorkers();
    }

    return processPhaseStack(true);
  }

  /** Process the phase stack. This method is called by multiple threads. */
  private static boolean processPhaseStack(boolean resume) {
    int order = VM.collection.rendezvous(1001);
    final boolean primary = order == 1;

    boolean log = Options.verbose.getValue() >= 6;
    boolean logDetails = Options.verbose.getValue() >= 7;

    if (primary && resume) {
      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Phase.isPhaseStackEmpty());
      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Plan.gcInProgress());
      Plan.setGCStatus(Plan.GC_PROPER);
    }

    /* In order to reduce the need for synchronization, we keep an odd or even
     * counter for the number of phases processed. As each phase has a single
     * rendezvous it is only possible to be out by one so the odd or even counter
     * protects us. */
    boolean isEvenPhase = true;

    if (primary) {
      /* First phase will be even, so we say we are odd here so that the next phase set is even*/
      setNextPhase(false, getNextPhase(), false);
    }

    /* Make sure everyone sees the first phase */
    VM.collection.rendezvous(1002);

    /* Global and Collector instances used in phases */
    Plan plan = VM.activePlan.global();
    CollectorContext collector = VM.activePlan.collector();

    /* The main phase execution loop */
    int scheduledPhase;
    while ((scheduledPhase = getCurrentPhase(isEvenPhase)) > 0) {
      short schedule = getSchedule(scheduledPhase);
      short phaseId = getPhaseId(scheduledPhase);
      Phase p = getPhase(phaseId);

      /* Start the timer(s) */
      if (primary) {
        if (resume) {
          resumeComplexTimers();
        }
        if (p.timer != null) p.timer.start();
        if (startComplexTimer > 0) {
          Phase.getPhase(startComplexTimer).timer.start();
          startComplexTimer = 0;
        }
      }

      if (log) {
        Log.write("Execute ");
        p.logPhase();
      }

      /* Execute a single simple scheduled phase */
      switch (schedule) {
          /* Global phase */
        case SCHEDULE_GLOBAL:
          {
            if (logDetails) Log.writeln(" as Global...");
            if (primary) plan.collectionPhase(phaseId);
            break;
          }

          /* Collector phase */
        case SCHEDULE_COLLECTOR:
          {
            if (logDetails) Log.writeln(" as Collector...");
            collector.collectionPhase(phaseId, primary);
            break;
          }

          /* Mutator phase */
        case SCHEDULE_MUTATOR:
          {
            if (logDetails) Log.writeln(" as Mutator...");
            /* Iterate through all mutator contexts */
            MutatorContext mutator;
            while ((mutator = VM.activePlan.getNextMutator()) != null) {
              mutator.collectionPhase(phaseId, primary);
            }
            break;
          }

          /* Concurrent phase */
        case SCHEDULE_CONCURRENT:
          {
            /* We are yielding to a concurrent collection phase */
            if (logDetails) Log.writeln(" as Concurrent, yielding...");
            if (primary) {
              concurrentPhaseId = phaseId;
              scheduleConcurrentWorkers();
              /* Concurrent phase, we need to stop gc */
              Plan.setGCStatus(Plan.NOT_IN_GC);
            }
            VM.collection.rendezvous(1003);
            if (primary) {
              pauseComplexTimers();
            }
            return false;
          }

        default:
          {
            /* getNextPhase has done the wrong thing */
            VM.assertions.fail("Invalid schedule in Phase.processPhaseStack");
            break;
          }
      }

      if (primary) {
        /* Set the next phase by processing the stack */
        int next = getNextPhase();
        boolean needsResetRendezvous =
            (next > 0) && (schedule == SCHEDULE_MUTATOR && getSchedule(next) == SCHEDULE_MUTATOR);
        setNextPhase(isEvenPhase, next, needsResetRendezvous);
      }

      /* Sync point after execution of a phase */
      VM.collection.rendezvous(1004);

      /* Mutator phase reset */
      if (primary && schedule == SCHEDULE_MUTATOR) {
        VM.activePlan.resetMutatorIterator();
      }

      /* At this point, in the case of consecutive phases with mutator
       * scheduling, we have to double-synchronize to ensure all
       * collector threads see the reset mutator counter. */
      if (needsMutatorResetRendezvous(isEvenPhase)) {
        VM.collection.rendezvous(1005);
      }

      /* Stop the timer(s) */
      if (primary) {
        if (p.timer != null) p.timer.stop();
        if (stopComplexTimer > 0) {
          Phase.getPhase(stopComplexTimer).timer.stop();
          stopComplexTimer = 0;
        }
      }

      /* Flip the even / odd phase sense */
      isEvenPhase = !isEvenPhase;
      resume = false;
    }

    /* Phase stack exhausted so we return true */
    return true;
  }

  /** Get the next phase. */
  private static int getCurrentPhase(boolean isEvenPhase) {
    return isEvenPhase ? evenScheduledPhase : oddScheduledPhase;
  }

  /** Do we need a mutator reset rendezvous in this phase? */
  private static boolean needsMutatorResetRendezvous(boolean isEvenPhase) {
    return isEvenPhase ? evenMutatorResetRendezvous : oddMutatorResetRendezvous;
  }
  /** Set the next phase. If we are in an even phase the next phase is odd. */
  private static void setNextPhase(
      boolean isEvenPhase, int scheduledPhase, boolean needsResetRendezvous) {
    if (isEvenPhase) {
      oddScheduledPhase = scheduledPhase;
      evenMutatorResetRendezvous = needsResetRendezvous;
    } else {
      evenScheduledPhase = scheduledPhase;
      oddMutatorResetRendezvous = needsResetRendezvous;
    }
  }

  /**
   * Pull the next scheduled phase off the stack. This may involve processing several complex phases
   * and skipping placeholders, etc.
   *
   * @return The next phase to run, or -1 if no phases are left.
   */
  private static int getNextPhase() {
    boolean allowConcurrentPhase = Plan.collectionTrigger == Collection.INTERNAL_PHASE_GC_TRIGGER;

    while (phaseStackPointer >= 0) {
      int scheduledPhase = peekScheduledPhase();
      short schedule = getSchedule(scheduledPhase);
      short phaseId = getPhaseId(scheduledPhase);

      switch (schedule) {
        case SCHEDULE_PLACEHOLDER:
          {
            /* Placeholders are ignored and we continue looking */
            popScheduledPhase();
            continue;
          }

        case SCHEDULE_GLOBAL:
        case SCHEDULE_COLLECTOR:
        case SCHEDULE_MUTATOR:
          {
            /* Simple phases are just popped off the stack and executed */
            popScheduledPhase();
            return scheduledPhase;
          }

        case SCHEDULE_CONCURRENT:
          {
            /* Concurrent phases are either popped off or we forward to
             * an associated non-concurrent phase. */
            if (!allowConcurrentPhase) {
              popScheduledPhase();
              ConcurrentPhase cp = (ConcurrentPhase) getPhase(phaseId);
              int alternateScheduledPhase = cp.getAtomicScheduledPhase();
              if (VM.VERIFY_ASSERTIONS)
                VM.assertions._assert(getSchedule(alternateScheduledPhase) != SCHEDULE_CONCURRENT);
              pushScheduledPhase(alternateScheduledPhase);
              continue;
            }
            if (VM.VERIFY_ASSERTIONS) {
              /* Concurrent phases can not have a timer */
              VM.assertions._assert(getPhase(getPhaseId(scheduledPhase)).timer == null);
            }
            return scheduledPhase;
          }

        case SCHEDULE_COMPLEX:
          {
            /* A complex phase may either be a newly pushed complex phase,
             * or a complex phase we are in the process of executing in
             * which case we move to the next subphase. */
            ComplexPhase p = (ComplexPhase) getPhase(phaseId);
            int cursor = incrementComplexPhaseCursor();
            if (cursor == 0 && p.timer != null) {
              /* Tell the primary thread to start the timer after the next sync. */
              startComplexTimer = phaseId;
            }
            if (cursor < p.count()) {
              /* There are more entries, we push the next one and continue */
              pushScheduledPhase(p.get(cursor));
              continue;
            }

            /* We have finished this complex phase */
            popScheduledPhase();
            if (p.timer != null) {
              /* Tell the primary thread to stop the timer after the next sync. */
              stopComplexTimer = phaseId;
            }
            continue;
          }

        default:
          {
            VM.assertions.fail("Invalid phase type encountered");
          }
      }
    }
    return -1;
  }

  /** Pause all of the timers for the complex phases sitting in the stack. */
  private static void pauseComplexTimers() {
    for (int i = phaseStackPointer; i >= 0; i--) {
      Phase p = getPhase(getPhaseId(phaseStack[i]));
      if (p.timer != null) p.timer.stop();
    }
  }

  /** Resume all of the timers for the complex phases sitting in the stack. */
  private static void resumeComplexTimers() {
    for (int i = phaseStackPointer; i >= 0; i--) {
      Phase p = getPhase(getPhaseId(phaseStack[i]));
      if (p.timer != null) p.timer.start();
    }
  }

  /**
   * Return true if phase stack is empty, false otherwise.
   *
   * @return true if phase stack is empty, false otherwise.
   */
  @Inline
  public static boolean isPhaseStackEmpty() {
    return phaseStackPointer < 0;
  }

  /** Clears the scheduled phase stack. */
  @Inline
  public static void resetPhaseStack() {
    phaseStackPointer = -1;
  }

  /**
   * Push a scheduled phase onto the top of the work stack.
   *
   * @param scheduledPhase The scheduled phase.
   */
  @Inline
  public static void pushScheduledPhase(int scheduledPhase) {
    phaseStack[++phaseStackPointer] = scheduledPhase;
    complexPhaseCursor[phaseStackPointer] = 0;
  }

  /**
   * Increment the cursor associated with the current phase stack entry. This is used to remember
   * the current sub phase when executing a complex phase.
   *
   * @return The old value of the cursor.
   */
  @Inline
  private static int incrementComplexPhaseCursor() {
    return complexPhaseCursor[phaseStackPointer]++;
  }

  /** Pop off the scheduled phase at the top of the work stack. */
  @Inline
  private static int popScheduledPhase() {
    return phaseStack[phaseStackPointer--];
  }

  /** Peek the scheduled phase at the top of the work stack. */
  @Inline
  private static int peekScheduledPhase() {
    return phaseStack[phaseStackPointer];
  }

  /** The concurrent phase being executed */
  private static short concurrentPhaseId;
  /** An atomic counter used to determine the threads performing gc work. */
  private static Lock concurrentWorkersLock = VM.newLock("Active Concurrent Workers");
  /** The number of concurrent workers currently active */
  private static int concurrentWorkersActive;
  /** Do we want to allow new concurrent workers to become active */
  private static boolean allowConcurrentWorkersActive;

  /** Get the current phase Id. */
  public static short getConcurrentPhaseId() {
    return concurrentPhaseId;
  }

  /** @return True if there is an active concurrent phase. */
  public static boolean concurrentPhaseActive() {
    return (concurrentPhaseId > 0);
  }

  /** Attempt to begin execution of a concurrent collection phase. */
  public static boolean startConcurrentPhase() {
    boolean result = false;
    concurrentWorkersLock.acquire();
    if (concurrentPhaseActive()) {
      if (allowConcurrentWorkersActive) {
        concurrentWorkersActive++;
        result = true;
      }
      VM.activePlan.collector().clearResetConcurrentWork();
    }
    if (Options.verbose.getValue() >= 2) {
      if (result) {
        Log.write("< Concurrent worker ");
        Log.write(concurrentWorkersActive - 1);
        Log.write(" started phase ");
        Log.write(getName(concurrentPhaseId));
        Log.writeln(" >");
      } else {
        Log.writeln("< worker failed in attempt to start phase >");
      }
    }
    concurrentWorkersLock.release();
    return result;
  }

  /**
   * Reset the workers that believe they are in the middle of a concurrent phase but have been
   * pre-empted by a collection.
   */
  public static void resetConcurrentWorkers() {
    for (int i = 0; i < VM.activePlan.collectorCount(); i++) {
      VM.activePlan.collector(i).resetConcurrentWork();
    }
    concurrentWorkersActive = 0;
    concurrentPhaseId = 0;
    allowConcurrentWorkersActive = false;
  }

  /**
   * Notify that the current thread believes that a concurrent collection phase is complete.
   *
   * @return True if this was the last thread.
   */
  public static boolean completeConcurrentPhase() {
    boolean result = false;
    concurrentWorkersLock.acquire();
    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(allowConcurrentWorkersActive);
    concurrentWorkersActive--;
    if (concurrentWorkersActive == 0) {
      allowConcurrentWorkersActive = false;
      result = true;
    }
    if (Options.verbose.getValue() >= 3) {
      Log.write("< Concurrent worker ");
      Log.write(concurrentWorkersActive);
      Log.write(" completed phase ");
      Log.write(getName(concurrentPhaseId));
      Log.writeln(" >");
    }
    concurrentWorkersLock.release();
    return result;
  }

  /**
   * Notify that the concurrent phase has completed successfully. This must only be called by a
   * single thread after it has determined that the phase has been completed successfully.
   */
  public static void notifyConcurrentPhaseComplete() {
    if (Options.verbose.getValue() >= 2) {
      Log.write("< Concurrent phase ");
      Log.write(getName(concurrentPhaseId));
      Log.writeln(" complete >");
    }
    /* Concurrent phase is complete*/
    concurrentPhaseId = 0;
    /* Remove it from the stack */
    popScheduledPhase();
    /* Pop the next phase off the stack */
    int nextScheduledPhase = getNextPhase();

    if (nextScheduledPhase > 0) {
      short schedule = getSchedule(nextScheduledPhase);

      /* A concurrent phase, lets wake up and do it all again */
      if (schedule == SCHEDULE_CONCURRENT) {
        concurrentPhaseId = getPhaseId(nextScheduledPhase);
        scheduleConcurrentWorkers();
        return;
      }

      /* Push phase back on and resume atomic collection */
      pushScheduledPhase(nextScheduledPhase);
      VM.collection.triggerAsyncCollection(Collection.INTERNAL_PHASE_GC_TRIGGER);
    }
  }

  /** Notify that the concurrent phase has not finished, and must be re-attempted. */
  public static void notifyConcurrentPhaseIncomplete() {
    if (Options.verbose.getValue() >= 2) {
      Log.write("< Concurrent phase ");
      Log.write(getName(concurrentPhaseId));
      Log.writeln(" incomplete >");
    }
    scheduleConcurrentWorkers();
  }

  /**
   * Schedule the concurrent collector threads. If this is called from within a collection interval
   * the threads must not be started until after the interval is complete.
   */
  private static void scheduleConcurrentWorkers() {
    concurrentWorkersLock.acquire();
    if (!allowConcurrentWorkersActive) {
      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(concurrentWorkersActive == 0);
      allowConcurrentWorkersActive = true;
    }
    concurrentWorkersLock.release();
    VM.collection.scheduleConcurrentWorkers();
  }
}
 /**
  * **************************************************************************
  *
  * <p>Initialization
  */
 static {
   classLock = VM.newLock("PageResource");
   Options.protectOnRelease = new ProtectOnRelease();
 }