TypeSpecializerAnalysis typeAnalysis = new TypeSpecializerAnalysis(
entityClass, unsafeLocalSet);
for (Iterator methods = entityClass.getMethods().iterator(); methods
.hasNext();) {
SootMethod method = (SootMethod) methods.next();
// Check to see if the method is safe to modify with:
// It has no arguments or return values which are
// tokens.
if (_methodWillBeInlined(method)) {
continue;
}
JimpleBody body = (JimpleBody) method.retrieveActiveBody();
// UnitGraph graph = new CompleteUnitGraph(body);
// MustAliasAnalysis aliasAnalysis = new MustAliasAnalysis(graph);
if (debug) {
System.out.println("creating replacement locals in method = "
+ method);
}
// A map from a local variable that references a
// token and a field of that token class to the
// local variable that will replace a
// fieldReference to that field based on the
// local.
for (Iterator locals = body.getLocals().snapshotIterator(); locals
.hasNext();) {
Local local = (Local) locals.next();
Type localType = typeAnalysis.getSpecializedSootType(local);
if (debug) {
System.out
.println("Attempting to create replacement fields for local = "
+ local);
}
if (debug) {
System.out.println("Type = " + localType);
}
// If the type is not a token, then skip it.
if (!PtolemyUtilities.isConcreteTokenType(localType)
|| unsafeLocalSet.contains(local)) {
if (debug) {
System.out
.println("skipping: unsafe or not concrete token");
}
continue;
}
ptolemy.data.type.Type localTokenType = typeAnalysis
.getSpecializedType(local);
if (debug) {
System.out.println("localTokenType = " + localTokenType);
}
// Ignore fields that aren't of the right depth.
if (PtolemyUtilities.getTypeDepth(localTokenType) != depth) {
if (debug) {
System.out
.println("skipping: depth is only "
+ PtolemyUtilities
.getTypeDepth(localTokenType));
}
continue;
}
// If the type is not instantiable, then skip it.
// if (!localTokenType.isInstantiable()) {
// continue;
// }
// If we've already created subfields for this
// field, then don't do it again.
if (localToFieldToLocal.get(local) != null) {
continue;
}
RefType type = PtolemyUtilities.getBaseTokenType(localType);
SootClass localClass = type.getSootClass();
if (!SootUtilities.derivesFrom(localClass,
PtolemyUtilities.tokenClass)) {
if (debug) {
System.out.println("skipping: not a token.");
}
continue;
}
if (debug) {
System.out
.println("Creating replacement fields for local = "
+ local);
}
if (debug) {
System.out.println("localClass = " + localClass);
}
// We are going to make a modification
doneSomething = true;
Type isNotNullType = SootUtilities.createIsomorphicType(
localType, BooleanType.v());
// Create a boolean value that tells us whether or
// not the token is null. Initialize it to true.
Local isNotNullLocal = Jimple.v().newLocal(
local.getName() + "_isNotNull", isNotNullType);
body.getLocals().add(isNotNullLocal);
localToIsNotNullLocal.put(local, isNotNullLocal);
// Note: default initialization is to false..
// body.getUnits().insertBefore(
// Jimple.v().newAssignStmt(
// isNotNullLocal,
// IntConstant.v(1)),
// body.getFirstNonIdentityStmt());
Map tokenFieldToReplacementLocal = new HashMap();
localToFieldToLocal.put(local, tokenFieldToReplacementLocal);
for (Iterator tokenFields = _getTokenClassFields(localClass)
.iterator(); tokenFields.hasNext();) {
SootField tokenField = (SootField) tokenFields.next();
if (debug) {
System.out.println("tokenField = " + tokenField);
}
Type replacementType = SootUtilities.createIsomorphicType(
localType, tokenField.getType());
Local replacementLocal = Jimple.v().newLocal(
local.getName() + "_" + tokenField.getName(),
replacementType);
body.getLocals().add(replacementLocal);
tokenFieldToReplacementLocal.put(tokenField,
replacementLocal);
}
}
// Go back again and replace references to fields
// in the token with references to local
// variables.
for (Iterator units = body.getUnits().snapshotIterator(); units
.hasNext();) {
Unit unit = (Unit) units.next();
if (debug) {
System.out.println("ttn2 unit = " + unit);
}
if (unit instanceof InvokeStmt) {
// Handle java.lang.arraycopy
InvokeExpr r = (InvokeExpr) ((InvokeStmt) unit)
.getInvokeExpr();
if (r.getMethod().equals(PtolemyUtilities.arraycopyMethod)) {
if (debug) {
System.out.println("handling as array copy");
}
Local toLocal = (Local) r.getArg(0);
Local fromLocal = (Local) r.getArg(2);
Map toFieldToReplacementLocal = (Map) localToFieldToLocal
.get(toLocal);
Map fromFieldToReplacementLocal = (Map) localToFieldToLocal
.get(fromLocal);
if ((toFieldToReplacementLocal != null)
&& (fromFieldToReplacementLocal != null)) {
if (debug) {
System.out
.println("toFieldToReplacementLocal = "
+ toFieldToReplacementLocal);
}
if (debug) {
System.out
.println("fromFieldToReplacementLocal = "
+ fromFieldToReplacementLocal);
}
{
List argumentList = new LinkedList();
argumentList.add((Local) localToIsNotNullLocal
.get(toLocal));
argumentList.add(r.getArg(1));
argumentList.add((Local) localToIsNotNullLocal
.get(fromLocal));
argumentList.add(r.getArg(3));
argumentList.add(r.getArg(4));
body
.getUnits()
.insertBefore(
Jimple
.v()
.newInvokeStmt(
Jimple
.v()
.newStaticInvokeExpr(
PtolemyUtilities.arraycopyMethod
.makeRef(),
argumentList)),
unit);
}
for (Iterator tokenFields = toFieldToReplacementLocal
.keySet().iterator(); tokenFields.hasNext();) {
SootField tokenField = (SootField) tokenFields
.next();
Local toReplacementLocal = (Local) toFieldToReplacementLocal
.get(tokenField);
Local fromReplacementLocal = (Local) fromFieldToReplacementLocal
.get(tokenField);
List argumentList = new LinkedList();
argumentList.add(toReplacementLocal);
argumentList.add(r.getArg(1));
argumentList.add(fromReplacementLocal);
argumentList.add(r.getArg(3));
argumentList.add(r.getArg(4));
body
.getUnits()
.insertBefore(
Jimple
.v()
.newInvokeStmt(
Jimple
.v()
.newStaticInvokeExpr(
PtolemyUtilities.arraycopyMethod
.makeRef(),
argumentList)),
unit);
}
body.getUnits().remove(unit);
doneSomething = true;
}
}
} else if (unit instanceof AssignStmt) {
AssignStmt stmt = (AssignStmt) unit;
/*Type assignmentType =*/stmt.getLeftOp().getType();
if (stmt.getLeftOp() instanceof Local
&& stmt.getRightOp() instanceof LengthExpr) {
if (debug) {
System.out.println("handling as length expr");
}
LengthExpr lengthExpr = (LengthExpr) stmt.getRightOp();
Local baseLocal = (Local) lengthExpr.getOp();
if (debug) {
System.out.println("operating on " + baseLocal);
}
Map fieldToReplacementArrayLocal = (Map) localToFieldToLocal
.get(baseLocal);
if (fieldToReplacementArrayLocal != null) {
doneSomething = true;
// Get the length of a random one of the replacement fields.
List replacementList = new ArrayList(
fieldToReplacementArrayLocal.keySet());
Collections.sort(replacementList, new Comparator() {
public int compare(Object o1, Object o2) {
SootField f1 = (SootField) o1;
SootField f2 = (SootField) o2;
return f1.getName().compareTo(f2.getName());
}
});
SootField field = (SootField) replacementList
.get(replacementList.size() - 1);
if (debug) {
System.out.println("replace with "
+ fieldToReplacementArrayLocal
.get(field));
}
lengthExpr
.setOp((Local) fieldToReplacementArrayLocal
.get(field));
if (debug) {
System.out.println("unit now = " + unit);
}
// body.getUnits().remove(unit);
}
} else if (stmt.getLeftOp() instanceof InstanceFieldRef) {
// Replace references to fields of tokens.
// FIXME: assign to all aliases as well.
if (debug) {
System.out
.println("is assignment to Instance FieldRef");
}
InstanceFieldRef r = (InstanceFieldRef) stmt
.getLeftOp();
SootField field = r.getField();
if (r.getBase().getType() instanceof RefType) {
RefType type = (RefType) r.getBase().getType();
//System.out.println("BaseType = " + type);
if (SootUtilities.derivesFrom(type.getSootClass(),
PtolemyUtilities.tokenClass)) {
if (debug) {
System.out.println("handling " + unit
+ " token operation");
}
// We have a reference to a field of a token class.
Local baseLocal = (Local) r.getBase();
Local instanceLocal = _getInstanceLocal(body,
baseLocal, field, localToFieldToLocal,
debug);
if (debug) {
System.out.println("instanceLocal = "
+ instanceLocal);
}
if (instanceLocal != null) {
stmt.getLeftOpBox().setValue(instanceLocal);
doneSomething = true;
}
}
}
} else if (stmt.getRightOp() instanceof InstanceFieldRef) {
// Replace references to fields of tokens.
if (debug) {
System.out
.println("is assignment from Instance FieldRef");
}
InstanceFieldRef r = (InstanceFieldRef) stmt
.getRightOp();
SootField field = r.getField();
if (r.getBase().getType() instanceof RefType) {
RefType type = (RefType) r.getBase().getType();
//System.out.println("BaseType = " + type);
if (SootUtilities.derivesFrom(type.getSootClass(),
PtolemyUtilities.tokenClass)) {
if (debug) {
System.out.println("handling " + unit
+ " token operation");
}
// We have a reference to a field of a token class.
Local baseLocal = (Local) r.getBase();
Local instanceLocal = _getInstanceLocal(body,
baseLocal, field, localToFieldToLocal,
debug);
if (debug) {
System.out.println("instanceLocal = "
+ instanceLocal);
}
if (instanceLocal != null) {
stmt.getRightOpBox()
.setValue(instanceLocal);
doneSomething = true;
}
}
}
}
}
}
}
if (debug) {
System.out.println("Specializing types for " + entityClass);
}
// Specialize the token types. Any field we created above
// should now have its correct concrete type.
// TypeSpecializer.specializeTypes(debug, entityClass, unsafeLocalSet);
// Now go through the methods again and handle all token assignments,
// replacing them with assignments on the native replacements.
for (Iterator methods = entityClass.getMethods().iterator(); methods
.hasNext();) {
SootMethod method = (SootMethod) methods.next();
if (debug) {
System.out.println("Replacing token assignments in method "
+ method);
}
JimpleBody body = (JimpleBody) method.retrieveActiveBody();
// InstanceEqualityEliminator.removeInstanceEqualities(body, null, true);
for (Iterator units = body.getUnits().snapshotIterator(); units
.hasNext();) {
Unit unit = (Unit) units.next();