package wcet.devel; /* Automated Test Procedure: * * $test$> make P1=test P2=wcet/devel P3=ResolveVirtuals CALLSTRING_LENGTH=3 USE_DFA=yes wcet * $grep$> ^wcet.always-hit:.*cost: 4341 * */ import com.jopdesign.sys.Config; import com.jopdesign.sys.Const; import com.jopdesign.sys.Native; /** * Testcase for Bug#11: * -------------------- * * When using callstrings, resolving virtual method invocations in the control flow graph is * <ol><li/> imprecise * <li/> might lead to cyclic callgraphs * <li/> problematic, as we have to deal with infeasible receivers * </ol> * Concerning (2), we must ensure that no method which is not reachable from the analyzed method is inserted into a * control flow graph (unreachable methods are usually not analyzed). * * For example, suppose we have * <pre> * interface I { f(); } * class A < I { f() { ok; } } * class B < I { f() { loop; } } // assume not reachable from WCET target * a() { g(new A()); } * b() { g(new B()); } // assume not reachable from WCET target * g(I i) { i.f(); } * </pre> * When analyzing a() in this example, if we know that B#f() is not reachable, we SHOULD NOT consider B as a feasible receiver type * for i in g. * * Ideally, we should not resolve virtual invokes statically at all. As a short time fix, unreachable methods should be * excluded when resolving virtual invokes in control flow graphs. * -------------------- * In this test case, we test two unreachable interface implementations, and one callstring sensitive performance difference. */ public class ResolveVirtuals { public static interface I { public void f(); } /* invoking f() is ok */ public static class A implements I { protected int a; @Override public void f() { a = (a+7); } } /* invoking f() is ok, but expensive */ public static class A1 extends A { int b; @Override public void f() { for(int i = 0; i<16;i++) { //@WCA loop = 16 super.f(); b += 7 * a; } } } /* invoking f() leads to cycle in call graph */ public static class B implements I { I target; @Override public void f() { target.f(); } } /* invoking f() is impossible, because there is no implementation of J */ public static interface J { public void f1(); } public static class C implements I { private J j; public C(J j) { this.j = j; } @Override public void f() { j.f1(); } } private A a = new A(); private A1 a1 = new A1(); private B b = new B(); private C c = null; /* test */ public static void g(I i) { i.f(); } public static void a(A a) { g(a); } public static void b(B b) { g(b); } public static void c(C c) { g(c); } static int ts, te, to; static ResolveVirtuals test; public static void main(String[] args) { int dt; ts = Native.rdMem(Const.IO_CNT); te = Native.rdMem(Const.IO_CNT); to = te-ts; test = new ResolveVirtuals(); test.b.target = test.b; /* cycle */ invoke(); if (Config.MEASURE) { dt = te-ts-to; System.out.print("max: "); System.out.println(dt); } } static void invoke() { measure(); if (Config.MEASURE) te = Native.rdMem(Const.IO_CNT); } static void measure() { if (Config.MEASURE) ts = Native.rdMem(Const.IO_CNT); a(test.a); a(test.a1); a(test.a); } }