package s3.services.j2c;
import ovm.core.execution.Activation;
import ovm.core.execution.Context;
import ovm.core.execution.CoreServicesAccess;
import ovm.core.repository.*;
import ovm.core.services.memory.VM_Address;
import ovm.core.domain.Code;
import ovm.core.domain.Domain;
import ovm.core.domain.LinkageException;
import ovm.core.domain.Oop;
import ovm.core.domain.WildcardException;
import ovm.services.bytecode.JVMConstants.Throwables;
import ovm.util.UnsafeAccess;
import s3.core.domain.S3Method;
import s3.core.domain.S3Code;
import s3.core.domain.S3ByteCode;
import s3.util.PragmaTransformCallsiteIR.BCdead;

class J2cCodeFragment extends S3Code implements UnsafeAccess {
    public static final Code.Kind KIND = new Code.Kind() { };
    
    static VM_Address[] ranges = new VM_Address[0];
    static J2cCodeFragment[] frags = new J2cCodeFragment[0];

    String cname;
    char rtype;			// simplify c++ code
    int index = -1;
    int startingLine;

    // Code fragments are allocated at boot time, and should not drag
    // ovm.core.services.format into the image
    J2cCodeFragment(S3Method m, int index)
	throws BCdead
    {
	super(m);
	this.cname = J2cFormat.format(m);
	this.index = index;
	Code bc = m.getCode(S3ByteCode.KIND);
	startingLine = bc.getLineNumber(0);
	try { rtype = m.getReturnType().getUnrefinedName().getTypeTag(); }
	catch (LinkageException e) { throw e.unchecked(); }
    }

    VM_Address getEntryPoint() {
	return index == -1 ? VM_Address.fromObject(null) : ranges[index<<1];
    }


    static J2cCodeFragment fromPC(int _pc)
    {
	VM_Address pc = VM_Address.fromInt(_pc);
	int start = 0;
	int range = ranges.length;

	// FIXME: we should only return null if pc is before the first
	// range or after the last range.
	// FIXME some more: end pcs aren't being set, so we can't tell
	// whether a pc is in the last method we generate or some
	// library function.
	while (true) {
	    // find the middle PAIR of integers
	    int i = start + ((range/2) & ~1);
	    if (ranges[i].uLE(pc))
		if (ranges[i+1].uGT(pc))
		    return frags[i/2];
		else {
		    range -= (i+2 - start);
		    start = i+2;
		}
	    else
		range = i - start;
	    if (range == 0)
		return null;
	}
    }

    public void bang(ovm.core.domain.Code c) {
	throw new Error("can not bang J2c code: not implemented yet");
    }

    public Kind getKind() { return KIND; }

    public byte[] getBytes() { return null; }
	
    public int getLineNumber(int pc) {
	return startingLine;
    }
    public Attribute[] getAttributes() {
	return new Attribute[0];
    }
    /* explicitly maintain lock in code, make inlining easier */
    public boolean isSynchronized() { return false; }
    public ExceptionHandler[] getExceptionHandlers() {
	throw new Error("exception handlers not exposed");
    }
    public ConstantPool getConstantPool() {
	throw new Error("who wants to know");
    }

    private static void throwWildcardException(Oop ex) {
	Context ctx = Context.getCurrentContext();
	throw (WildcardException) ctx.makeWildcardException(ex);
    }

    private static void generateThrowable(int ex) {
	Activation act = Context.getCurrentContext().getCurrentActivation();
	act = act.caller(act);
	Code code = act.getCode();
	Domain d = code.getMethod().getDeclaringType().getDomain();
	CoreServicesAccess csa = d.getCoreServicesAccess();
	csa.generateThrowable(ex, 0);
    }
}
