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 }