package gc;
import icecaptools.IcecapCompileMe;
import reflect.ClassInfo;
import reflect.ObjectInfo;
import thread.Semaphore;
import thread.Thread;
import util.LiveSet;
import util.ReferenceIterator;
import vm.HVMHeap;
import vm.Heap;
public class GarbageCollector implements Runnable {
public boolean GCstopped;
private static Semaphore gcFinished;
private static GCMonitor monitor;
private static Thread gc;
private static ReferenceIterator staticRoots;
private static LiveSet liveSet;
private static BitMap bitMap;
private static boolean GCIsRunning;
private static Heap heap;
private Semaphore startGC;
private Semaphore endGC;
static {
init();
}
@IcecapCompileMe
private static void init() {
GCIsRunning = false;
heap = HVMHeap.getHeap();
bitMap = new BitMap(heap.getBlockSize(), heap.getStartAddress(), heap.getHeapSize());
heap.setBitMap(bitMap);
Object hack = new Object();
newBarrier(ObjectInfo.getAddress(hack));
writeBarrier(0, 0);
short count = ClassInfo.getNumberOfClasses();
do {
count--;
ClassInfo.getClassInfo(count);
} while (count > 0);
}
public GarbageCollector(Semaphore startGC, Semaphore endGC) {
this.startGC = startGC;
this.endGC = endGC;
GCstopped = false;
}
@IcecapCompileMe
private static void writeBarrier(int source, int oldRef) {
if (GCIsRunning) {
if (Thread.currentThread() != gc) {
if (!bitMap.isRefBlack(source)) {
if (oldRef != 0) {
if (bitMap.isRefWhite(oldRef)) {
liveSet.push(oldRef);
}
}
}
}
}
}
@IcecapCompileMe
private static void newBarrier(int ref) {
if (GCIsRunning) {
if (Thread.currentThread() == gc) {
bitMap.shadeRefWhite(ref);
} else {
bitMap.shadeRefBlack(ref);
}
} else {
if (bitMap != null) {
bitMap.shadeRefWhite(ref);
}
}
}
private void setRoots() {
liveSet.clear();
staticRoots = heap.getStaticRef();
while (staticRoots.hasNext()) {
int nextRoot = staticRoots.next();
if (nextRoot != 0) {
monitor.addStaticRoot(nextRoot);
liveSet.push(nextRoot);
}
}
ReferenceIterator stackRoots = heap.getRefFromStacks();
while (stackRoots.hasNext()) {
int possibleRef = stackRoots.next();
if (possibleRef != 0) {
if (bitMap.isWithinRangeOfHeap(possibleRef)) {
if (heap.isRefAnObj(possibleRef)) {
if (heap.isRefAllocated(possibleRef)) {
liveSet.push(possibleRef);
monitor.addStackRoot(possibleRef);
}
}
}
}
}
}
private void traverse(LiveSet nodes) {
ReferenceIterator children;
int parent;
while (!nodes.isEmpty()) {
parent = nodes.pop();
children = heap.getRefFromObj(parent);
while (children.hasNext()) {
int child = children.next();
if (child != 0) {
if (bitMap.isWithinRangeOfHeap(child)) {
monitor.visitChild(parent, child);
if (!bitMap.isRefBlack(child)) {
nodes.push(child);
}
}
}
}
bitMap.shadeRefBlack(parent);
}
}
private void makeFreeList() {
ReferenceIterator freeList = bitMap.getFreeList();
while (freeList.hasNext()) {
monitor.freeObject(freeList.next());
}
}
public void run() {
while (!GCstopped) {
Thread.print("GC wait for next cycle");
// run when signaled from controller thread
startGC.acquire();
Thread.print("starting GC cycle");
GCIsRunning = true;
Thread.getScheduler().disable();
setRoots();
Thread.getScheduler().enable();
// start incremental traversal of object graph
traverse(liveSet);
GCIsRunning = false;
// stops the write and new barrier - if free is not atomic then
// position and relation regarding the free operation to be
// considered ...
// free unused object - atomic ?
makeFreeList();
// signal controller that GC is finished
endGC.release();
gcFinished.release();
}
}
public static void start() {
Semaphore startGC = new Semaphore((byte) 0);
Semaphore endGC = new Semaphore((byte) 0);
gcFinished = new Semaphore((byte) 0);
Thread controller = new Thread(new GarbargeCollectorController(startGC, endGC));
gc = new Thread(new GarbageCollector(startGC, endGC));
liveSet = new LiveSet(bitMap);
devices.Console.println("Bitmap size = " + bitMap.getSize());
controller.start();
gc.start();
}
public static void registerMonitor(GCMonitor m) {
monitor = m;
}
public static void requestCollection() {
GarbargeCollectorController.requestCollection();
}
public static void waitForNextCollection() {
gcFinished.acquire();
}
}