package s3.services.simplejit.ir;

import ovm.core.repository.TypeCodes;
import ovm.util.ArrayList;
import ovm.util.HashMap;
import ovm.util.Iterator;
import s3.services.simplejit.util.SimpleJITIdentitySet;

public class SimpleJITOperand {

    protected SimpleJITOperand() {
    }

    public boolean isTemporaryDefOperand() {
	return this instanceof SimpleJITTemporaryDefOperand;
    }
    public boolean isTemporaryUseOperand() {
	return this instanceof SimpleJITTemporaryUseOperand;
    }
    public SimpleJITTemporaryDefOperand asTemporaryDefOperand() {
	return (SimpleJITTemporaryDefOperand)this;
    }
    public SimpleJITTemporaryUseOperand asTemporaryUseOperand() {
	return (SimpleJITTemporaryUseOperand)this;
    }

    public boolean isStackTemporaryOperand() {
	return this instanceof SimpleJITStackTemporaryOperand;
    }
    public boolean isLocalTemporaryOperand() {
	return this instanceof SimpleJITLocalTemporaryOperand;
    }
    public SimpleJITStackTemporaryOperand asStackTemporaryOperand() {
	return (SimpleJITStackTemporaryOperand)this;
    }
    public SimpleJITLocalTemporaryOperand asLocalTemporaryOperand() {
	return (SimpleJITLocalTemporaryOperand)this;
    }

    static final String[] cptag2name =
	new String[] {
	    "invalid", //0
	    "Utf8",    //1
	    "invalid", //2
	    "Integer", //3
	    "Float",   //4
	    "Long",    //5
	    "Double",  //6
	    "Class",   //7
	    "String",  //8
	    "Fieldref", //9
	    "Methodref", //10
	    "InterfaceMethodref", //11
	    "NameAndType", //12
	    "Reference", //13
	    "SharedState", //14
	    "Binder", //15
	    "ResolvedClass", //16
	};

    public static class SimpleJITConstantReferenceOperand 
	extends SimpleJITReferenceOperand {
	int cpindex;
	byte cptag;
	public SimpleJITConstantReferenceOperand(int cpindex,
						 byte cptag) {
	    this.cpindex = cpindex;
	    this.cptag = cptag;
	}
	public String toString() {
	    return "[CP," + cpindex + "," + cptag2name[(int)cptag] + "]";
	}
    }

    public static class SimpleJITIntOperand extends SimpleJITOperand {
	int constantValue;
	public SimpleJITIntOperand(int c) {
	    constantValue = c;
	}
	public String toString() {
	    return Integer.toString(constantValue) + "I";
	}
    }
    public static class SimpleJITLongOperand extends SimpleJITOperand {
	long constantValue;
	public SimpleJITLongOperand(long c) {
	    constantValue = c;
	}
	public String toString() {
	    return Long.toString(constantValue) + "L";
	}
    }
    public static class SimpleJITFloatOperand extends SimpleJITOperand {
	float constantValue;
	public SimpleJITFloatOperand(float c) {
	    constantValue = c;
	}
	public String toString() {
	    return Float.toString(constantValue) + "F";
	}
    }
    public static class SimpleJITDoubleOperand extends SimpleJITOperand {
	double constantValue;
	public SimpleJITDoubleOperand(double c) {
	    constantValue = c;
	}
	public String toString() {
	    return Double.toString(constantValue) + "D";
	}
    }

    public static class SimpleJITReferenceOperand 
	extends SimpleJITOperand {
	public String toString() {
	    return "Reference";
	}
    }

    public static class SimpleJITNullReferenceOperand 
	extends SimpleJITReferenceOperand {
	public String toString() {
	    return "Null";
	}
    }

    public static class SimpleJITReturnAddressOperand 
	extends SimpleJITOperand {
	public String toString() {
	    return "ReturnAddress";
	}
    }

