package dk.brics.xact.analysis.transformations;
import java.util.LinkedList;
import dk.brics.xact.analysis.flowgraph.Edge;
import dk.brics.xact.analysis.flowgraph.FlowGraph;
import dk.brics.xact.analysis.flowgraph.Method;
import dk.brics.xact.analysis.flowgraph.Statement;
import dk.brics.xact.analysis.flowgraph.Variable;
import dk.brics.xact.analysis.flowgraph.VariableFilter;
import dk.brics.xact.analysis.flowgraph.statements.CallStm;
import dk.brics.xact.analysis.flowgraph.statements.VarStm;
import dk.brics.xact.analysis.soot.ControlFlowBuilder;
import dk.brics.xact.analysis.soot.StatementPair;
/**
* Removes all call statements and inserts assignments and interprocedural edges instead.
*/
public class CallTransformer {
public void run(FlowGraph graph) {
// collect all call statements first so we don't modify the node set while iterating it
LinkedList<CallStm> calls = new LinkedList<CallStm>();
for (Statement stm : graph.getNodes()) {
if (stm instanceof CallStm)
calls.add((CallStm)stm);
}
ControlFlowBuilder cfg = new ControlFlowBuilder(graph, null);
// transform!
for (CallStm call : calls) {
Method target = call.getMethod();
cfg.setOrigin(call.getOrigin());
Statement start = cfg.currentStatement();
Variable[] params = target.getParameters();
Variable[] args = call.getArguments();
VariableFilter paramsOnly = new VariableFilter(false, VariableFilter.Kind.CALL);
VariableFilter argsOnly = new VariableFilter(false);
VariableFilter notArgs = new VariableFilter(true);
VariableFilter resultFilter = new VariableFilter(call.getResult(), VariableFilter.Kind.RETURN);
VariableFilter returnFilter = new VariableFilter(target.getReturnVar());
for (int i=0; i<args.length; i++) {
paramsOnly.addVariable(params[i]);
argsOnly.addVariable(args[i]);
notArgs.removeVariable(args[i]);
if (call.isArgumentMutable(i)) {
resultFilter.addVariable(call.getArgument(i));
returnFilter.addVariable(target.getParameter(i));
}
}
cfg.addFilter(argsOnly);
for (int i=0; i<args.length; i++) {
cfg.addStatement(new VarStm(params[i], args[i], call.getOrigin()));
}
graph.addEdge(cfg.currentStatement(), target.getEntry(), paramsOnly);
cfg.moveToStatement(target.getExit());
cfg.addStatement(new VarStm(call.getResult(), target.getReturnVar(), call.getOrigin()), returnFilter);
/*for (int i=0; i<args.length; i++) {
if (call.isArgumentMutable(i)) {
cfg.addStatement(new VarStm(call.getArgument(i), target.getParameter(i), call.getOrigin()));
}
}*/
cfg.addFilter(resultFilter);
VariableFilter notResult = new VariableFilter(true);
notResult.removeVariable(call.getResult());
graph.addEdge(start, cfg.currentStatement(), notResult);
StatementPair pair = cfg.finish();
for (Edge<Statement,VariableFilter> edge : graph.getInEdges(call)) {
graph.addEdge(edge.getFrom(), pair.first, edge.getData());
}
for (Edge<Statement,VariableFilter> edge : graph.getOutEdges(call)) {
graph.addEdge(pair.last, edge.getTo(), edge.getData());
}
graph.removeNode(call);
}
}
}