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