    public static class TemporaryFactory {
	protected static class TemporaryKey {
	    private char typeCode;
	    private int index;
	    private TemporaryKey(char typeCode, int index) {
		this.typeCode = typeCode;
		this.index = index;
	    }
	    public boolean equals(Object other) {
		if (other == null)
		    return false;
		if (! (other instanceof TemporaryKey))
		    return false;
		TemporaryKey tkother = (TemporaryKey)other;
		return this.typeCode == tkother.typeCode
		    && this.index == tkother.index;
	    }
	    public String toString() {
		return "[TK, " + typeCode + ", " + index + "]";
	    }
	    public int hashCode() {
		return (index << 16) + (int)typeCode;
	    }
	}
	private HashMap 
	    stackTemporaryInternTable = new HashMap();
	public SimpleJITStackTemporaryOperand 
	    createStackTemporary(char typeCode,
				 int index) {
	    TemporaryKey key = new TemporaryKey(typeCode, index);
	    Object value = stackTemporaryInternTable.get(key);
	    if (value == null) {
		SimpleJITStackTemporaryOperand sto =
		    new SimpleJITStackTemporaryOperand(typeCode, index);
		stackTemporaryInternTable.put(key, sto);
		return sto;
	    } else {
		return (SimpleJITStackTemporaryOperand)value;
	    }
	}
	private HashMap 
	    localTemporaryInternTable = new HashMap();
	public SimpleJITLocalTemporaryOperand 
	    createLocalTemporary(char typeCode, 
				 int index) {
	    TemporaryKey key = new TemporaryKey(typeCode, index);
	    Object value = localTemporaryInternTable.get(key);
	    if (value == null) {
		SimpleJITLocalTemporaryOperand lto =
		    new SimpleJITLocalTemporaryOperand(typeCode, index);
		localTemporaryInternTable.put(key, lto);
		return lto;
	    } else {
		return (SimpleJITLocalTemporaryOperand)value;
	    }
	}
    }

    public abstract static class SimpleJITTemporaryOperand 
	extends SimpleJITOperand {
	private static int tempIDCounter = 0;
	protected char typeCode;
	protected int ID;
	protected SimpleJITTemporaryOperand(char typeCode) {
	    this.typeCode = typeCode;
	    ID = tempIDCounter++;
	}
	public char getTypeCode() {
	    return typeCode;
	}
	public abstract boolean equals(Object other);
	public abstract boolean equalsExceptType
	    (SimpleJITTemporaryOperand other);
	public abstract SimpleJITTemporaryOperand
	    copyWithNewTypeCode(TemporaryFactory tempFactory,
				char typeCode);
    }

    public static class SimpleJITStackTemporaryOperand 
	extends SimpleJITTemporaryOperand {
	int index;
	protected String name;
	private SimpleJITStackTemporaryOperand(char typeCode,
					      int index) {
	    super(typeCode);
	    name = "S" + index;
	    this.index = index;
	}
	public int getIndex() {
	    return index;
	}
	public String toString() {
	    //return name + "(" + typeCode + ")" + "[" +  ID + "]";
	    return name + "(" + typeCode + ")";
	}
	public boolean equals(Object other) {
	    if (other == null)
		return false;
	    if (! (other instanceof SimpleJITStackTemporaryOperand))
		return false;
	    SimpleJITStackTemporaryOperand stother =
		(SimpleJITStackTemporaryOperand)other;
	    return this.index == stother.index
		&& this.typeCode == stother.typeCode;
	}
	public boolean equalsExceptType(SimpleJITTemporaryOperand other) {
	    if (other == null)
		return false;
	    if (! (other instanceof SimpleJITStackTemporaryOperand))
		return false;
	    SimpleJITStackTemporaryOperand stother =
		(SimpleJITStackTemporaryOperand)other;
	    return this.index == stother.index;
	}
	public int hashCode() {
	    throw new Error();
	}
	public SimpleJITTemporaryOperand
	    copyWithNewTypeCode(TemporaryFactory tempFactory,
				char typeCode) {
	    return tempFactory
		.createStackTemporary(typeCode, this.index);
	}
    }

    public static class SimpleJITLocalTemporaryOperand 
	extends SimpleJITTemporaryOperand {
	int index;
	protected String name;
	private SimpleJITLocalTemporaryOperand(char typeCode,
					      int index) {
	    super(typeCode);
	    name = "L" + index;
	    this.index = index;
	}
	public int getIndex() {
	    return index;
	}
	public String toString() {
	    //return name + "(" + typeCode + ")" + "[" +  ID + "]";
	    return name + "(" + typeCode + ")";
	}
	public boolean equals(Object other) {
	    if (other == null)
		return false;
	    if (! (other instanceof SimpleJITLocalTemporaryOperand))
		return false;
	    SimpleJITLocalTemporaryOperand lother =
		(SimpleJITLocalTemporaryOperand)other;
	    return this.index == lother.index
		&& this.typeCode == lother.typeCode;
	}
	public boolean equalsExceptType(SimpleJITTemporaryOperand other) {
	    if (other == null)
		return false;
	    if (! (other instanceof SimpleJITLocalTemporaryOperand))
		return false;
	    SimpleJITLocalTemporaryOperand lother =
		(SimpleJITLocalTemporaryOperand)other;
	    return this.index == lother.index;
	}
	public int hashCode() {
	    throw new Error();
	}
	public SimpleJITTemporaryOperand
	    copyWithNewTypeCode(TemporaryFactory tempFactory,
				char typeCode) {
	    return tempFactory
		.createLocalTemporary(typeCode, this.index);
	}
    }


