package s3.services.fastLock;

import ovm.core.domain.Domain;
import ovm.core.domain.ObjectModel;
import ovm.core.domain.Oop;
import ovm.core.execution.Context;
import ovm.core.execution.CoreServicesAccess;
import ovm.core.services.threads.OVMThread;
import ovm.core.services.threads.OVMThreadContext;
import ovm.services.monitors.FastLockable;
import ovm.services.monitors.Monitor;
import s3.core.domain.S3Domain;
import s3.core.execution.S3CoreServicesAccess;
import s3.util.PragmaAtomic;
import s3.util.PragmaInline;
import s3.util.PragmaNoInline;
import s3.util.PragmaNoPollcheck;

public class FastLockCoreServicesAccess extends S3CoreServicesAccess {
    public void monitorEnterSlow(FastLockable obj) throws PragmaNoInline, PragmaNoPollcheck {
	int rc = obj.getRecursionCount();
	if (obj.isMine()
	    && rc < ((FastLockable.Model) ObjectModel.getObjectModel()).maxRecursionCount())
	{
	    obj.setRecursionCount(rc + 1);
	} else {
	    super.monitorEnter(obj);
	}
    }

    public void monitorEnter(Oop _obj) throws PragmaInline, PragmaNoPollcheck
    {
	FastLockable obj = (FastLockable) _obj.asAnyOop();
	if (!obj.fastLock())
	    monitorEnterSlow(obj);
    }


    public void monitorTransfer(Oop _obj, OVMThread newOwner) 
        throws PragmaInline {
	FastLockable obj = (FastLockable) _obj.asAnyOop();
        // do this first so no pollchecks occur once we start checking bits
        Context ctx = newOwner.getContext();

	if (!obj.isMine() || obj.isInflated()) {
	    super.monitorTransfer(obj, newOwner);
            return;
        }

        // assert: recursion-count == 0
        obj.setOwner(ctx);
    }

	
    public Monitor ensureMonitor(Oop _obj) throws PragmaAtomic {
	FastLockable obj = (FastLockable) _obj.asAnyOop();
	Monitor ret = obj.getMonitor();
	if (ret == null) {
	    Context owner = obj.getOwner();
	    int rc = obj.getRecursionCount();
	    ret = super.ensureMonitor(obj);
	    if (owner != null) {
//                 BasicIO.out.println("ensureMonitor: inflating owned monitor");
		OVMThread t = ((OVMThreadContext) owner).getThread();
		do {
		    ret.enter(t);
		} while (rc-- > 0);
	    }
            else {
//                 BasicIO.out.println("ensureMonitor: inflating unowned monitor");
            }
	}
	return ret;
    }

    // override to avoid unnecessary inflation as we do not want allocation
    // to occur unnecessarily during thread finalization.
    public boolean currentThreadOwnsMonitor(Oop _obj) {
	FastLockable obj = (FastLockable) _obj.asAnyOop();
        // explicitly check for inflation so that a false answer to isMine
        // doesn't force inflation through the super call
        if (!obj.isInflated())
            return obj.isMine();
        else
            return super.currentThreadOwnsMonitor(_obj);
    }


    public Monitor aliasMonitor(Oop obj) {
	return new ForwardingJavaMonitor(this, obj);
    }

    public void monitorExitSlow(FastLockable obj) throws PragmaNoInline {
	if (obj.isMine()) {
	    obj.setRecursionCount(obj.getRecursionCount() - 1);
	} else {
	    super.monitorExit(obj);
	}
    }

    public void monitorExit(Oop _obj) throws PragmaInline, PragmaNoPollcheck {
	FastLockable obj = (FastLockable) _obj.asAnyOop();
	if (!obj.fastUnlock())
	    monitorExitSlow(obj);
    }

    public void monitorSignal(Oop _obj) {
	FastLockable obj = (FastLockable) _obj.asAnyOop();
	if (!obj.isMine())
	    super.monitorSignal(obj);
    }

    public void monitorSignalAll(Oop _obj) {
	FastLockable obj = (FastLockable) _obj.asAnyOop();
	if (!obj.isMine())
	    super.monitorSignalAll(obj);
    }

    protected FastLockCoreServicesAccess(S3Domain d) {
	super(d);
    }

    static public class FLFactory extends Factory {
	public CoreServicesAccess make(Domain d) {
	    return new FastLockCoreServicesAccess((S3Domain)d);
	}
    }

}
