/*
* 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.sanity;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.mmtk.harness.Harness;
import org.mmtk.harness.Mutator;
import org.mmtk.harness.Mutators;
import org.mmtk.harness.lang.Trace;
import org.mmtk.harness.lang.Trace.Item;
import org.mmtk.harness.lang.runtime.ObjectValue;
import org.mmtk.harness.vm.ActivePlan;
import org.mmtk.harness.vm.ObjectModel;
import org.mmtk.harness.vm.Scanning;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.ObjectReference;
/**
* Perform a traversal of the heap, calling appropriate methods on
* the HeapVisitor object supplied.
*/
public final class Traversal {
private static final boolean VERBOSE = false;
/**
* Traverse the heap. This is the only public method in the class
* @param visitor The heap visitor
*/
public static void traverse(HeapVisitor visitor) {
new Traversal(visitor);
}
private final Set<ObjectReference> blackSet = new HashSet<ObjectReference>();
private final List<ObjectReference> markStack = new ArrayList<ObjectReference>();
private final HeapVisitor visitor;
/**
* Perform the traversal.
* @param visitor
*/
private Traversal(HeapVisitor visitor) {
this.visitor = visitor;
traceRoots();
doClosure();
}
/**
* Scan an object, calling the appropriate visitor method
* @param object
*/
private void scan(ObjectReference object) {
if (VERBOSE) {
Trace.trace(Item.SANITY, "scanning object %s", ObjectModel.getString(object));
}
for (int i=0; i < ObjectModel.getRefs(object); i++) {
Address slot = ObjectModel.getRefSlot(object, i);
ObjectReference ref = loadReferenceSlot(slot);
if (!ref.isNull()) {
visitor.visitPointer(object, slot, ref);
traceObject(ref,false);
}
}
}
private ObjectReference loadReferenceSlot(Address slot) {
if (Harness.sanityUsesReadBarrier.getValue()) {
return ActivePlan.plan.loadObjectReference(slot);
}
return slot.loadObjectReference();
}
/**
* Trace an object, calling the appropriate visitor method
* @param object
* @param root
*/
private void traceObject(ObjectReference object, boolean root) {
if (VERBOSE) {
Trace.trace(Item.SANITY, "tracing object %s", ObjectModel.getString(object));
}
if (object.isNull()) return;
boolean marked = blackSet.contains(object);
if (!marked) {
blackSet.add(object);
markStack.add(object);
}
visitor.visitObject(object, root, marked);
}
/**
* Trace the harness root set
*/
private void traceRoots() {
for (ObjectValue value : Scanning.getRoots()) {
traceObject(value.getObjectValue(), true);
}
for (Mutator m : Mutators.getAll()) {
for (ObjectValue value : m.getRoots()) {
traceObject(value.getObjectValue(), true);
}
}
}
/**
* Iterate over the heap depth-first, scanning objects until
* the mark stack is empty.
*/
private void doClosure() {
while (markStack.size() > 0) {
ObjectReference object = markStack.remove(markStack.size()-1);
scan(object);
}
blackSet.clear();
markStack.clear();
}
}