    public static class VirtualRegisterFactory {
	protected static class VirtualRegisterKey {
	    private int index;
    	    private char typeCode;
 	    private VirtualRegisterKey(char typeCode,
 				       int index) {
 		this.typeCode = typeCode;
 		this.index = index;
 	    }
	    public boolean equals(Object other) {
		if (other == null)
		    return false;
		if (! (other instanceof VirtualRegisterKey))
		    return false;
		VirtualRegisterKey tkother = 
		    (VirtualRegisterKey)other;
		return this.index == tkother.index
		    && this.typeCode == tkother.typeCode;
	    }
	    public String toString() {
		return "[VRK, " + typeCode + "," + index + "]";
	    }
	    public int hashCode() {
		return (index << 16) + typeCode;
	    }
	}
	private HashMap virtualRegisterInternTable = new HashMap();
 	public SimpleJITVirtualRegisterOperand 
 	    create(char typeCode, int index) {
	    synchronized(virtualRegisterInternTable) {
		VirtualRegisterKey key = 
		    new VirtualRegisterKey(typeCode, index);
		Object value = virtualRegisterInternTable.get(key);
		if (value == null) {
		    SimpleJITVirtualRegisterOperand sto =
			new SimpleJITVirtualRegisterOperand(typeCode, index);
		    virtualRegisterInternTable.put(key, sto);
		    return sto;
		} else {
		    return (SimpleJITVirtualRegisterOperand)value;
		}
	    }
 	}
	/**
	 * Swap the indices of the two specified virtual
	 * registers. This is used by the graph coloring allocator so
	 * that the final register table can be sorted. This method is
	 * not thread safe.
	 */
	public void swapVirtualRegisterIndices
	    (char typeCode, int index1, int index2) {
	    if (index1 == index2)
		return;
	    synchronized(virtualRegisterInternTable) {
		VirtualRegisterKey key1 = 
		    new VirtualRegisterKey(typeCode, index1);
		VirtualRegisterKey key2 = 
		    new VirtualRegisterKey(typeCode, index2);
		SimpleJITVirtualRegisterOperand vr1 = 
		    (SimpleJITVirtualRegisterOperand)
		    virtualRegisterInternTable.get(key1);
		SimpleJITVirtualRegisterOperand vr2 = 
		    (SimpleJITVirtualRegisterOperand)
		    virtualRegisterInternTable.get(key2);
		if (vr1 == null || vr2 == null)
		    throw new Error();
		vr1.setIndex(index2);
		vr2.setIndex(index1);
		virtualRegisterInternTable.put(key1, vr2);
		virtualRegisterInternTable.put(key2, vr1);
	    }
	}
    }

    public static class SimpleJITVirtualRegisterOperand 
	extends SimpleJITOperand {
	private static int IDcounter = 0;
	protected int index;
	protected char typeCode;
	protected int weightedRefCount;
	protected SimpleJITIdentitySet interferers;
	protected int ID;
  	private SimpleJITVirtualRegisterOperand(char typeCode,
  						int index) {
  	    this.typeCode = typeCode;
  	    this.index = index;
	    interferers = new SimpleJITIdentitySet();
	    ID = IDcounter++;
  	}
	public char getTypeCode() {
	    return typeCode;
	}
	public void setWeightedRefCount(int wrc) {
	    weightedRefCount = wrc;
	}
	public int getWeightedRefCount() {
	    return weightedRefCount;
	}
	public boolean equals(Object other) {
	    if (other == null)
		return false;
	    if (! (other instanceof SimpleJITVirtualRegisterOperand))
		return false;
	    SimpleJITVirtualRegisterOperand tkother = 
		(SimpleJITVirtualRegisterOperand)other;
	    return this.index == tkother.index
		&& this.typeCode == tkother.typeCode;
	}
	public int hashCode() {
	    return (index << 16) + typeCode;
	}
	public String toString() {
	    return "V" + index + "(" + typeCode + ")";
	}
	public String toSimpleString() {
	    return "V" + index;
	}
	public int getIndex() {
	    return index;
	}
	public void setIndex(int idx) {
	    index = idx;
	}
	public String getInterferersAsString() {
	    String interferersList = "{ ";
	    for(Iterator it = interferers.iterator();
		it.hasNext(); ) {
		SimpleJITVirtualRegisterOperand v =
		    (SimpleJITVirtualRegisterOperand)it.next();
		interferersList += v.toString() + " ";
	    }
	    interferersList += "}";
	    return interferersList;
	}
	public SimpleJITIdentitySet getInterferers() {
	    return interferers.copy();
	}
	public void setInterferers(SimpleJITIdentitySet s) {
	    interferers = s.copy();
	}
    }

