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 static org.mmtk.utility.Constants.*;
016import static org.mmtk.vm.VM.EXIT_CODE_REFLECTION_FAILURE;
017
018import org.mmtk.policy.MarkSweepSpace;
019import org.mmtk.policy.Space;
020import org.mmtk.policy.ImmortalSpace;
021import org.mmtk.policy.RawPageSpace;
022import org.mmtk.policy.LargeObjectSpace;
023import org.mmtk.utility.alloc.LinearScan;
024import org.mmtk.utility.Conversions;
025import org.mmtk.utility.HeaderByte;
026import org.mmtk.utility.heap.HeapGrowthManager;
027import org.mmtk.utility.heap.Map;
028import org.mmtk.utility.heap.VMRequest;
029import org.mmtk.utility.Log;
030import org.mmtk.utility.options.*;
031import org.mmtk.utility.sanitychecker.SanityChecker;
032import org.mmtk.utility.statistics.Timer;
033import org.mmtk.utility.statistics.Stats;
034import org.mmtk.vm.VM;
035import org.vmmagic.pragma.*;
036import org.vmmagic.unboxed.*;
037
038/**
039 * This abstract class implements the global core functionality for all
040 * memory management schemes.  All global MMTk plans should inherit from
041 * this class.<p>
042 *
043 * All plans make a clear distinction between <i>global</i> and
044 * <i>thread-local</i> activities, and divides global and local state
045 * into separate class hierarchies.  Global activities must be
046 * synchronized, whereas no synchronization is required for
047 * thread-local activities.  There is a single instance of Plan (or the
048 * appropriate sub-class), and a 1:1 mapping of PlanLocal to "kernel
049 * threads" (aka CPUs).  Thus instance
050 * methods of PlanLocal allow fast, unsynchronized access to functions such as
051 * allocation and collection.
052 *
053 * The global instance defines and manages static resources
054 * (such as memory and virtual memory resources).  This mapping of threads to
055 * instances is crucial to understanding the correctness and
056 * performance properties of MMTk plans.
057 */
058@Uninterruptible
059public abstract class Plan {
060  /****************************************************************************
061   * Constants
062   */
063
064  /**
065   *
066   */
067
068  /* GC State */
069  public static final int NOT_IN_GC = 0; // this must be zero for C code
070  public static final int GC_PREPARE = 1; // before setup and obtaining root
071  public static final int GC_PROPER = 2;
072
073  /* Space Size Constants. */
074  public static final boolean USE_CODE_SPACE = true;
075
076  /* Allocator Constants */
077  public static final int ALLOC_DEFAULT = 0;
078  public static final int ALLOC_NON_REFERENCE = 1;
079  public static final int ALLOC_NON_MOVING = 2;
080  public static final int ALLOC_IMMORTAL = 3;
081  public static final int ALLOC_LOS = 4;
082  public static final int ALLOC_PRIMITIVE_LOS = 5;
083  public static final int ALLOC_GCSPY = 6;
084  public static final int ALLOC_CODE = 7;
085  public static final int ALLOC_LARGE_CODE = 8;
086  public static final int ALLOC_HOT_CODE = USE_CODE_SPACE ? ALLOC_CODE : ALLOC_DEFAULT;
087  public static final int ALLOC_COLD_CODE = USE_CODE_SPACE ? ALLOC_CODE : ALLOC_DEFAULT;
088  public static final int ALLOC_STACK = ALLOC_LOS;
089  public static final int ALLOCATORS = 9;
090  public static final int DEFAULT_SITE = -1;
091
092  /* Miscellaneous Constants */
093//  public static final int LOS_SIZE_THRESHOLD = SegregatedFreeListSpace.MAX_CELL_SIZE;
094  public static final int NON_PARTICIPANT = 0;
095  public static final boolean GATHER_WRITE_BARRIER_STATS = false;
096  public static final int DEFAULT_MIN_NURSERY =  (2 << 20) >> LOG_BYTES_IN_PAGE;
097  public static final int DEFAULT_MAX_NURSERY = (32 << 20) >> LOG_BYTES_IN_PAGE;
098  public static final boolean SCAN_BOOT_IMAGE = true;  // scan it for roots rather than trace it
099 // public static final boolean REQUIRES_LOS = VM.activePlan.constraints().requiresLOS();
100  public static final int MAX_NON_LOS_DEFAULT_ALLOC_BYTES = VM.activePlan.constraints().maxNonLOSDefaultAllocBytes();
101  public static final int MAX_NON_LOS_NONMOVING_ALLOC_BYTES = VM.activePlan.constraints().maxNonLOSNonMovingAllocBytes();
102  public static final int MAX_NON_LOS_COPY_BYTES = VM.activePlan.constraints().maxNonLOSCopyBytes();
103
104  /* Do we support a log bit in the object header?  Some write barriers may use it */
105  public static final boolean NEEDS_LOG_BIT_IN_HEADER = VM.activePlan.constraints().needsLogBitInHeader();
106
107  /****************************************************************************
108   * Class variables
109   */
110
111  /** The space that holds any VM specific objects (e.g. a boot image) */
112  public static final Space vmSpace = VM.memory.getVMSpace();
113
114  /** Any immortal objects allocated after booting are allocated here. */
115  public static final ImmortalSpace immortalSpace = new ImmortalSpace("immortal", VMRequest.discontiguous());
116
117  /** All meta data that is used by MMTk is allocated (and accounted for) in the meta data space. */
118  public static final RawPageSpace metaDataSpace = new RawPageSpace("meta", VMRequest.discontiguous());
119
120  /** Large objects are allocated into a special large object space. */
121  public static final LargeObjectSpace loSpace = new LargeObjectSpace("los", VMRequest.discontiguous());
122
123  /** Space used by the sanity checker (used at runtime only if sanity checking enabled */
124  public static final RawPageSpace sanitySpace = new RawPageSpace("sanity", VMRequest.discontiguous());
125
126  /** Space used to allocate objects that cannot be moved. we do not need a large space as the LOS is non-moving. */
127  public static final MarkSweepSpace nonMovingSpace = new MarkSweepSpace("non-moving", VMRequest.discontiguous());
128
129  public static final MarkSweepSpace smallCodeSpace = USE_CODE_SPACE ? new MarkSweepSpace("sm-code", VMRequest.discontiguous()) : null;
130  public static final LargeObjectSpace largeCodeSpace = USE_CODE_SPACE ? new LargeObjectSpace("lg-code", VMRequest.discontiguous()) : null;
131
132  public static int pretenureThreshold = Integer.MAX_VALUE;
133
134  /* Space descriptors */
135  public static final int IMMORTAL = immortalSpace.getDescriptor();
136  public static final int VM_SPACE = vmSpace.getDescriptor();
137  public static final int META = metaDataSpace.getDescriptor();
138  public static final int LOS = loSpace.getDescriptor();
139  public static final int SANITY = sanitySpace.getDescriptor();
140  public static final int NON_MOVING = nonMovingSpace.getDescriptor();
141  public static final int SMALL_CODE = USE_CODE_SPACE ? smallCodeSpace.getDescriptor() : 0;
142  public static final int LARGE_CODE = USE_CODE_SPACE ? largeCodeSpace.getDescriptor() : 0;
143
144  /** Timer that counts total time */
145  public static final Timer totalTime = new Timer("time");
146
147  /** Support for allocation-site identification */
148  protected static int allocationSiteCount = 0;
149
150  /** Global sanity checking state **/
151  public static final SanityChecker sanityChecker = new SanityChecker();
152
153  /** Default collector context */
154  protected final Class<? extends ParallelCollector> defaultCollectorContext;
155
156  /****************************************************************************
157   * Constructor.
158   */
159  public Plan() {
160    /* Create base option instances */
161    Options.verbose = new Verbose();
162    Options.verboseTiming = new VerboseTiming();
163    Options.stressFactor = new StressFactor();
164    Options.noFinalizer = new NoFinalizer();
165    Options.noReferenceTypes = new NoReferenceTypes();
166    Options.fullHeapSystemGC = new FullHeapSystemGC();
167    Options.harnessAll = new HarnessAll();
168    Options.ignoreSystemGC = new IgnoreSystemGC();
169    Options.metaDataLimit = new MetaDataLimit();
170    Options.nurserySize = new NurserySize();
171    Options.nurseryZeroing = new NurseryZeroing();
172    Options.pretenureThresholdFraction = new PretenureThresholdFraction();
173    Options.variableSizeHeap = new VariableSizeHeap();
174    Options.eagerMmapSpaces = new EagerMmapSpaces();
175    Options.sanityCheck = new SanityCheck();
176    Options.debugAddress = new DebugAddress();
177    Options.perfEvents = new PerfEvents();
178    Options.useReturnBarrier = new UseReturnBarrier();
179    Options.useShortStackScans = new UseShortStackScans();
180    Options.threads = new Threads();
181    Options.cycleTriggerThreshold = new CycleTriggerThreshold();
182    Map.finalizeStaticSpaceMap();
183    registerSpecializedMethods();
184
185    // Determine the default collector context.
186    Class<? extends Plan> mmtkPlanClass = this.getClass().asSubclass(Plan.class);
187    while (!mmtkPlanClass.getName().startsWith("org.mmtk.plan")) {
188      mmtkPlanClass = mmtkPlanClass.getSuperclass().asSubclass(Plan.class);
189    }
190    String contextClassName = mmtkPlanClass.getName() + "Collector";
191    Class<? extends ParallelCollector> mmtkCollectorClass = null;
192    try {
193      mmtkCollectorClass = Class.forName(contextClassName).asSubclass(ParallelCollector.class);
194    } catch (Throwable t) {
195      t.printStackTrace();
196      System.exit(EXIT_CODE_REFLECTION_FAILURE);
197    }
198    defaultCollectorContext = mmtkCollectorClass;
199  }
200
201  /****************************************************************************
202   * The complete boot Sequence is:
203   *
204   *  1. enableAllocation: allow allocation (but not collection).
205   *  2. processOptions  : the VM has parsed/prepared options for MMTk to react to.
206   *  3. enableCollection: the VM can support the spawning of MMTk collector contexts.
207   *  4. fullyBooted     : control is just about to be given to application code.
208   */
209
210  /**
211   * The enableAllocation method is called early in the boot process to allow
212   * allocation.
213   */
214  @Interruptible
215  public void enableAllocation() {
216  }
217
218  /**
219   * The processOptions method is called by the runtime immediately after
220   * command-line arguments are available. Allocation must be supported
221   * prior to this point because the runtime infrastructure may require
222   * allocation in order to parse the command line arguments.  For this
223   * reason all plans should operate gracefully on the default minimum
224   * heap size until the point that processOptions is called.
225   */
226  @Interruptible
227  public void processOptions() {
228    VM.statistics.perfEventInit(Options.perfEvents.getValue());
229    if (Options.verbose.getValue() > 2) Space.printVMMap();
230    if (Options.verbose.getValue() > 3) VM.config.printConfig();
231    if (Options.verbose.getValue() > 0) Stats.startAll();
232    if (Options.eagerMmapSpaces.getValue()) Space.eagerlyMmapMMTkSpaces();
233    pretenureThreshold = (int) ((Options.nurserySize.getMaxNursery() << LOG_BYTES_IN_PAGE) * Options.pretenureThresholdFraction.getValue());
234  }
235
236  /**
237   * The enableCollection method is called by the runtime after it is
238   * safe to spawn collector contexts and allow garbage collection.
239   */
240  @Interruptible
241  public void enableCollection() {
242    int actualThreadCount = determineThreadCount();
243
244    if (VM.VERIFY_ASSERTIONS) {
245      VM.assertions._assert(actualThreadCount == VM.activePlan.collectorCount(),
246          "Actual thread count does not match collector count from active plan.");
247    }
248
249    preCollectorSpawn();
250
251    spawnCollectorThreads(actualThreadCount);
252  }
253
254  /**
255   * Determines the number of threads that will be used for collection.<p>
256   *
257   * Collectors that need fine-grained control over the number of spawned collector
258   * threads may override this method. Subclasses must ensure that the return value
259   * of this method is consistent with the number of collector threads in
260   * the active plan.
261   *
262   * @return number of threads to be used for collection
263   * @see PlanConstraints#maxNumGCThreads() setting only the maximum number
264   *  of collectors
265   */
266  @Interruptible("Options methods and Math.min are interruptible")
267  protected int determineThreadCount() {
268    int defaultThreadCount = VM.collection.getDefaultThreads();
269    int maxThreadCount = VM.activePlan.constraints().maxNumGCThreads();
270    int safeDefaultValue = Math.min(defaultThreadCount, maxThreadCount);
271
272    // Make sure that if we have not explicitly set threads, then we use the right default.
273    if (Options.verbose.getValue() > 0) {
274        Log.write("Setting default thread count for MMTk to minimum of ");
275        Log.write("default thread count ");
276        Log.write(defaultThreadCount);
277        Log.write(" and maximal thread count ");
278        Log.write(maxThreadCount);
279        Log.write(" supported by current GC plan.");
280        Log.writeln();
281        Log.write("New default thread count value is ");
282        Log.write(safeDefaultValue);
283        Log.writeln();
284    }
285    Options.threads.updateDefaultValue(safeDefaultValue);
286
287    int desiredThreadCount = Options.threads.getValue();
288    int actualThreadCount = Math.min(desiredThreadCount, maxThreadCount);
289    if (Options.verbose.getValue() > 0) {
290      Log.write("Setting actual thread count for MMTk to minimum of ");
291      Log.write("desired thread count ");
292      Log.write(desiredThreadCount);
293      Log.write(" and maximal thread count ");
294      Log.write(maxThreadCount);
295      Log.write(" supported by current GC plan.");
296      Log.writeln();
297      Log.write("New actual thread count is ");
298      Log.write(actualThreadCount);
299      Log.writeln();
300    }
301    Options.threads.setValue(actualThreadCount);
302
303    if (VM.VERIFY_ASSERTIONS) {
304      VM.assertions._assert(actualThreadCount > 0,
305          "Determining the number of gc threads yieled a result <= 0");
306    }
307
308    return actualThreadCount;
309  }
310
311  /**
312   * Prepares for spawning of collectors.<p>
313   *
314   * This is a good place to do initialization work that depends on
315   * options that are only known at runtime. Collectors must keep allocation
316   * to a minimum because collection is not yet enabled.
317   */
318  @Interruptible
319  protected void preCollectorSpawn() {
320    // most collectors do not need to do any work here
321  }
322
323  /**
324   * Spawns the collector threads.<p>
325   *
326   * Collection is enabled after this method returns.
327   *
328   * @param numThreads the number of collector threads to spawn
329   */
330  @Interruptible("Spawning collector threads requires allocation")
331  protected void spawnCollectorThreads(int numThreads) {
332    // Create our parallel workers
333    parallelWorkers.initGroup(numThreads, defaultCollectorContext);
334
335    // Create the concurrent worker threads.
336    if (VM.activePlan.constraints().needsConcurrentWorkers()) {
337      concurrentWorkers.initGroup(numThreads, defaultCollectorContext);
338    }
339
340    // Create our control thread.
341    VM.collection.spawnCollectorContext(controlCollectorContext);
342
343    // Allow mutators to trigger collection.
344    initialized = true;
345  }
346
347  @Interruptible
348  public void fullyBooted() {
349    if (Options.harnessAll.getValue()) harnessBegin();
350  }
351
352  public static final ParallelCollectorGroup parallelWorkers = new ParallelCollectorGroup("ParallelWorkers");
353  public static final ParallelCollectorGroup concurrentWorkers = new ParallelCollectorGroup("ConcurrentWorkers");
354  public static final ControllerCollectorContext controlCollectorContext = new ControllerCollectorContext(parallelWorkers);
355
356  /**
357   * The VM is about to exit. Perform any clean up operations.
358   *
359   * @param value The exit value
360   */
361  @Interruptible
362  public void notifyExit(int value) {
363    if (Options.harnessAll.getValue()) harnessEnd();
364    if (Options.verbose.getValue() == 1) {
365      Log.write("[End ");
366      totalTime.printTotalSecs();
367      Log.writeln(" s]");
368    } else if (Options.verbose.getValue() == 2) {
369      Log.write("[End ");
370      totalTime.printTotalMillis();
371      Log.writeln(" ms]");
372    }
373    if (Options.verboseTiming.getValue()) printDetailedTiming(true);
374  }
375
376  /**
377   * Any Plan can override this to provide additional plan specific
378   * timing information.
379   *
380   * @param totals Print totals
381   */
382  protected void printDetailedTiming(boolean totals) {}
383
384  /**
385   * Perform any required write barrier action when installing an object reference
386   * a boot time.
387   *
388   * @param reference the reference value that is to be stored
389   * @return The raw value to be stored
390   */
391  public Word bootTimeWriteBarrier(Word reference) {
392    return reference;
393  }
394
395  /**
396   * Performs any required initialization of the GC portion of the header.
397   * Called for objects created at boot time.
398   *
399   * @param object the Address representing the storage to be initialized
400   * @param typeRef the type reference for the instance being created
401   * @param size the number of bytes allocated by the GC system for
402   * this object.
403   * @return The new value of the status word
404   */
405  public byte setBuildTimeGCByte(Address object, ObjectReference typeRef, int size) {
406    if (HeaderByte.NEEDS_UNLOGGED_BIT) {
407      return HeaderByte.UNLOGGED_BIT;
408    } else {
409      return 0;
410    }
411  }
412
413  /****************************************************************************
414   * Allocation
415   */
416
417  /**
418   * @param compileTime is this a call by the compiler?
419   * @return an allocation site
420   *
421   */
422  public static int getAllocationSite(boolean compileTime) {
423    if (compileTime) // a new allocation site is being compiled
424      return allocationSiteCount++;
425    else             // an anonymous site
426      return DEFAULT_SITE;
427  }
428
429  /****************************************************************************
430   * Collection.
431   */
432
433  /**
434   * Perform a (global) collection phase.
435   *
436   * @param phaseId The unique id of the phase to perform.
437   */
438  public abstract void collectionPhase(short phaseId);
439
440  /**
441   * Replace a phase.
442   *
443   * @param oldScheduledPhase The scheduled phase to insert after
444   * @param scheduledPhase The scheduled phase to insert
445   */
446  @Interruptible
447  public void replacePhase(int oldScheduledPhase, int scheduledPhase) {
448    VM.assertions.fail("replacePhase not implemented for this plan");
449  }
450
451  /**
452   * Insert a phase.
453   *
454   * @param markerScheduledPhase The scheduled phase to insert after
455   * @param scheduledPhase The scheduled phase to insert
456   */
457  @Interruptible
458  public void insertPhaseAfter(int markerScheduledPhase, int scheduledPhase) {
459    short tempPhase = Phase.createComplex("auto-gen", null, markerScheduledPhase, scheduledPhase);
460    replacePhase(markerScheduledPhase, Phase.scheduleComplex(tempPhase));
461  }
462
463  /**
464   * @return Whether last GC was an exhaustive attempt to collect the heap.  For many collectors this is the same as asking whether the last GC was a full heap collection.
465   */
466  public boolean lastCollectionWasExhaustive() {
467    return lastCollectionFullHeap();
468  }
469
470  /**
471   * @return Whether last GC is a full GC.
472   */
473  public boolean lastCollectionFullHeap() {
474    return true;
475  }
476
477  /**
478   * @return Is last GC a full collection?
479   */
480  public static boolean isEmergencyCollection() {
481    return emergencyCollection;
482  }
483
484  /**
485   * Force the next collection to be full heap.
486   */
487  public void forceFullHeapCollection() {}
488
489  /**
490   * @return Is current GC only collecting objects allocated since last GC.
491   */
492  public boolean isCurrentGCNursery() {
493    return false;
494  }
495
496  private long lastStressPages = 0;
497
498  /**
499   * Return the expected reference count. For non-reference counting
500   * collectors this becomes a {@code true/false} relationship.
501   *
502   * @param object The object to check.
503   * @param sanityRootRC The number of root references to the object.
504   * @return The expected (root excluded) reference count.
505   */
506  public int sanityExpectedRC(ObjectReference object, int sanityRootRC) {
507    Space space = Space.getSpaceForObject(object);
508    return space.isReachable(object) ? SanityChecker.ALIVE : SanityChecker.DEAD;
509  }
510
511  /**
512   * Perform a linear scan of all spaces to check for possible leaks.
513   * This is only called after a full-heap GC.
514   *
515   * @param scanner The scanner callback to use.
516   */
517  public void sanityLinearScan(LinearScan scanner) {
518  }
519
520  /**
521   * @return {@code true} is a stress test GC is required
522   */
523  @Inline
524  public final boolean stressTestGCRequired() {
525    long pages = Space.cumulativeCommittedPages();
526    if (initialized &&
527        ((pages ^ lastStressPages) > Options.stressFactor.getPages())) {
528      lastStressPages = pages;
529      return true;
530    } else
531      return false;
532  }
533
534  /****************************************************************************
535   * GC State
536   */
537
538  /**
539   *
540   */
541  protected static boolean userTriggeredCollection;
542  protected static boolean internalTriggeredCollection;
543  protected static boolean lastInternalTriggeredCollection;
544  protected static boolean emergencyCollection;
545  protected static boolean stacksPrepared;
546
547  private static boolean initialized = false;
548
549  @Entrypoint
550  private static int gcStatus = NOT_IN_GC; // shared variable
551
552  /** @return Is the memory management system initialized? */
553  public static boolean isInitialized() {
554    return initialized;
555  }
556
557  /**
558   * Return {@code true} if stacks have been prepared in this collection cycle.
559   *
560   * @return {@code true} if stacks have been prepared in this collection cycle.
561   */
562  public static boolean stacksPrepared() {
563    return stacksPrepared;
564  }
565  /**
566   * Return {@code true} if a collection is in progress.
567   *
568   * @return {@code true} if a collection is in progress.
569   */
570  public static boolean gcInProgress() {
571    return gcStatus != NOT_IN_GC;
572  }
573
574  /**
575   * Return {@code true} if a collection is in progress and past the preparatory stage.
576   *
577   * @return {@code true} if a collection is in progress and past the preparatory stage.
578   */
579  public static boolean gcInProgressProper() {
580    return gcStatus == GC_PROPER;
581  }
582
583  /**
584   * Sets the GC status.
585   *
586   * @param s The new GC status.
587   */
588  public static void setGCStatus(int s) {
589    if (gcStatus == NOT_IN_GC) {
590      /* From NOT_IN_GC to any phase */
591      stacksPrepared = false;
592      // Need to call this method to get a correct collection
593      // count (which we need for JMX). This call won't cause
594      // gathering of additional stats unless stats are enabled.
595      Stats.startGC();
596      if (Stats.gatheringStats()) {
597        VM.activePlan.global().printPreStats();
598      }
599    }
600    VM.memory.isync();
601    gcStatus = s;
602    VM.memory.sync();
603    if (gcStatus == NOT_IN_GC) {
604      /* From any phase to NOT_IN_GC */
605      if (Stats.gatheringStats()) {
606        Stats.endGC();
607        VM.activePlan.global().printPostStats();
608      }
609    }
610  }
611
612  /**
613   * Print pre-collection statistics.
614   */
615  public void printPreStats() {
616    if ((Options.verbose.getValue() == 1) ||
617        (Options.verbose.getValue() == 2)) {
618      Log.write("[GC "); Log.write(Stats.gcCount());
619      if (Options.verbose.getValue() == 1) {
620        Log.write(" Start ");
621        Plan.totalTime.printTotalSecs();
622        Log.write(" s");
623      } else {
624        Log.write(" Start ");
625        Plan.totalTime.printTotalMillis();
626        Log.write(" ms");
627      }
628      Log.write("   ");
629      Log.write(Conversions.pagesToKBytes(getPagesUsed()));
630      Log.write("KB ");
631      Log.flush();
632    }
633    if (Options.verbose.getValue() > 2) {
634      Log.write("Collection "); Log.write(Stats.gcCount());
635      Log.write(":        ");
636      printUsedPages();
637      Log.write("  Before Collection: ");
638      Space.printUsageMB();
639      if (Options.verbose.getValue() >= 4) {
640        Log.write("                     ");
641        Space.printUsagePages();
642      }
643      if (Options.verbose.getValue() >= 5) {
644        Space.printVMMap();
645      }
646    }
647  }
648
649  /**
650   * Print out statistics at the end of a GC
651   */
652  public final void printPostStats() {
653    if ((Options.verbose.getValue() == 1) ||
654        (Options.verbose.getValue() == 2)) {
655      Log.write("-> ");
656      Log.writeDec(Conversions.pagesToBytes(getPagesUsed()).toWord().rshl(10));
657      Log.write("KB   ");
658      if (Options.verbose.getValue() == 1) {
659        totalTime.printLast();
660        Log.writeln(" ms]");
661      } else {
662        Log.write("End ");
663        totalTime.printTotal();
664        Log.writeln(" ms]");
665      }
666    }
667    if (Options.verbose.getValue() > 2) {
668      Log.write("   After Collection: ");
669      Space.printUsageMB();
670      if (Options.verbose.getValue() >= 4) {
671        Log.write("                     ");
672        Space.printUsagePages();
673      }
674      if (Options.verbose.getValue() >= 5) {
675        Space.printVMMap();
676      }
677      Log.write("                     ");
678      printUsedPages();
679      Log.write("    Collection time: ");
680      totalTime.printLast();
681      Log.writeln(" ms");
682    }
683  }
684
685  public final void printUsedPages() {
686    Log.write("reserved = ");
687    Log.write(Conversions.pagesToMBytes(getPagesReserved()));
688    Log.write(" MB (");
689    Log.write(getPagesReserved());
690    Log.write(" pgs)");
691    Log.write("      used = ");
692    Log.write(Conversions.pagesToMBytes(getPagesUsed()));
693    Log.write(" MB (");
694    Log.write(getPagesUsed());
695    Log.write(" pgs)");
696    Log.write("      total = ");
697    Log.write(Conversions.pagesToMBytes(getTotalPages()));
698    Log.write(" MB (");
699    Log.write(getTotalPages());
700    Log.write(" pgs)");
701    Log.writeln();
702  }
703
704  /**
705   * The application code has requested a collection.
706   */
707  @Unpreemptible
708  public static void handleUserCollectionRequest() {
709    if (Options.ignoreSystemGC.getValue()) {
710      // Ignore the user GC request.
711      return;
712    }
713    // Mark this as a user triggered collection
714    userTriggeredCollection = true;
715    // Request the collection
716    controlCollectorContext.request();
717    // Wait for the collection to complete
718    VM.collection.blockForGC();
719  }
720
721  /**
722   * MMTK has requested stop-the-world activity (e.g., stw within a concurrent gc).
723   */
724  public static void triggerInternalCollectionRequest() {
725    // Mark this as a user triggered collection
726    internalTriggeredCollection = lastInternalTriggeredCollection = true;
727    // Request the collection
728    controlCollectorContext.request();
729  }
730
731  /**
732   * Reset collection state information.
733   */
734  public static void resetCollectionTrigger() {
735    lastInternalTriggeredCollection = internalTriggeredCollection;
736    internalTriggeredCollection = false;
737    userTriggeredCollection = false;
738  }
739
740  /**
741   * @return {@code true} if this collection was triggered by application code.
742   */
743  public static boolean isUserTriggeredCollection() {
744    return userTriggeredCollection;
745  }
746
747  /**
748   * @return {@code true} if this collection was triggered internally.
749   */
750  public static boolean isInternalTriggeredCollection() {
751    return lastInternalTriggeredCollection;
752  }
753
754  /****************************************************************************
755   * Harness
756   */
757
758  /**
759   *
760   */
761  protected static boolean insideHarness = false;
762
763  /**
764   * Generic hook to allow benchmarks to be harnessed.  A plan may use
765   * this to perform certain actions prior to the commencement of a
766   * benchmark, such as a full heap collection, turning on
767   * instrumentation, etc.  By default we do a full heap GC,
768   * and then start stats collection.
769   */
770  @Interruptible
771  public static void harnessBegin() {
772    // Save old values.
773    boolean oldFullHeap = Options.fullHeapSystemGC.getValue();
774    boolean oldIgnore = Options.ignoreSystemGC.getValue();
775
776    // Set desired values.
777    Options.fullHeapSystemGC.setValue(true);
778    Options.ignoreSystemGC.setValue(false);
779
780    // Trigger a full heap GC.
781    System.gc();
782
783    // Restore old values.
784    Options.ignoreSystemGC.setValue(oldIgnore);
785    Options.fullHeapSystemGC.setValue(oldFullHeap);
786
787    // Start statistics
788    insideHarness = true;
789    Stats.startAll();
790  }
791
792  /**
793   * Generic hook to allow benchmarks to be harnessed.  A plan may use
794   * this to perform certain actions after the completion of a
795   * benchmark, such as a full heap collection, turning off
796   * instrumentation, etc.  By default we stop all statistics objects
797   * and print their values.
798   */
799  @Interruptible
800  public static void harnessEnd()  {
801    Stats.stopAll();
802    insideHarness = false;
803  }
804
805  /****************************************************************************
806   * VM Accounting
807   */
808
809  /* Global accounting and static access */
810
811  /**
812   * Return the amount of <i>free memory</i>, in bytes (where free is
813   * defined as not in use).  Note that this may overstate the amount
814   * of <i>available memory</i>, which must account for unused memory
815   * that is held in reserve for copying, and therefore unavailable
816   * for allocation.
817   *
818   * @return The amount of <i>free memory</i>, in bytes (where free is
819   * defined as not in use).
820   */
821  public static Extent freeMemory() {
822    return totalMemory().minus(usedMemory());
823  }
824
825  /**
826   * Return the amount of <i>available memory</i>, in bytes.  Note
827   * that this accounts for unused memory that is held in reserve
828   * for copying, and therefore unavailable for allocation.
829   *
830   * @return The amount of <i>available memory</i>, in bytes.
831   */
832  public static Extent availableMemory() {
833    return totalMemory().minus(reservedMemory());
834  }
835
836  /**
837   * Return the amount of <i>memory in use</i>, in bytes.  Note that
838   * this excludes unused memory that is held in reserve for copying,
839   * and therefore unavailable for allocation.
840   *
841   * @return The amount of <i>memory in use</i>, in bytes.
842   */
843  public static Extent usedMemory() {
844    return Conversions.pagesToBytes(VM.activePlan.global().getPagesUsed());
845  }
846
847  /**
848   * Return the amount of <i>memory in use</i>, in bytes.  Note that
849   * this includes unused memory that is held in reserve for copying,
850   * and therefore unavailable for allocation.
851   *
852   * @return The amount of <i>memory in use</i>, in bytes.
853   */
854  public static Extent reservedMemory() {
855    return Conversions.pagesToBytes(VM.activePlan.global().getPagesReserved());
856  }
857
858  /**
859   * Return the total amount of memory managed to the memory
860   * management system, in bytes.
861   *
862   * @return The total amount of memory managed to the memory
863   * management system, in bytes.
864   */
865  public static Extent totalMemory() {
866    return HeapGrowthManager.getCurrentHeapSize();
867  }
868
869  /* Instance methods */
870
871  /**
872   * Return the total amount of memory managed to the memory
873   * management system, in pages.
874   *
875   * @return The total amount of memory managed to the memory
876   * management system, in pages.
877   */
878  public final int getTotalPages() {
879    return totalMemory().toWord().rshl(LOG_BYTES_IN_PAGE).toInt();
880  }
881
882  /**
883   * Return the number of pages available for allocation.
884   *
885   * @return The number of pages available for allocation.
886   */
887  public int getPagesAvail() {
888    return getTotalPages() - getPagesReserved();
889  }
890
891  /**
892   * Return the number of pages reserved for use given the pending
893   * allocation.  Sub-classes must override the getCopyReserve method,
894   * as the arithmetic here is fixed.
895   *
896   * @return The number of pages reserved given the pending
897   * allocation, including space reserved for copying.
898   */
899  public final int getPagesReserved() {
900    return getPagesUsed() + getCollectionReserve();
901  }
902
903  /**
904   * Return the number of pages reserved for collection.
905   * In most cases this is a copy reserve, all subclasses that
906   * manage a copying space must add the copying contribution.
907   *
908   * @return The number of pages reserved given the pending
909   * allocation, including space reserved for collection.
910   */
911  public int getCollectionReserve() {
912    return 0;
913  }
914
915  /**
916   * Return the number of pages reserved for use given the pending
917   * allocation.
918   *
919   * @return The number of pages reserved given the pending
920   * allocation, excluding space reserved for copying.
921   */
922  public int getPagesUsed() {
923    return loSpace.reservedPages() + immortalSpace.reservedPages() +
924      metaDataSpace.reservedPages() + nonMovingSpace.reservedPages();
925  }
926
927  /****************************************************************************
928   * Internal read/write barriers.
929   */
930
931  /**
932   * Store an object reference
933   *
934   * @param slot The location of the reference
935   * @param value The value to store
936   */
937  @Inline
938  public void storeObjectReference(Address slot, ObjectReference value) {
939    slot.store(value);
940  }
941
942  /**
943   * Load an object reference
944   *
945   * @param slot The location of the reference
946   * @return the object reference loaded from slot
947   */
948  @Inline
949  public ObjectReference loadObjectReference(Address slot) {
950    return slot.loadObjectReference();
951  }
952
953  /****************************************************************************
954   * Collection.
955   */
956
957  /**
958   * This method is called periodically by the allocation subsystem
959   * (by default, each time a page is consumed), and provides the
960   * collector with an opportunity to collect.
961   *
962   * @param spaceFull Space request failed, must recover pages within 'space'.
963   * @param space The space that triggered the poll.
964   * @return <code>true</code> if a collection is required.
965   */
966  public final boolean poll(boolean spaceFull, Space space) {
967    if (collectionRequired(spaceFull, space)) {
968      if (space == metaDataSpace) {
969        /* In general we must not trigger a GC on metadata allocation since
970         * this is not, in general, in a GC safe point.  Instead we initiate
971         * an asynchronous GC, which will occur at the next safe point.
972         */
973        logPoll(space, "Asynchronous collection requested");
974        controlCollectorContext.request();
975        return false;
976      }
977      logPoll(space, "Triggering collection");
978      controlCollectorContext.request();
979      return true;
980    }
981
982    if (concurrentCollectionRequired()) {
983      if (space == metaDataSpace) {
984        logPoll(space, "Triggering async concurrent collection");
985        triggerInternalCollectionRequest();
986        return false;
987      } else {
988        logPoll(space, "Triggering concurrent collection");
989        triggerInternalCollectionRequest();
990        return true;
991      }
992    }
993
994    return false;
995  }
996
997  protected void logPoll(Space space, String message) {
998    if (Options.verbose.getValue() >= 5) {
999      Log.write("  [POLL] ");
1000      Log.write(space.getName());
1001      Log.write(": ");
1002      Log.writeln(message);
1003    }
1004  }
1005
1006  /**
1007   * This method controls the triggering of a GC. It is called periodically
1008   * during allocation. Returns <code>true</code> to trigger a collection.
1009   *
1010   * @param spaceFull Space request failed, must recover pages within 'space'.
1011   * @param space TODO
1012   * @return <code>true</code> if a collection is requested by the plan.
1013   */
1014  protected boolean collectionRequired(boolean spaceFull, Space space) {
1015    boolean stressForceGC = stressTestGCRequired();
1016    boolean heapFull = getPagesReserved() > getTotalPages();
1017
1018    return spaceFull || stressForceGC || heapFull;
1019  }
1020
1021  /**
1022   * This method controls the triggering of an atomic phase of a concurrent
1023   * collection. It is called periodically during allocation.
1024   *
1025   * @return <code>true</code> if a collection is requested by the plan.
1026   */
1027  protected boolean concurrentCollectionRequired() {
1028    return false;
1029  }
1030
1031  /**
1032   * Start GCspy server.
1033   *
1034   * @param port The port to listen on,
1035   * @param wait Should we wait for a client to connect?
1036   */
1037  @Interruptible
1038  public void startGCspyServer(int port, boolean wait) {
1039    VM.assertions.fail("startGCspyServer called on non GCspy plan");
1040  }
1041
1042  /**
1043   * Can this object ever move.  Used by the VM to make decisions about
1044   * whether it needs to copy IO buffers etc.
1045   *
1046   * @param object The object in question
1047   * @return <code>true</code> if it is not possible that the object will ever move.
1048   */
1049  public boolean willNeverMove(ObjectReference object) {
1050    if (!VM.activePlan.constraints().movesObjects())
1051      return true;
1052    if (Space.isInSpace(LOS, object))
1053      return true;
1054    if (Space.isInSpace(IMMORTAL, object))
1055      return true;
1056    if (Space.isInSpace(VM_SPACE, object))
1057      return true;
1058    if (Space.isInSpace(NON_MOVING, object))
1059      return true;
1060    if (USE_CODE_SPACE && Space.isInSpace(SMALL_CODE, object))
1061      return true;
1062    if (USE_CODE_SPACE && Space.isInSpace(LARGE_CODE, object))
1063      return true;
1064    /*
1065     * Default to false- this preserves correctness over efficiency.
1066     * Individual plans should override for non-moving spaces they define.
1067     */
1068    return false;
1069  }
1070
1071  /****************************************************************************
1072   * Specialized Methods
1073   */
1074
1075  /**
1076   * Registers specialized methods.
1077   */
1078  @Interruptible
1079  protected void registerSpecializedMethods() {}
1080
1081  /**
1082   * @param id the id of the specialized scan class
1083   * @return the specialized scan with the given id
1084   */
1085  public final Class<?> getSpecializedScanClass(int id) {
1086    return TransitiveClosure.getSpecializedScanClass(id);
1087  }
1088}