if (debug) {
System.out.println("invoking = " + r.getMethod());
}
if (r.getBase().getType() instanceof RefType) {
RefType type = (RefType) r.getBase().getType();
if (debug) {
System.out.println("baseType = " + type);
}
// Remove calls to validate().
if (r.getMethod().equals(PtolemyUtilities.validateMethod)) {
body.getUnits().remove(stmt);
continue;
} else {
// Inline calls to attribute changed that do
// not occur from within another
// attributeChanged method.
if (r.getMethod().getSubSignature().equals(
PtolemyUtilities.attributeChangedMethod
.getSubSignature())) {
// If we are calling attribute changed on
// one of the classes we are generating
// code for, then inline it.
if (type.getSootClass().isApplicationClass()) {
SootMethod inlinee = null;
if (r instanceof VirtualInvokeExpr) {
inlinee = SootUtilities
.resolveVirtualInvokationForInlining(
type.getSootClass(),
PtolemyUtilities.attributeChangedMethod);
} else if (r instanceof SpecialInvokeExpr) {
inlinee = SootUtilities
.resolveSpecialInvokationForInlining(
(SpecialInvokeExpr) r,
method);
}
if (inlinee.equals(method)) {
System.out
.println("Skipping inline at "
+ r
+ " because we can't inline methods into themselves.");
} else {
if (debug) {
System.out
.println("Inlining method call: "
+ r);
}
if (debug) {
System.out.println("Inlinee = "
+ inlinee);
}
SiteInliner.inlineSite(inlinee, stmt,
method);
doneSomething = true;
}
} else {
// FIXME: this is a bit of a hack, but
// for right now it seems to work.
// How many things that aren't
// the actors we are generating
// code for do we really care about here?
// Can we do this without having to create
// a class for the attribute too????
body.getUnits().remove(stmt);
doneSomething = true;
}
}
}
// Statically evaluate constant arguments.
Value[] argValues = new Value[r.getArgCount()];
int argCount = 0;
for (Iterator args = r.getArgs().iterator(); args.hasNext();) {
Value arg = (Value) args.next();
// if (debug) System.out.println("arg = " + arg);
if (Evaluator.isValueConstantValued(arg)) {
argValues[argCount++] = Evaluator
.getConstantValueOf(arg);
if (debug) {
System.out.println("argument = "
+ argValues[argCount - 1]);
}
} else {
break;
}
}
if (SootUtilities.derivesFrom(type.getSootClass(),
PtolemyUtilities.settableClass)) {
// If we are invoking a method on a
// variable class, then attempt to get the
// constant value of the variable.
Attribute attribute = (Attribute) namedObjAnalysis
.getObject((Local) r.getBase());
if (debug) {
System.out.println("Settable base = " + attribute);
}
// If the attribute resolves to null, then
// replace the invocation with an exception
// throw. It would be nice to do this, but
// some strange cases fail as a result, in
// particular, if you showName on a
// PortParameter it fails (!)
// if (attribute == null) {
// if (debug) System.out.println("replacing with NullPointerException!");
// Local exceptionLocal =
// SootUtilities.createRuntimeException(
// body, stmt,
// "NullPointerException: " + r);
// body.getUnits().swapWith(stmt,
// Jimple.v().newThrowStmt(
// exceptionLocal));
// continue;
// }
// Inline getType, setTypeEquals, etc...
if (attribute instanceof Typeable) {
if (PtolemyUtilities.inlineTypeableMethods(body,
stmt, box, r, (Typeable) attribute)) {
continue;
}
}
// Inline namedObj methods on the attribute.
if (r.getMethod().getSubSignature().equals(
PtolemyUtilities.getFullNameMethod
.getSubSignature())) {
box.setValue(StringConstant.v(attribute
.getFullName()));
continue;
}
if (r.getMethod().getSubSignature().equals(
PtolemyUtilities.getNameMethod
.getSubSignature())) {
box.setValue(StringConstant.v(attribute.getName()));
continue;
}
if (r instanceof SpecialInvokeExpr) {
continue;
}
// Get some references to the container of the
// attribute.
if (attribute == null) {
throw new InternalErrorException(
"Attribute == null?, "
+ "this should not be happening! "
+ "\n\tInstanceInvokeExpr: "
+ r
+ "\n\tbase: "
+ r.getBase()
+ "\n\tmethod: "
+ method
+ "\n\treferredObject: "
+ referredObject
+ "\nGetting 'null' out of the "
+ "TypeAnalysis means "
+ "'I can't figure "
+ "out where this came "
+ "from and hence, I can't tell "
+ "you what the type is' "
+ "The type might be incomparable, "
+ "or maybe not! The type analysis "
+ "is rather hairy to debug because "
+ "it happens multiple times and "
+ "is self dependent... A bug in "
+ "one place tends to propagate "
+ "to a method inline, which "
+ "propagates to another type "
+ "analysis . . .");
}
Entity container = FieldsForEntitiesTransformer
.getEntityContainerOfObject(attribute);
/*Local thisLocal =*/body.getThisLocal();
Local containerLocal = getAttributeContainerRef(
container, method, (Local) r.getBase(), stmt,
localDefs, localUses, stmt);
// FieldsForEntitiesTransformer.getLocalReferenceForEntity(
// container, theClass, thisLocal, body, stmt, _options);
// For Variables, we handle get/setToken,
// get/setExpression different from other
// settables
if (attribute instanceof Variable) {
// Deal with tricky methods separately.
// Match the subsignature so we catch
// isomorphic subclasses as well...
if (r
.getMethod()
.getSubSignature()
.equals(
PtolemyUtilities.variableConstructorWithToken
.getSubSignature())) {
SootClass variableClass = r.getMethod()
.getDeclaringClass();
SootMethod constructorWithoutToken = variableClass
.getMethod(PtolemyUtilities.variableConstructorWithoutToken
.getSubSignature());
// Replace the three-argument
// constructor with a two-argument
// constructor. We do this for
// several reasons:
// 1) The assignment is
// redundant... all parameters
// are initialized with the
// appropriate value.
// 2) The type of the token is
// often wrong for polymorphic
// actors.
// 3) Later on, when we inline all
// token constructors, there is no
// longer a token to pass to the
// constructor. It is easier to
// just deal with it now...
// Create a new two-argument constructor.
box.setValue(Jimple.v().newSpecialInvokeExpr(
(Local) r.getBase(),
constructorWithoutToken.makeRef(),
r.getArg(0), r.getArg(1)));
// Call setToken with the actual value of the parameter
Token token;
// First create a token with the given
// expression and then set the
// token to that value.
try {
token = ((Variable) attribute).getToken();
} catch (Exception ex) {
throw new RuntimeException(
"Illegal parameter value = "
+ argValues[0]);
}
String localName = "_CGTokenLocal";
Local tokenLocal = PtolemyUtilities
.buildConstantTokenLocal(body, stmt,
token, localName);
body
.getUnits()
.insertAfter(
Jimple
.v()
.newInvokeStmt(
Jimple
.v()
.newVirtualInvokeExpr(
(Local) r
.getBase(),
PtolemyUtilities.variableSetTokenMethod
.makeRef(),
tokenLocal)),
stmt);
doneSomething = true;
} else if (r.getMethod().getName().equals(
"getToken")) {
if (debug) {
System.out
.println("Replacing getToken on Variable");
}
// replace the method call with a field ref.
SootField tokenField = (SootField) attributeToValueFieldMap
.get(attribute);
if (tokenField == null) {
throw new RuntimeException(
"No tokenField found for attribute "
+ attribute);
}
if (stmt instanceof InvokeStmt) {
body.getUnits().remove(stmt);
} else {
box.setValue(Jimple.v()
.newInstanceFieldRef(
containerLocal,
tokenField.makeRef()));
}
doneSomething = true;
} else if (r.getMethod().getName().equals(
"setToken")
|| r.getMethod().getName().equals(
"_setTokenAndNotify")) {
if (debug) {
System.out
.println("Replacing setToken on Variable");
}
// replace the entire statement
// (which must be an invokeStmt anyway)
// with an assignment to the field of the first argument.
SootField tokenField = (SootField) attributeToValueFieldMap
.get(attribute);
if (tokenField == null) {
throw new RuntimeException(
"No tokenField found for attribute "
+ attribute);
}
Local tokenLocal = Jimple.v().newLocal(
"convertedToken", tokenField.getType());
body.getLocals().add(tokenLocal);
// Convert the token to the type of the variable.
Local typeLocal = PtolemyUtilities
.buildConstantTypeLocal(body, stmt,
((Variable) attribute)
.getType());
body
.getUnits()
.insertBefore(
Jimple
.v()
.newAssignStmt(
tokenLocal,
Jimple
.v()
.newInterfaceInvokeExpr(
typeLocal,
PtolemyUtilities.typeConvertMethod
.makeRef(),
r
.getArg(0))),
stmt);
body.getUnits().insertBefore(
Jimple.v().newAssignStmt(
tokenLocal,
Jimple.v().newCastExpr(
tokenLocal,
tokenField.getType())),
stmt);
// Assign the value field for the variable.
body.getUnits().insertBefore(
Jimple.v().newAssignStmt(
Jimple.v().newInstanceFieldRef(
containerLocal,
tokenField.makeRef()),
tokenLocal), stmt);
// Invoke attributeChanged on the
// container of the variable.
PtolemyUtilities.callAttributeChanged(
containerLocal, (Local) r.getBase(),
theClass, method, body, stmt);
// remove the old call.
body.getUnits().remove(stmt);
doneSomething = true;
} else if (r.getMethod().getSubSignature().equals(
PtolemyUtilities.getExpressionMethod
.getSubSignature())) {
if (debug) {
System.out
.println("Replacing getExpression on Variable");
}
// First get the token out of the
// field, and then insert a call to
// its toString method to get the
// expression.
SootField tokenField = (SootField) attributeToValueFieldMap
.get(attribute);
if (tokenField == null) {
throw new RuntimeException(
"No tokenField found for attribute "
+ attribute);
}
String localName = "_CGTokenLocal";
Local tokenLocal = Jimple.v().newLocal(
localName, tokenField.getType());
body.getLocals().add(tokenLocal);
body.getUnits().insertBefore(
Jimple.v().newAssignStmt(
tokenLocal,
Jimple.v().newInstanceFieldRef(
containerLocal,
tokenField.makeRef())),
stmt);
box.setValue(Jimple.v().newVirtualInvokeExpr(
tokenLocal,
PtolemyUtilities.toStringMethod
.makeRef()));
doneSomething = true;
// FIXME null result => ""
} else if (false) { // (r.getMethod().getSubSignature().equals(PtolemyUtilities.setExpressionMethod.getSubSignature())) {
// FIXME: 1/08: This section used to
// never be run, but the change to
// NonStrictTest.wrapup() requires it.
// To test this, run copernicus on
// ../../actor/lib/test/auto/Const.xml
// Set Expression is problematic
// because the expression might not be
// known. We used to assume that this
// was part of creation, but now all
// the initialization code is removed
// early on. Beware variables used to
// evaluate expressions!
if (debug) {
System.out
.println("Replacing setExpression on Variable");
}
// Call attribute changed AFTER we set the token.
PtolemyUtilities.callAttributeChanged(
containerLocal, (Local) r.getBase(),
theClass, method, body, body.getUnits()
.getSuccOf(stmt));
Token token;
// First create a token with the given
// expression and then set the
// token to that value.
try {
token = ((Variable) attribute).getToken();
} catch (Exception ex) {
throw new RuntimeException(
"Illegal parameter value = "
+ argValues[0]);
}
// Create code to instantiate the token
SootField tokenField = (SootField) attributeToValueFieldMap
.get(attribute);
if (tokenField == null) {
throw new RuntimeException(
"No tokenField found for attribute "
+ attribute);
}
String localName = "_CGTokenLocal";
Local tokenLocal = PtolemyUtilities
.buildConstantTokenLocal(body, stmt,
token, localName);
body.getUnits().swapWith(
stmt,
Jimple.v().newAssignStmt(
Jimple.v().newInstanceFieldRef(
containerLocal,
tokenField.makeRef()),
tokenLocal));
doneSomething = true;
} else if (r.getMethod().getName().equals("update")) {
// FIXME: for PortParameters.
// Now inline the resulting call.
SootMethod inlinee = null;
if (r instanceof VirtualInvokeExpr) {
inlinee = SootUtilities
.resolveVirtualInvokationForInlining(
type.getSootClass(),
PtolemyUtilities.portParameterUpdateMethod);
} else if (r instanceof SpecialInvokeExpr) {
inlinee = SootUtilities
.resolveSpecialInvokationForInlining(
(SpecialInvokeExpr) r,