    public static class SimpleJITWebTemporaryOperand 
	extends SimpleJITOperand {
	private static final boolean TOSTRING_AS_VREG = false;
	private static int webIDCounter = 0;
	protected char typeCode;
	protected int ID;
	protected SimpleJITIdentitySet defuses;
	protected SimpleJITIdentitySet interferers;
	protected int refCount;
	protected int weightedRefCount;
	protected SimpleJITVirtualRegisterOperand vreg;

	/** Used by the graph coloring reg allocator*/
	protected SimpleJITIdentitySet scratch_interferers;
	protected SimpleJITVirtualRegisterOperand scratch_vreg;
	protected boolean potentialSpill = false;

	public SimpleJITWebTemporaryOperand(char typeCode) {
	    this.typeCode = typeCode;
	    ID = webIDCounter++;
	    interferers = new SimpleJITIdentitySet();
	}
	public void merge(SimpleJITWebTemporaryOperand other) {
	    if (typeCode != other.typeCode)
		throw new Error();
	    SimpleJITWebTemporaryOperand w =
		new SimpleJITWebTemporaryOperand(typeCode);
	    interferers.union(other.interferers);
	    defuses.union(other.defuses);
	    refCount += other.refCount;
	    weightedRefCount += other.weightedRefCount;
	}
	public char getTypeCode() {
	    return typeCode;
	}
	public void setTypeCode(char tc) {
	    typeCode = tc;
	}
	public boolean equals(Object other) {
	    return this == other;
	}
	public void setVirtualRegister(SimpleJITVirtualRegisterOperand vro) {
	    vreg = vro;
	}
	public SimpleJITVirtualRegisterOperand getVirtualRegister() {
	    return vreg;
	}
	public String getInterferersAsString() {
	    String interferersList = "{ ";
	    for(Iterator it = interferers.iterator();
		it.hasNext(); ) {
		SimpleJITWebTemporaryOperand w =
		    (SimpleJITWebTemporaryOperand)it.next();
		try {
		    interferersList += w.toSimpleString() + " ";
		}catch(Exception e) {
		    System.err.println("Web " + w + " does not have register");
		    e.printStackTrace();
		}
	    }
	    interferersList += "}";
	    return interferersList;
	}
	public String getVirtualRegisterAsString() {
	    return vreg.toString();
	}
	public String toStringAsVirtualRegister() {
	    return "" + vreg;
	}
	public String toSimpleString() {
	    if (TOSTRING_AS_VREG)
		return "" + vreg;
	    else
		return "W" + ID;
	}
	public String toString() {
	    if (TOSTRING_AS_VREG)
		return "" + vreg;
	    else
		return "W" + ID + "(" + typeCode + ")";
	}
	public SimpleJITIdentitySet getDefUses() {
	    return defuses.copy();
	}
	public void setRefCount(int rc) {
	    refCount = rc;
	}
	public int getRefCount() {
	    return refCount;
	}
	public void setWeightedRefCount(int wrc) {
	    weightedRefCount = wrc;
	}
	public int getWeightedRefCount() {
	    return weightedRefCount;
	}
	public void setDefUses(SimpleJITIdentitySet s) {
	    defuses = s.copy();
	}
	public SimpleJITIdentitySet getInterferers() {
	    return interferers.copy();
	}
	public void addInterferer(SimpleJITWebTemporaryOperand w) {
	    if (this != w)
		interferers.add(w);
	}
	public void removeInterferer(SimpleJITWebTemporaryOperand w) {
	    interferers.remove(w);
	}
	public void setInterferers(SimpleJITIdentitySet s) {
	    interferers = s.copy();
	}

	public void copyInterferersToScatch() {
	    scratch_interferers = interferers.copy();
	}

	/**
	 * Copy the original interefer set to the scatch interefer
	 * set, but only copy the interfering webs in the given web
	 * set. Used by the graph coloring allocator.
	 */
	public void copyInterferersToScatchForSubset
	    (SimpleJITIdentitySet webs) {
	    scratch_interferers = new SimpleJITIdentitySet();
	    for(Iterator it = interferers.iterator();
		it.hasNext();) {
		SimpleJITWebTemporaryOperand w = 
		    (SimpleJITWebTemporaryOperand)it.next();
		if (webs.contains(w)) {
		    scratch_interferers.add(w);
		}
	    }
	}

	public void setScratchVirtualRegister
	    (SimpleJITVirtualRegisterOperand vr) {
	    scratch_vreg = vr;
	}
	public SimpleJITVirtualRegisterOperand 
	    getScratchVirtualRegister() {
	    return scratch_vreg;
	}
	public SimpleJITIdentitySet getScratchInterferers() {
	    return scratch_interferers; // no copying
	}
	public void addScatchInterferer(SimpleJITWebTemporaryOperand w) {
	    if (this != w)
		scratch_interferers.add(w);
	}
	public void removeScatchInterferer(SimpleJITWebTemporaryOperand w) {
	    scratch_interferers.remove(w);
	}
	public void setScratchInterferers(SimpleJITIdentitySet s) {
	    scratch_interferers = s.copy();
	}

	public void setPotentialSpillFlag(boolean f) {
	    potentialSpill = f;
	}
	public boolean isPotentialSpill() {
	    return potentialSpill;
	}

	public static class Set {
	    private SimpleJITIdentitySet internal;
	    private char typeCode;
	    public Set(char typeCode) {
		internal = new SimpleJITIdentitySet();
		this.typeCode = typeCode;
	    }
	    public void add(SimpleJITWebTemporaryOperand w) {
		if (w.getTypeCode() != typeCode)
		    throw new Error();
		internal.add(w);
	    }
	    public Iterator iterator() {
		return internal.iterator();
	    }
	    public boolean contains(SimpleJITWebTemporaryOperand w) {
		return internal.contains(w);
	    }
	    public int getWeightedRefCount() {
		int rc = 0;
		for(Iterator it = internal.iterator();
		    it.hasNext(); ) {
		    SimpleJITWebTemporaryOperand w =
			(SimpleJITWebTemporaryOperand)it.next();
		    rc += w.getWeightedRefCount();
		}
		return rc;
	    }
	    public char getTypeCode() {
		return typeCode;
	    }
	    public void setVirtualRegister
		(SimpleJITVirtualRegisterOperand vreg) {
		for(Iterator it = internal.iterator();
		    it.hasNext(); ) {
		    SimpleJITWebTemporaryOperand w =
			(SimpleJITWebTemporaryOperand)it.next();
		    w.setVirtualRegister(vreg);
		}
	    }
	    public SimpleJITVirtualRegisterOperand 
		getVirtualRegister() {
		SimpleJITVirtualRegisterOperand reg = null;
		for(Iterator it = internal.iterator();
		    it.hasNext(); ) {
		    SimpleJITWebTemporaryOperand w =
			(SimpleJITWebTemporaryOperand)it.next();
		    if (reg == null)
			reg = w.getVirtualRegister();
		    else {
			if (reg != w.getVirtualRegister())
			    throw new Error
				("Different vreg in the same web set");
			reg = w.getVirtualRegister();
		    }
		}
		return reg;
	    }
	    public String toStringAsVirtualRegister() {
		Iterator it = internal.iterator();
		if (it.hasNext()) {
		    SimpleJITWebTemporaryOperand w =
			    (SimpleJITWebTemporaryOperand)it.next();
		    return w.toStringAsVirtualRegister();
		} else {
		    return "EMPTY_WEB_SET";
		}
	    }
	    public String toString() {
		if (TOSTRING_AS_VREG) {
		    Iterator it = internal.iterator();
		    if (it.hasNext()) {
			SimpleJITWebTemporaryOperand w =
			    (SimpleJITWebTemporaryOperand)it.next();
			return w.toSimpleString();
		    } else {
			return "EMPTY_WEB_SET";
		    }
		} else {
		    String ret = "[ ";
		    for(Iterator it = internal.iterator();
			it.hasNext(); ) {
			SimpleJITWebTemporaryOperand w =
			    (SimpleJITWebTemporaryOperand)it.next();
			ret += w.toSimpleString() + " ";
		    }
		    ret += "]";
		    return ret;
		}
	    }
	    public SimpleJITIdentitySet getInterferers() {
		SimpleJITIdentitySet interfererSet = 
		    new SimpleJITIdentitySet();
		for(Iterator it0 = internal.iterator();
		    it0.hasNext(); ) {
		    SimpleJITWebTemporaryOperand w0 =
			(SimpleJITWebTemporaryOperand)it0.next();
		    SimpleJITIdentitySet interferers = 
			w0.getInterferers();
		    interfererSet.union(interferers);
		}
		return interfererSet;
	    }
	    public String getInterferersAsVirtualRegisterAsString() {
		SimpleJITIdentitySet interfererVRegSet =
		    new SimpleJITIdentitySet();
		for(Iterator it0 = internal.iterator();
		    it0.hasNext(); ) {
		    SimpleJITWebTemporaryOperand w0 =
			(SimpleJITWebTemporaryOperand)it0.next();
		    SimpleJITIdentitySet interferers = 
			w0.getInterferers();
		    for(Iterator it1 = interferers.iterator();
			it1.hasNext(); ) {
			SimpleJITWebTemporaryOperand w1 =
			    (SimpleJITWebTemporaryOperand)it1.next();
			interfererVRegSet.add(w1.getVirtualRegister());
		    }
		}
		String interferersVRegList = "{ ";
		for(Iterator it = interfererVRegSet.iterator();
		    it.hasNext(); ) {
		    SimpleJITVirtualRegisterOperand v =
			(SimpleJITVirtualRegisterOperand)it.next();
		    interferersVRegList += v.toString() + " ";
		}
		interferersVRegList += "}";
		return interferersVRegList;
	    }

	    public SimpleJITIdentitySet 
		getInterferersAsVirtualRegisters() {
		SimpleJITIdentitySet interfererVRegSet =
		    new SimpleJITIdentitySet();
		for(Iterator it0 = internal.iterator();
		    it0.hasNext(); ) {
		    SimpleJITWebTemporaryOperand w0 =
			(SimpleJITWebTemporaryOperand)it0.next();
		    SimpleJITIdentitySet interferers = 
			w0.getInterferers();
		    for(Iterator it1 = interferers.iterator();
			it1.hasNext(); ) {
			SimpleJITWebTemporaryOperand w1 =
			    (SimpleJITWebTemporaryOperand)it1.next();
			interfererVRegSet.add(w1.getVirtualRegister());
		    }
		}
		return interfererVRegSet;
	    }

	    public String getInterferersAsString() {
		SimpleJITIdentitySet interfererSet = 
		    new SimpleJITIdentitySet();
		SimpleJITIdentitySet interfererVRegSet =
		    new SimpleJITIdentitySet();
		for(Iterator it0 = internal.iterator();
		    it0.hasNext(); ) {
		    SimpleJITWebTemporaryOperand w0 =
			(SimpleJITWebTemporaryOperand)it0.next();
		    SimpleJITIdentitySet interferers = 
			w0.getInterferers();
		    for(Iterator it1 = interferers.iterator();
			it1.hasNext(); ) {
			SimpleJITWebTemporaryOperand w1 =
			    (SimpleJITWebTemporaryOperand)it1.next();
			interfererSet.add(w1);
			interfererVRegSet.add(w1.getVirtualRegister());
		    }
		}
		if (TOSTRING_AS_VREG) {
		    String interferersVRegList = "{ ";
		    for(Iterator it = interfererVRegSet.iterator();
			it.hasNext(); ) {
			SimpleJITVirtualRegisterOperand v =
			    (SimpleJITVirtualRegisterOperand)it.next();
			interferersVRegList += v.toString() + " ";
		    }
		    interferersVRegList += "}";
		    return interferersVRegList;
		} else {
		    String interferersList = "{ ";
		    for(Iterator it = interfererSet.iterator();
			it.hasNext(); ) {
			SimpleJITWebTemporaryOperand w =
			    (SimpleJITWebTemporaryOperand)it.next();
			interferersList += w.toSimpleString() + " ";
		    }
		    interferersList += "}";
		    return interferersList;
		}
	    }
	}
    }

