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