LocalUses localUses) {
if (debug) {
System.out.println("_getInequalityTerm(): " + method + " " + value);
}
if (value instanceof StaticInvokeExpr) {
StaticInvokeExpr r = (StaticInvokeExpr) value;
if (r.getMethod().equals(PtolemyUtilities.arraycopyMethod)) {
// If we are copying one array to another, then the
// types must be equal.
InequalityTerm firstArgTerm = (InequalityTerm) objectToInequalityTerm
.get(r.getArg(0));
InequalityTerm thirdArgTerm = (InequalityTerm) objectToInequalityTerm
.get(r.getArg(2));
_addInequality(debug, solver, firstArgTerm, thirdArgTerm);
_addInequality(debug, solver, thirdArgTerm, firstArgTerm);
return null;
}
} else if (value instanceof InstanceInvokeExpr) {
InstanceInvokeExpr r = (InstanceInvokeExpr) value;
String methodName = r.getMethod().getName();
// If we are invoking on something that is not a reference type,
// then ignore it.
if (!(r.getBase().getType() instanceof RefType)) {
return null;
}
// System.out.println("invokeExpr = " + r);
SootClass baseClass = ((RefType) r.getBase().getType())
.getSootClass();
InequalityTerm baseTerm = (InequalityTerm) objectToInequalityTerm
.get(r.getBase());
// FIXME: match better.
// If we are invoking a method on a token, then...
if (SootUtilities
.derivesFrom(baseClass, PtolemyUtilities.typeClass)) {
if (methodName.equals("convert")) {
return baseTerm;
// try {
// ptolemy.data.type.Type baseType = PtolemyUtilities
// .getTypeValue(method, (Local) r.getBase(),
// unit, localDefs, localUses);
// InequalityTerm baseTypeTerm = new ConstantTerm(
// baseType, r);
// return baseTypeTerm;
// } catch (RuntimeException ex) {
// // Ignore..
// }
} else if (r
.getMethod()
.getSignature()
.equals(
"<ptolemy.data.type.ArrayType: void <init>(ptolemy.data.type.Type)>")) {
InequalityTerm elementTerm = (InequalityTerm) objectToInequalityTerm
.get(r.getArg(0));
ptolemy.data.type.ArrayType arrayType = new ptolemy.data.type.ArrayType(
ptolemy.data.type.BaseType.UNKNOWN);
InequalityTerm variableTerm = new VariableTerm(arrayType, r);
_addInequality(debug, solver, elementTerm, arrayType
.getElementTypeTerm());
_addInequality(debug, solver, arrayType
.getElementTypeTerm(), elementTerm);
_addInequality(debug, solver, variableTerm, baseTerm);
return variableTerm;
}
}
if (SootUtilities.derivesFrom(baseClass,
PtolemyUtilities.tokenClass)) {
if (r.getMethod()
.equals(PtolemyUtilities.arrayTokenConstructor)) {
InequalityTerm firstArgTerm = (InequalityTerm) objectToInequalityTerm
.get(r.getArg(0));
ptolemy.data.type.ArrayType arrayType = new ptolemy.data.type.ArrayType(
ptolemy.data.type.BaseType.UNKNOWN);
VariableTerm newTerm = new VariableTerm(arrayType, r);
_addInequality(debug, solver, baseTerm, newTerm);
_addInequality(debug, solver, newTerm, baseTerm);
InequalityTerm elementTerm = arrayType.getElementTypeTerm();
_addInequality(debug, solver, firstArgTerm, elementTerm);
_addInequality(debug, solver, elementTerm, firstArgTerm);
return baseTerm;
} else if (r.getMethod().equals(
PtolemyUtilities.arrayTokenWithTypeConstructor)) {
InequalityTerm elementTypeTerm = (InequalityTerm) objectToInequalityTerm
.get(r.getArg(0));
ptolemy.data.type.ArrayType arrayType = new ptolemy.data.type.ArrayType(
ptolemy.data.type.BaseType.UNKNOWN);
VariableTerm newTerm = new VariableTerm(arrayType, r);
_addInequality(debug, solver, baseTerm, newTerm);
_addInequality(debug, solver, newTerm, baseTerm);
InequalityTerm elementTerm = arrayType.getElementTypeTerm();
_addInequality(debug, solver, elementTypeTerm, elementTerm);
_addInequality(debug, solver, elementTerm, elementTypeTerm);
return baseTerm;
} else if (methodName.equals("one")
|| methodName.equals("zero")
|| methodName.equals("bitwiseNot")
|| methodName.equals("pow")
|| methodName.equals("logicalRightShift")
|| methodName.equals("leftShift")
|| methodName.equals("rightShit")) {
// The returned type must be equal to the type
// we are calling the method on.
return baseTerm;
} else if (methodName.equals("add")
|| methodName.equals("addReverse")
|| methodName.equals("subtract")
|| methodName.equals("subtractReverse")
|| methodName.equals("multiply")
|| methodName.equals("multiplyReverse")
|| methodName.equals("divide")
|| methodName.equals("divideReverse")
|| methodName.equals("modulo")
|| methodName.equals("moduloReverse")
|| methodName.equals("bitwiseAnd")
|| methodName.equals("bitwiseOr")
|| methodName.equals("bitwiseXor")) {
// The return value is greater than the base and
// the argument.
// InequalityTerm returnValueTerm = new VariableTerm(
// PtolemyUtilities.getTokenTypeForSootType(
// (RefType)r.getMethod().getReturnType()),
// r.getMethod());
final InequalityTerm firstArgTerm = (InequalityTerm) objectToInequalityTerm
.get(r.getArg(0));
final InequalityTerm finalBaseTerm = baseTerm;
final InstanceInvokeExpr finalExpression = r;
// _addInequality(debug, solver, firstArgTerm,
// returnValueTerm);
// _addInequality(debug, solver, baseTerm,
// returnValueTerm);
InequalityTerm returnValueTerm = new MonotonicFunction() {
public Object getValue() throws IllegalActionException {
if (firstArgTerm.getValue().equals(
TypeLattice.lattice().bottom())
|| finalBaseTerm.getValue().equals(
TypeLattice.lattice().bottom())) {
return TypeLattice.lattice().bottom();
}
return TypeLattice.lattice().leastUpperBound(
firstArgTerm.getValue(),
finalBaseTerm.getValue());
}
public InequalityTerm[] getVariables() {
ArrayList list = new ArrayList();
if (firstArgTerm.isSettable()) {
list.add(firstArgTerm);
}
if (finalBaseTerm.isSettable()) {
list.add(finalBaseTerm);
}
InequalityTerm[] terms = (InequalityTerm[]) list
.toArray(new InequalityTerm[list.size()]);
return terms;
}
public Object getAssociatedObject() {
return finalExpression;
}
};
return returnValueTerm;
} else if (methodName.equals("convert")) {
System.out.println("convert method!");
// The return value type is equal to the base
// type. The first argument type is less than or
// equal to the base type.
InequalityTerm firstArgTerm = (InequalityTerm) objectToInequalityTerm
.get(r.getArg(0));
_addInequality(debug, solver, firstArgTerm, baseTerm);
return baseTerm;
} else if (methodName.equals("getElement")
|| methodName.equals("arrayValue")
|| methodName.equals("getElementType")) {
// If we call getElement or arrayValue on an array
// token, then the returned type is the element
// type of the array.
ptolemy.data.type.ArrayType arrayType = new ptolemy.data.type.ArrayType(
ptolemy.data.type.BaseType.UNKNOWN);
_addInequality(debug, solver, baseTerm, new VariableTerm(
arrayType, r));
InequalityTerm returnTypeTerm = arrayType
.getElementTypeTerm();
return returnTypeTerm;
} else if (methodName.equals("getElementAsToken")) {
final InequalityTerm matrixTerm = baseTerm;
InequalityTerm returnTypeTerm = new MonotonicFunction() {
public Object getValue() throws IllegalActionException {
if (matrixTerm.getValue() instanceof MatrixType) {
MatrixType type = (MatrixType) matrixTerm
.getValue();
return type.getElementType();
} else {
return BaseType.UNKNOWN;
}
}
public InequalityTerm[] getVariables() {
if (matrixTerm.isSettable()) {
InequalityTerm[] terms = new InequalityTerm[1];
terms[0] = matrixTerm;
return terms;
} else {
return new InequalityTerm[0];
}
}
};
return returnTypeTerm;
} else if (methodName.equals("absolute")) {
// Return the same as the input type, unless
// complex, in which case, return double.
final InequalityTerm finalBaseTerm = baseTerm;
final InstanceInvokeExpr finalExpression = r;
InequalityTerm returnValueTerm = new MonotonicFunction() {
public Object getValue() throws IllegalActionException {
if (finalBaseTerm.getValue().equals(
BaseType.COMPLEX)) {
return BaseType.DOUBLE;
}
return finalBaseTerm.getValue();
}
public InequalityTerm[] getVariables() {
ArrayList list = new ArrayList();
if (finalBaseTerm.isSettable()) {
list.add(finalBaseTerm);
}
InequalityTerm[] terms = (InequalityTerm[]) list
.toArray(new InequalityTerm[list.size()]);
return terms;
}
public Object getAssociatedObject() {
return finalExpression;
}
};
return returnValueTerm;
}
} else if (SootUtilities.derivesFrom(baseClass,
PtolemyUtilities.componentPortClass)) {
// If we are invoking a method on a port.
TypedIOPort port = InlinePortTransformer.getPortValue(method,
(Local) r.getBase(), unit, localDefs, localUses);
if (port == null) {
throw new RuntimeException("Failed to find port for "
+ unit);
}
// Don't create constant terms for
// ports where we don't already know the type.
if (!port.getType().isInstantiable()) {
return null;
}
InequalityTerm portTypeTerm = new ConstantTerm(port.getType(),
port);
if (methodName.equals("broadcast")) {
// The type of the argument must be less than the
// type of the port.
InequalityTerm firstArgTerm = (InequalityTerm) objectToInequalityTerm
.get(r.getArg(0));
_addInequality(debug, solver, firstArgTerm, portTypeTerm);
// Return type is void.
return null;
} else if (methodName.equals("get")) {
if (r.getArgCount() == 2) {
// FIXME: array of portTypeTerm?
return portTypeTerm;
} else if (r.getArgCount() == 1) {
return portTypeTerm;
}
} else if (methodName.equals("send")) {
if (r.getArgCount() == 3) {
// The type of the argument must be less than the
// type of the port.
InequalityTerm secondArgTerm = (InequalityTerm) objectToInequalityTerm
.get(r.getArg(1));
_addInequality(debug, solver, secondArgTerm,
portTypeTerm);
// Return type is void.
return null;
} else if (r.getArgCount() == 2) {
// The type of the argument must be less than the
// type of the port.
InequalityTerm secondArgTerm = (InequalityTerm) objectToInequalityTerm
.get(r.getArg(1));
_addInequality(debug, solver, secondArgTerm,
portTypeTerm);
// Return type is void.
return null;
}
}
} else if (SootUtilities.derivesFrom(baseClass,
PtolemyUtilities.attributeClass)) {
// If we are invoking a method on a port.
Attribute attribute = InlineParameterTransformer
.getAttributeValue(method, (Local) r.getBase(), unit,
localDefs, localUses);
if (attribute == null) {
// A method invocation with a null base is bogus,
// so don't create a type constraint.
return null;
}
if (attribute instanceof Variable) {
Variable parameter = (Variable) attribute;
InequalityTerm parameterTypeTerm = new ConstantTerm(
parameter.getType(), parameter);
if (methodName.equals("setToken")) {
// The type of the argument must be less than the
// type of the parameter.
InequalityTerm firstArgTerm = (InequalityTerm) objectToInequalityTerm
.get(r.getArg(0));
_addInequality(debug, solver, firstArgTerm,
parameterTypeTerm);
// Return type is void.
return null;
} else if (methodName.equals("getToken")) {
// Return the type of the parameter.
return parameterTypeTerm;
}
}
}
} else if (value instanceof ArrayRef) {
// The type must be the same as the type of the
// base of the array.
return (InequalityTerm) objectToInequalityTerm
.get(((ArrayRef) value).getBase());
// If we call getElement or arrayValue on an array
// token, then the returned type is the element
// type of the array.
// InequalityTerm baseTerm =
// (InequalityTerm)objectToInequalityTerm.get(
// ((ArrayRef)value).getBase());
// ptolemy.data.type.ArrayType arrayType =
// new ptolemy.data.type.ArrayType(
// ptolemy.data.type.BaseType.UNKNOWN);
// _addInequality(debug, solver, baseTerm,
// new VariableTerm(arrayType, value));
// InequalityTerm returnTypeTerm = (InequalityTerm)
// arrayType.getElementTypeTerm();
// return returnTypeTerm;
} else if (value instanceof CastExpr) {
CastExpr castExpr = (CastExpr) value;
// The return type will be the type
// of the cast.
InequalityTerm baseTerm = (InequalityTerm) objectToInequalityTerm
.get(castExpr.getOp());
return baseTerm;
} else if (value instanceof NewExpr) {
NewExpr newExpr = (NewExpr) value;
RefType type = newExpr.getBaseType();
SootClass castClass = type.getSootClass();
// If we are creating a Token type...
if (SootUtilities.derivesFrom(castClass,
PtolemyUtilities.tokenClass)) {
InequalityTerm typeTerm = new ConstantTerm(PtolemyUtilities
.getTokenTypeForSootType(type), newExpr);
// Then the value of the expression is the type of the
// constructor.
return typeTerm;
} else {
// Otherwise there is nothing to be done.
return null;
}
} else if (value instanceof NewArrayExpr) {
// Since arrays are aliasable, we must update their types.
NewArrayExpr newExpr = (NewArrayExpr) value;
Type type = newExpr.getBaseType();
RefType tokenType = PtolemyUtilities.getBaseTokenType(type);
if ((tokenType != null)
&& (objectToInequalityTerm.get(newExpr) == null)) {
InequalityTerm typeTerm = new VariableTerm(PtolemyUtilities
.getTokenTypeForSootType(tokenType), newExpr);
// This is something we update, so put an entry
// in the map used for updating
objectToInequalityTerm.put(newExpr, typeTerm);
// Then the value of the expression is the type of the
// constructor.
return typeTerm;
}
// Otherwise there is nothing to be done.
return null;
} else if (value instanceof NewMultiArrayExpr) {
// Since arrays are aliasable, we must update their types.
NewMultiArrayExpr newExpr = (NewMultiArrayExpr) value;
Type type = newExpr.getBaseType();
RefType tokenType = PtolemyUtilities.getBaseTokenType(type);
if ((tokenType != null)
&& (objectToInequalityTerm.get(newExpr) == null)) {
InequalityTerm typeTerm = new VariableTerm(PtolemyUtilities
.getTokenTypeForSootType(tokenType), newExpr);
// This is something we update, so put an entry
// in the map used for updating
objectToInequalityTerm.put(newExpr, typeTerm);
// Then the value of the expression is the type of the
// constructor.
return typeTerm;
}
// Otherwise there is nothing to be done.
return null;
} else if (value instanceof FieldRef) {
FieldRef r = (FieldRef) value;
// Field references have the type of the field.
SootField field = r.getField();
// FIXME: UGH: This is the same as elementType...
if (field.getSignature().equals(
"<ptolemy.data.ArrayToken: ptolemy.data.Token[] _value>")
|| field