    public abstract static class SimpleJITTemporaryWrapperOperand
	extends SimpleJITOperand {
	protected static final boolean TOSTRING_AS_WEB = true;
	protected static int IDCounter = 0;

	protected SimpleJITTemporaryOperand temporary;
	protected int ID;
	protected SimpleJITWebTemporaryOperand web;
	protected SimpleJITBasicBlock enclosingBlock;
	protected SimpleJITTemporaryWrapperOperand
	    (SimpleJITTemporaryOperand t,
	     SimpleJITBasicBlock block) {
	    ID = IDCounter++;
	    temporary = t;
	    web = null;
	    enclosingBlock = block;
	}
	public int getLoopDepth() {
	    return enclosingBlock.getLoopDepth();
	}
	public SimpleJITTemporaryOperand getTemporary() {
	    return temporary;
	}
	public SimpleJITWebTemporaryOperand getWeb() {
	    return web;
	}
	public void setWeb(SimpleJITWebTemporaryOperand web) {
	    this.web = web;
	}
	public abstract boolean 
	    equalsAsTemporary
	    (SimpleJITTemporaryWrapperOperand o);
	public abstract boolean 
	    equalsAsTemporaryExceptType
	    (SimpleJITTemporaryWrapperOperand o);
    }

    public static class SimpleJITTemporaryDefOperand
	extends SimpleJITTemporaryWrapperOperand {

	// Don't define hashCode or equals so that it works in HashSet as
	// in IdentityHashSet

	private ArrayList useList; // du-chain
	public SimpleJITTemporaryDefOperand(SimpleJITTemporaryOperand t,
					    SimpleJITBasicBlock block) {
	    super(t, block);
	    useList = new ArrayList();
	}
	public void addUse(SimpleJITTemporaryUseOperand u) {
	    useList.add(u);
	}
	public int getUseSize() {
	    return useList.size();
	}
	public SimpleJITTemporaryUseOperand[] getUses() {
	    int size = useList.size();
	    SimpleJITTemporaryUseOperand[] uses = 
		new SimpleJITTemporaryUseOperand[size];
	    for(int i = 0; i < size; i++) {
		uses[i] = (SimpleJITTemporaryUseOperand)useList.get(i);
	    }
	    return uses;
	}
	public boolean equalsAsTemporary
	    (SimpleJITTemporaryWrapperOperand other) {
	    if (other == null)
		return false;
	    return this.temporary.equals(other.temporary);
	}
	public boolean equalsAsTemporaryExceptType
	    (SimpleJITTemporaryWrapperOperand other) {
	    if (other == null)
		return false;
	    return this.temporary.equalsExceptType(other.temporary);
	}
	public int getID() {
	    return ID;
	}
	public String toSimpleString() {
	    return "D" + ID;
	}
	public String toString() {
	    if (TOSTRING_AS_WEB &&
		web != null) {
		return web.toString();
	    }
	    String us = "(";
	    int size = useList.size();
	    for(int i = 0; i < size; i++) {
		String suffix = null;
		if (i == size - 1)
		    suffix = "";
		else
		    suffix = ",";
		us += ((SimpleJITTemporaryUseOperand)useList.get(i))
		    .toSimpleString() + suffix;
	    }
	    us += ")";
	    return "D" + ID + "[" + temporary + "," 
		+ web + "," + us + "]";
	}
    }

