VariableReferenceValue.java

package edu.udel.cis.vsl.tass.dynamic.impl.value;

import edu.udel.cis.vsl.tass.dynamic.IF.cell.CellIF;
import edu.udel.cis.vsl.tass.dynamic.IF.cell.HeapCellIF;
import edu.udel.cis.vsl.tass.dynamic.IF.cell.LocalCellIF;
import edu.udel.cis.vsl.tass.dynamic.IF.cell.ProcessCellIF;
import edu.udel.cis.vsl.tass.dynamic.IF.cell.SharedCellIF;
import edu.udel.cis.vsl.tass.dynamic.IF.type.ReferenceValueTypeIF;
import edu.udel.cis.vsl.tass.dynamic.IF.value.ValueIF;
import edu.udel.cis.vsl.tass.dynamic.IF.value.VariableReferenceValueIF;
import edu.udel.cis.vsl.tass.dynamic.impl.type.ValueTypeFactory;
import edu.udel.cis.vsl.tass.model.IF.ProcessIF;
import edu.udel.cis.vsl.tass.model.IF.scope.LocalScopeIF;
import edu.udel.cis.vsl.tass.model.IF.variable.LocalVariableIF;
import edu.udel.cis.vsl.tass.morph.Morphic;

// question: is initial value part of the state of this object?
// why do two instances have to have same initial value?
// answer: this is the initial value before any initialization expression
// is evaluated and assigned to the variable.  Hence it is either "undefined"
// or a symbolic constant because it is an input variable.

/**
 * Represents a reference to a variable. The variable is an instance of CellIF,
 * i.e., a dynamic variable. There is also an integer-valued symbolic
 * expression, the "offset". This is technically either 0 or 1. It is there
 * because it is possible in C to have a pointer to the position just after a
 * variable, as in
 * 
 * double x; double *p = (&x) + 1;
 * 
 * However, an attempt to dereference a reference value for which the offset if
 * not 0 will result in an execution exception.
 * 
 * The initial value for the variable can be cached here for convenience, so it
 * does not have to be re-computed repeatedly.
 */
public class VariableReferenceValue extends ReferenceValue implements
		VariableReferenceValueIF {

	private static int classHashCode = VariableReferenceValue.class.hashCode();

	private CellIF cell;

	/**
	 * Extrinsic data: like the undefined value, the initialValue can only be
	 * cached if the type is committed.
	 */
	// TODO: this is never used:
	private ValueIF initialValue = null;

	/**
	 * This can be 0 or 1. 0 means a pointer to the variable, as you would
	 * expect. 1 means a pointer to the point just after the variable, which is
	 * the result of pointer arithmetic in which "1" was added to the original
	 * variable pointer. This is a legal pointer value, but cannot be
	 * dereferenced.
	 */
	private ValueIF offset;

	public VariableReferenceValue(CellIF variable,
			ReferenceValueTypeIF valueType, ValueIF offset) {
		super(null, valueType);
		if (variable == null)
			throw new NullPointerException("null variable");
		this.cell = variable;
		if (offset == null)
			throw new NullPointerException("null offset");
		this.offset = offset;
	}

	@Override
	protected int computeHashCode() {
		return super.computeHashCode() + classHashCode + cell.hashCode()
				+ offset.hashCode();
	}

	public String fullName() {
		if (cell instanceof LocalCellIF) {
			LocalVariableIF localVariable = ((LocalCellIF) cell).variable();
			int stackPosition = ((LocalCellIF) cell).stackIndex();
			LocalScopeIF scope = localVariable.scope();
			int mid = localVariable.model().id();
			int pid = scope.function().process().pid();
			int fid = scope.function().idInScope();
			int scopeId = scope.localId();
			int vid = localVariable.idInScope();

			return "m" + mid + "p" + pid + "s" + stackPosition + "f" + fid
					+ "c" + scopeId + "v" + vid;
		} else if (cell instanceof SharedCellIF) {
			SharedCellIF sharedCell = (SharedCellIF) cell;

			return "m" + sharedCell.variable().model().id() + "v"
					+ sharedCell.sharedVariableId();
		} else if (cell instanceof ProcessCellIF) {
			ProcessCellIF processCell = (ProcessCellIF) cell;
			ProcessIF process = processCell.variable().scope().process();

			return "m" + process.model().id() + "p" + process.pid() + "v"
					+ processCell.processVariableId();
		} else if (cell instanceof HeapCellIF) {
			HeapCellIF dynamicHeapVariable = (HeapCellIF) cell;
			ProcessIF process = dynamicHeapVariable.process();
			int heapIndex = dynamicHeapVariable.heapIndex();

			return "m" + process.model().id() + "p" + process.pid() + "h"
					+ heapIndex;
		}
		throw new RuntimeException("Unknown dynamic variable type:\n" + cell);
	}

	public CellIF variable() {
		return cell;
	}

	public ValueIF offset() {
		return offset;
	}

	public String toString() {
		String result = "&" + cell;
		String offsetString = offset.toString();

		if (!"0".equals(offsetString))
			result += "+" + offsetString;
		return result;
	}

	public VariableReferenceValueIF variableReference() {
		return this;
	}

	@Override
	public boolean computeEquals(Morphic component) {
		if (!super.computeEquals(component))
			return false;
		if (component instanceof VariableReferenceValue) {
			VariableReferenceValue that = (VariableReferenceValue) component;

			return cell.equals(that.cell) && offset.equals(that.offset);
		}
		return false;
	}

	@Override
	public boolean isNull() {
		return false;
	}

	@Override
	protected void commitChildren() {
		super.commit();
		if (initialValue != null)
			initialValue.commit();
	}

	@Override
	protected void canonicalizeChildren(ValueFactory valueFactory,
			ValueTypeFactory typeFactory) {
		super.canonicalizeChildren(valueFactory, typeFactory);

		offset = valueFactory.canonic(offset);
		if (initialValue != null)
			initialValue = valueFactory.canonic(initialValue);
	}
}