/*
This file is part of JOP, the Java Optimized Processor
see <http://www.jopdesign.com/>
Copyright (C) 2011, Benedikt Huber (benedikt@vmars.tuwien.ac.at)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jopdesign.common.code;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.jopdesign.common.AppInfo;
import com.jopdesign.common.AppSetup;
import com.jopdesign.common.MethodInfo;
import com.jopdesign.common.TestFramework;
import com.jopdesign.common.code.ControlFlowGraph.CFGNode;
import com.jopdesign.common.code.ControlFlowGraph.InvokeNode;
import com.jopdesign.common.code.SuperGraph.ContextCFG;
import com.jopdesign.common.code.SuperGraph.SuperEdge;
import com.jopdesign.common.code.SuperGraph.SuperGraphEdge;
import com.jopdesign.common.code.SuperGraph.SuperGraphNode;
import com.jopdesign.common.code.SuperGraph.SuperInvokeEdge;
import com.jopdesign.common.misc.BadGraphException;
import com.jopdesign.common.misc.Iterators;
/**
* Purpose:
* @author Benedikt Huber (benedikt@vmars.tuwien.ac.at)
*
*/
public class SegmentTest implements CFGProvider {
AppInfo appInfo;
public static void check(String msg, boolean test) {
System.out.println(msg + ": " + (test ? "OK" : "FAIL"));
}
public static<T> void checkEquals(String msg, T expect, T actual) {
if(expect.equals(actual)) {
System.out.println(msg + " OK both " + expect);
} else {
System.out.println(msg + " FAILED because expected /= actual: " + expect + " /= " + actual);
}
}
public static<T extends Comparable<T>> void checkLessEqual(String msg, T o1, T o2) {
if(o1.compareTo(o2) < 1) {
System.out.println(msg + " OK with " + o1 + " <= " + o2);
} else {
System.out.println(msg + " FAILED because " + o1 + " > " + o2);
}
}
public static void main(String[] args) {
TestFramework testFramework = new TestFramework();
AppSetup setup = testFramework.setupAppSetup("java/tools/test/test/cg1.zip", null);
AppInfo appInfo = testFramework.setupAppInfo("wcet.devel.CallGraph1.run", true);
SegmentTest testInst = new SegmentTest();
testInst.appInfo = appInfo;
MethodInfo mainMethod = appInfo.getMainMethod();
/* count total number of CFG nodes */
SuperGraph superGraph = new SuperGraph(testInst, testInst.getFlowGraph(mainMethod), 2);
Segment segment = Segment.methodSegment(mainMethod, CallString.EMPTY, testInst, 2, superGraph.getInfeasibleEdgeProvider());
int count = 0;
for(ContextCFG cgNode : superGraph.getCallGraphNodes()) {
try {
cgNode.getCfg().exportDOT(new File("/tmp/cfg-"+cgNode.getCfg().getMethodInfo().getClassName()+"_"+cgNode.getCfg().getMethodInfo().getShortName()+".dot"));
} catch (IOException e) {}
count += cgNode.getCfg().vertexSet().size();
}
checkEquals("[Segment 1] Expected node count", (count-2), Iterators.size(segment.getNodes()));
try {
segment.exportDOT(new File("/tmp/cg1-segment.dot"));
} catch (IOException e) {
e.printStackTrace();
}
/* root */
ContextCFG root = superGraph.getRootNode();
/* Build a segment cuts all invokes in those methods invoked by run() */
Segment segment2;
/* root entries */
Set<SuperGraphEdge> entries = new HashSet<SuperGraphEdge>();
Iterators.addAll(entries, superGraph.liftCFGEdges(root, root.getCfg().outgoingEdgesOf(root.getCfg().getEntry())));
Set<SuperGraphEdge> exits = new HashSet<SuperGraphEdge>();
int cfgNodeCandidateCount = root.getCfg().vertexSet().size();
/* find callees */
for(SuperEdge superEdge : superGraph.getCallGraph().outgoingEdgesOf(root)) {
if(! (superEdge instanceof SuperInvokeEdge)) continue;
ContextCFG callee1 = superGraph.getCallGraph().getEdgeTarget(superEdge);
cfgNodeCandidateCount += callee1.getCfg().vertexSet().size();
/* find all edges from invoke nodes */
for(CFGNode cfgNode : callee1.getCfg().vertexSet()) {
if(cfgNode instanceof InvokeNode) {
Iterators.addAll(exits, superGraph.outgoingEdgesOf(new SuperGraphNode(callee1, cfgNode)));
}
}
}
segment2 = new Segment(superGraph, entries, exits);
exits = segment2.getExitEdges(); /* reachable exits */
try {
segment2.exportDOT(new File("/tmp/cg1-segment2.dot"));
} catch (IOException e) {
e.printStackTrace();
}
checkEquals("[Segment 2] Expected node count", 14, Iterators.size(segment2.getNodes())+2);
checkLessEqual("[Segment 2] Expected node count <= |root + directly invoked|",
Iterators.size(segment2.getNodes()) + 2, cfgNodeCandidateCount);
/* Another segment, with entries the exits of the last segment, and exits all invokes in methods the entries */
Segment segment3;
entries = segment2.getExitEdges();
exits = new HashSet<SuperGraphEdge>();
cfgNodeCandidateCount = 0;
/* find callees */
for(SuperGraphEdge superEdge : entries) {
SuperGraphNode node1 = superEdge.getTarget();
for(SuperEdge superEdge2 : superGraph.getCallGraph().outgoingEdgesOf(node1.getContextCFG())) {
if(! (superEdge2 instanceof SuperInvokeEdge)) continue;
ContextCFG callee2 = superGraph.getCallGraph().getEdgeTarget(superEdge2);
/* find all edges from invoke nodes */
for(CFGNode cfgNode : callee2.getCfg().vertexSet()) {
if(cfgNode instanceof InvokeNode) {
Iterators.addAll(exits, superGraph.outgoingEdgesOf(new SuperGraphNode(callee2, cfgNode)));
}
}
}
}
segment3 = new Segment(superGraph, entries, exits);
try {
segment3.exportDOT(new File("/tmp/cg1-segment3.dot"));
} catch (IOException e) {
e.printStackTrace();
}
checkEquals("[Segment 2] 3 exits", 3, segment2.getExitEdges().size());
checkEquals("[Segment 3] 3 entries", 3, segment3.getEntryEdges().size());
checkEquals("[Segment 3] 4 exits", 4, segment3.getExitEdges().size());
}
@Override
public ControlFlowGraph getFlowGraph(MethodInfo method) {
ControlFlowGraph cfg = appInfo.getFlowGraph(method);
try {
cfg.resolveVirtualInvokes();
cfg.insertReturnNodes();
} catch (BadGraphException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return cfg;
}
}