    public static class SimpleJITTemporaryUseOperand
	extends SimpleJITTemporaryWrapperOperand {

	// Don't define hashCode or equals so that it works in HashSet as
	// in IdentityHashSet

	private ArrayList defList; // ud-chain
	public SimpleJITTemporaryUseOperand(SimpleJITTemporaryOperand t,
					    SimpleJITBasicBlock block) {
	    super(t, block);
	    defList = new ArrayList();
	}
	public void addDef(SimpleJITTemporaryDefOperand d) {
	    defList.add(d);
	}
	public int getDefSize() {
	    return defList.size();
	}
	public SimpleJITTemporaryDefOperand[] getDefs() {
	    int size = defList.size();
	    SimpleJITTemporaryDefOperand[] defs = 
		new SimpleJITTemporaryDefOperand[size];
	    for(int i = 0; i < size; i++) {
		defs[i] = (SimpleJITTemporaryDefOperand)defList.get(i);
	    }
	    return defs;
	}
	public boolean equalsAsTemporaryExceptType
	    (SimpleJITTemporaryWrapperOperand other) {
	    if (other == null)
		return false;
	    return this.temporary.equalsExceptType(other.temporary);
	}
	public boolean equalsAsTemporary
	    (SimpleJITTemporaryWrapperOperand other) {
	    if (other == null)
		return false;
	    return this.temporary.equals(other.temporary);
	}
	public int getID() {
	    return ID;
	}
	public String toSimpleString() {
	    return "U" + ID;
	}
	public String toString() {
	    if (TOSTRING_AS_WEB
		&& web != null) {
		return web.toString();
	    }
	    String ds = "(";
	    int size = defList.size();
	    for(int i = 0; i < size; i++) {
		String suffix = null;
		if (i == size - 1)
		    suffix = "";
		else
		    suffix = ",";
		ds += ((SimpleJITTemporaryDefOperand)defList.get(i))
		    .toSimpleString() + suffix;
	    }
	    ds += ")";
	    return "U" + ID + "[" + temporary + "," + web + "," + ds + "]";
	}
    }

