/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.mmtk.harness.vm;
import org.mmtk.harness.Collector;
import org.mmtk.harness.Harness;
import org.mmtk.harness.Mutator;
import org.mmtk.harness.Mutators;
import org.mmtk.harness.exception.OutOfMemory;
import org.mmtk.harness.scheduler.Scheduler;
import org.mmtk.plan.CollectorContext;
import org.mmtk.plan.MutatorContext;
import org.mmtk.plan.Plan;
import org.mmtk.utility.options.Options;
import org.vmmagic.pragma.*;
@Uninterruptible
public class Collection extends org.mmtk.vm.Collection {
/****************************************************************************
*
* Class variables
*/
/**
* Triggers a collection.
*
* @param why the reason why a collection was triggered. 0 to
* <code>TRIGGER_REASONS - 1</code>.
*/
@Override
public void triggerCollection(int why) {
if (Options.verbose.getValue() >= 4) {
new Exception("Collection trigger: " + triggerReasons[why]).printStackTrace();
}
Plan.setCollectionTriggered();
if (Options.verbose.getValue() >= 1) {
if (why == EXTERNAL_GC_TRIGGER) {
System.err.print("[Forced GC]");
} else if (why == INTERNAL_PHASE_GC_TRIGGER) {
System.err.print("[Phase GC]");
}
}
Mutator mutator = Mutator.current();
if (why != EXTERNAL_GC_TRIGGER && why != INTERNAL_PHASE_GC_TRIGGER) {
mutator.reportCollectionAttempt();
}
if (mutator.isOutOfMemory()) throw new OutOfMemory();
Collector.triggerGC(why);
Scheduler.waitForGC();
if (mutator.isOutOfMemory() && !mutator.isPhysicalAllocationFailure()) {
throw new OutOfMemory();
}
}
/**
* Joins an already requested collection.
*/
@Override
public void joinCollection() {
while (Plan.isCollectionTriggered()) {
/* allow a gc thread to run */
Mutator.current().gcSafePoint();
}
Mutator mutator = Mutator.current();
if (mutator.isOutOfMemory() && !mutator.isPhysicalAllocationFailure()) {
throw new OutOfMemory();
}
}
/**
* Trigger an asynchronous collection, checking for memory
* exhaustion first.
*
* @param why the reason why a collection was triggered. 0 to
* <code>TRIGGER_REASONS - 1</code>.
*/
@Override
public void triggerAsyncCollection(int why) {
Plan.setCollectionTriggered();
if (Options.verbose.getValue() >= 1) {
if (why == INTERNAL_PHASE_GC_TRIGGER) {
System.err.print("[Async-Phase GC]");
} else {
System.err.print("[Async GC]");
}
}
Collector.triggerGC(why);
}
/**
* @return The maximum number of collection attempts across threads.
*/
@Override
public int maximumCollectionAttempt() {
int max = 1;
for(Mutator m : Mutators.getAll()) {
int current = m.getCollectionAttempts();
if (current > max) max = current;
}
return max + Collector.getCollectionAttemptBase();
}
/**
* Report that the allocation has succeeded.
*/
@Override
public void reportAllocationSuccess() {
Mutator mutator = Mutator.current();
mutator.setOutOfMemory(false);
mutator.clearCollectionAttempts();
mutator.setPhysicalAllocationFailure(false);
}
/**
* Report that a physical allocation has failed.
*/
@Override
public void reportPhysicalAllocationFailed() {
Mutator.current().setPhysicalAllocationFailure(true);
}
/**
* Does the VM consider this an emergency alloction, where the normal
* heap size rules can be ignored.
*/
@Override
public boolean isEmergencyAllocation() {
// Not required
return false;
}
/**
* Determine whether a collection cycle has fully completed (this is
* used to ensure a GC is not in the process of completing, to
* avoid, for example, an async GC being triggered on the switch
* from GC to mutator thread before all GC threads have switched.
*
* @return True if GC is not in progress.
*/
@Override
public boolean noThreadsInGC() {
return Scheduler.noThreadsInGC();
}
/**
* Prepare a mutator for collection.
*
* @param m the mutator to prepare
*/
@Override
public void prepareMutator(MutatorContext m) {
// Nothing to do
}
/**
* Prepare a collector for a collection.
*
* @param c the collector to prepare
*/
@Override
public void prepareCollector(CollectorContext c) {
// Nothing to do
}
/**
* Rendezvous with all other processors, returning the rank
* (that is, the order this processor arrived at the barrier).
*/
@Override
public int rendezvous(int where) {
return Collector.rendezvous(where);
}
/** @return The number of active collector threads */
@Override
public int activeGCThreads() {
return Harness.collectors.getValue();
}
/**
* @return The ordinal ID of the running collector thread w.r.t.
* the set of active collector threads (zero based)
*/
@Override
public int activeGCThreadOrdinal() {
return Collector.current().getContext().getId();
}
/**
* Ensure all concurrent worker threads are scheduled.
*/
public void scheduleConcurrentWorkers() {
Assert.notImplemented();
}
/**
* Request each mutator flush remembered sets. This method
* will trigger the flush and then yield until all processors have
* flushed.
*/
@Override
public void requestMutatorFlush() {
Assert.notImplemented();
}
/**
* Possibly yield the current concurrent collector thread. Return
* true if yielded.
*/
public boolean yieldpoint() {
return Mutator.current().gcSafePoint();
}
}