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 }