    public static class SimpleJITBranchOperand extends SimpleJITOperand {
	SimpleJITBasicBlock block;
	public SimpleJITBranchOperand(SimpleJITBasicBlock block) {
	    this.block = block;
	}
	public static SimpleJITBranchOperand[] 
	    blocks2BranchOperands(SimpleJITBasicBlock[] blocks) {
	    SimpleJITBranchOperand[] ret 
		= new SimpleJITBranchOperand[blocks.length];
	    for(int i = 0; i < ret.length; i++)
		ret[i] = new SimpleJITBranchOperand(blocks[i]);
	    return ret;
	}
	public SimpleJITBasicBlock getBlock() {
	    return block;
	}
	public void setBlock(SimpleJITBasicBlock newblock) {
	    block = newblock;
	}
	public String toString() {
	    return "BRANCH(" + block.toString() + ")";
	}
    }

    public static class SimpleJITConditionOperand 
	extends SimpleJITOperand {
	final static SimpleJITConditionOperand _eq = new SimpleJITConditionOperand("EQ");
	final static SimpleJITConditionOperand _ne = new SimpleJITConditionOperand("NE");
	final static SimpleJITConditionOperand _lt = new SimpleJITConditionOperand("LT");
	final static SimpleJITConditionOperand _ge = new SimpleJITConditionOperand("GE");
	final static SimpleJITConditionOperand _gt = new SimpleJITConditionOperand("GT");
	final static SimpleJITConditionOperand _le = new SimpleJITConditionOperand("LE");

	String name;
	private SimpleJITConditionOperand(String name) {
	    this.name = name;
	}
	public String toString() {
	    return name;
	}

	public static SimpleJITConditionOperand eq() { return _eq; }
	public static SimpleJITConditionOperand ne() { return _ne; }
	public static SimpleJITConditionOperand lt() { return _lt; }
	public static SimpleJITConditionOperand ge() { return _ge; }
	public static SimpleJITConditionOperand gt() { return _gt; }
	public static SimpleJITConditionOperand le() { return _le; }
    }

