package s3.services.memory.mostlyCopying;

import ovm.core.execution.Activation;
import ovm.core.execution.Context;
import ovm.core.execution.NativeInterface;
import ovm.core.services.memory.VM_Address;
import ovm.core.services.memory.VM_Word;
import ovm.util.Iterator;

/**
 * A base class for conservative, moving GC.  This class inherits
 * scanning support from {@link ExtentUpdater} and adds support for
 * conservative stack walking.<p>
 *
 * FIXME:  This inheritence relationship seems wrong.  It exists
 * because each thread state contains one precies root: the pointer
 * from a native context to it's java peer.  This root must be walked
 * with {@link ExtentUpdater#updateLoc} or some equivalent for a
 * non-moving collector.
 *
 * @author <a href=mailto://baker29@cs.purdue.edu> Jason Baker </a>
 */
public abstract class ConservativeUpdater extends ExtentUpdater {
    /**
     * This method is called on every word in a thread stack.  If the
     * word may be an object reference, the appropriate action should
     * be taken.
     **/
    public abstract void checkConservativeRoot(VM_Word w);

    public static final class NativeHelpers implements NativeInterface {
	static native VM_Address getOVMContextLoc(int nativeContext);
	// bottom frame, highest address
	static native VM_Address getStackBase(int nativeContext);
	// top frame, lowest address
	static native VM_Address getStackTop(int nativeContext);

	// These methods are used in combination with getStackTop to
	// walk non-current threads.
	static native VM_Address getSavedRegisters(int nativeContext);
	static native int getSavedRegisterSize();

	// This method is called on the garbageCollect() frame to walk
	// the current thread.  It relies on garbageCollect() using
	// all call-preserved registers.
	static native VM_Address callerLocalsEnd(int frameHandle);
	
	static native boolean stackGrowsUp();
    }

    protected Context getNext(Iterator it) {
	if (!it.hasNext())
	    return null;
	return (Context) it.next();
    }

    /**
     * This method calls {@link #checkConservativeRoot} on every
     * potential pointer in the system.  It iterates over the
     * register set and stack of all threads other than the current
     * one, and iterates over the part of the current thread stack
     * below <code>curThreadSkip</code>.
     * 
     * @param curThreadSkip the activation of the main GC loop.  The
     * current thread stack is walked starting with this activation's
     * caller,
     **/
    public void walkThreadStacks(Activation curThreadSkip) {
	int nact = curThreadSkip.getNativeHandle();
        Context currentThread = Context.getCurrentContext();
	boolean swap = NativeHelpers.stackGrowsUp();

        Iterator it = Context.iterator();
	for (Context ctx = getNext(it); ctx != null; ctx = getNext(it)) {
	    int nctx = ctx.nativeContextHandle_;
	    VM_Address start, end;

	    if (ctx != currentThread) {
		start = NativeHelpers.getSavedRegisters(nctx);
		end = start.add(NativeHelpers.getSavedRegisterSize());
		while (start.uLT(end)) {
		    checkConservativeRoot(start.getWord());
		    start = start.add(VM_Word.widthInBytes());
		}
		start = NativeHelpers.getStackTop(nctx);
	    } else
		start = NativeHelpers.callerLocalsEnd(nact);
	    end = NativeHelpers.getStackBase(nctx);
		
	    if (swap) {
		VM_Address tmp = end;
		end = start;
		start = tmp;
	    }
            if (ovm.core.OVMBase.ASSERTS_ENABLED) 
                ovm.core.OVMBase.OVMassert(start.uLE(end));
	    while (start.uLT(end)) {
		checkConservativeRoot(start.getWord());
		start = start.add(VM_Word.widthInBytes());
	    }
	}
	// We don't want to update native context back-pointers until
	// after thread stacks are walked: the Context object may be
	// on a pinned page!
	it = Context.iterator();
	for (Context ctx = getNext(it); ctx != null; ctx = getNext(it))
	    updateLoc(NativeHelpers.getOVMContextLoc(ctx.nativeContextHandle_));
    }
}

    
