package s3.services.memory.mostlyCopying;
import ovm.core.domain.Blueprint;
import ovm.core.domain.ObjectModel;
import ovm.core.domain.Oop;
import ovm.core.services.memory.ExtentWalker;
import ovm.core.services.memory.MovingGC;
import ovm.core.services.memory.VM_Address;
import ovm.core.services.memory.VM_Word;
import ovm.util.NumberRanges;

/**
 * A base class for implementing Chenney scanning garbage collection.
 * Essentially, this class provides support for scanning root objects
 * and grey objects.
 *
 * @author <a href=mailto://baker29@cs.purdue.edu> Jason Baker </a>
 **/
public abstract class ExtentUpdater extends ExtentWalker {
    /**
     * true if <code>oop</code> either has been or should be moved in
     * this GC cycle.
     **/
    public abstract boolean needsUpdate(MovingGC oop);
    /**
     * Called to move an object to a new location.  That location
     * should be returned, and recorded as the forwarding address of
     * oop.
     **/
    public abstract Oop updateReference(MovingGC oop);

    /**
     * This method takes the address of an object reference, and
     * updates that location in memory.  This method is implemented in
     * terms of {@link #needsUpdate}, {@link #updateReference}, and
     * {@link ovm.core.services.memory.MovingGC#getForwardAddress}.
     **/
    public void updateLoc(VM_Address loc) {
	MovingGC oop = (MovingGC) loc.getAddress().asAnyOop();
	if (needsUpdate(oop)) {
	    Oop newVal = (oop.isForwarded()
			  ? oop.getForwardAddress().asOop()
			  : updateReference(oop));
	    loc.setAddress(VM_Address.fromObject(newVal));
	}
    }

    /**
     * Update references within a region of memory.  References to
     * objects that have been or should be copied will be updated to
     * point to the object address.  The address of each pointer within the
     * region is passed to {@link #updateLoc}.<p>
     *
     * The region of memory examined should be a contiguous group of
     * objects.  The <code>start</code> address is a pointer to the
     * first object in the group.  The <code>end</code> address
     * provides an upper bound on the total size of the region.  There
     * may be unused space between the end of the last object and the
     * <code>end</code> address, but the first word of this unused
     * space must be zero.
     **/
    public void walk(VM_Address start, VM_Address end) {
	while (start.uLT(end) && start.getAddress() != null) {
	    Oop.WithUpdate oop = (Oop.WithUpdate) start.asAnyOop();
	    Blueprint bp = oop.getBlueprint();
	    start = start.add(bp.getVariableSize(oop));

	    for (int i = 0;
		 i < ObjectModel.getObjectModel().maxReferences();
		 i++) {
		MovingGC r = (MovingGC) oop.getReference(i).asAnyOop();
		if (needsUpdate(r)) {
		    Oop newVal = (r.isForwarded()
				  ? r.getForwardAddress().asOop()
				  : updateReference(r));
		    oop.updateReference(i, newVal);
		}
	    }
	    if (bp.isArray()) {
		Blueprint.Array abp = bp.asArray();
		if (abp.getComponentBlueprint().isReference()) {
		    VM_Address p = abp.addressOfElement(oop, 0);
		    VM_Address pend = p.add(VM_Word.widthInBytes()
					    * abp.getLength(oop));
		    while (p.uLT(pend)) {
			updateLoc(p);
			p = p.add(VM_Word.widthInBytes());
		    }
		}
	    }
	    else {
		VM_Address base = VM_Address.fromObject(oop);
		int[] offset = bp.getRefMap();
		for (int i = 0; i < offset.length; i++)
		    updateLoc(base.add(offset[i]));
	    }
	}
    }
}
	    
	    

    