    public static class Stack {
	private SimpleJITOperand[] items;
	private int top;
	public Stack(int capacity) {
	    items = new SimpleJITOperand[capacity];
	    top = -1;
	}
	public String toString() {
	    String s = "OpStack height = " + top + "\n";
	    for(int i = 0; i < top; i++) {
		s += "\t[" + i + "] = " + items[i] + "\n";
	    }
	    return s;
	}
	public Stack copy() {
	    Stack s = new Stack(this.items.length);
	    s.top = this.top;
	    for(int i = 0; i < s.items.length; i++) {
		s.items[i] = this.items[i];
	    }
	    return s;
	}
	public void clear() {
	    top = -1;
	    for(int i = 0; i < items.length; i++)
		items[i] = null;
	}
	public void dup_x1() {
	    try {
		items[top + 1] = items[top];
		items[top] = items[top - 1];
		items[top - 1] = items[top + 1];
		top++;
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack overflow");
	    }
	}
	public void dup_x2() {
	    try {
		items[top + 1] = items[top];
		items[top] = items[top - 1];
		items[top - 1] = items[top - 2];
		items[top - 2] = items[top + 1];
		top++;
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack overflow");
	    }
	}
	public void dup() {
	    try {
		items[top + 1] = items[top];
		top++;
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack overflow");
	    }
	}
	public void dup2() {
	    try {
		items[top + 2] = items[top];
		items[top + 1] = items[top - 1];
		top += 2;
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack overflow");
	    }
	}
	public void dup2_x1() {
	    try {
		items[top + 2] = items[top];
		items[top + 1] = items[top - 1];
		items[top] = items[top - 2];
		items[top - 1] = items[top + 2];
		items[top - 2] = items[top + 1];
		top += 2;
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack overflow");
	    }
	}
	public void dup2_x2() {
	    try {
		items[top + 2] = items[top];
		items[top + 1] = items[top - 1];
		items[top] = items[top - 2];
		items[top - 1] = items[top - 3];
		items[top - 2] = items[top + 2];
		items[top - 3] = items[top + 1];
		top += 2;
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack overflow");
	    }
	}
	public void push(SimpleJITOperand o) {
	    top++;
	    try {
		items[top] = o;
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack overflow : height " 
				+ (top - 1));
	    }
	}
	public void pushWide(SimpleJITOperand o) {
	    top += 2;
	    try {
		items[top - 1] = o;
		items[top] = null;
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack overflow");
	    }
	}
	public int height() {
	    return top;
	}
	public void swap() {
	    try {
		SimpleJITOperand t = items[top];
		items[top] = items[top - 1];
		items[top - 1] = t;
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack overflow");
	    }
	}
	public void pop2() {
	    try {
		top -= 2;
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack underflow");
	    }
	}
	public SimpleJITOperand pop() {
	    try {
		SimpleJITOperand r = items[top];
		top--;
		return r;
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack underflow");
	    }
	}
	public SimpleJITOperand popWide() {
	    try {
		SimpleJITOperand r = items[top - 1];
		top -= 2;
		return r;
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack underflow");
	    }
	}
	// the stack top is at depth 0
	public SimpleJITOperand peekByDepth(int depth) {
	    try {
		if (depth < 0)
		    throw new ArrayIndexOutOfBoundsException();
		return items[top - depth];
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack out-of-bound depth");
	    }
	}
	// the stack bottom is at height 0
	public SimpleJITOperand peekByHeight(int height) {
	    try {
		if (height > top)
		    throw new ArrayIndexOutOfBoundsException();
		return items[height];
	    } catch (ArrayIndexOutOfBoundsException e) {
		throw new Error("stack out-of-bound height");
	    }
	}

	public SimpleJITOperand popWithTag(char tag) {
	    switch(tag) {
	    case TypeCodes.LONG:
	    case TypeCodes.DOUBLE:
		return popWide();
	    default:
		return pop();
	    }
	}

	public void pushWithTag(char tag, 
				SimpleJITOperand op) {
	    switch(tag) {
	    case TypeCodes.LONG:
	    case TypeCodes.DOUBLE:
		pushWide(op);
		break;
	    default:
		push(op);
	    }
	}
	
    }

}
