package com.googlecode.dex2jar.ir.test; import static com.googlecode.dex2jar.ir.expr.Exprs.*; import static com.googlecode.dex2jar.ir.stmt.Stmts.*; import com.googlecode.dex2jar.ir.Trap; import com.googlecode.dex2jar.ir.expr.Exprs; import com.googlecode.dex2jar.ir.stmt.Stmts; import org.junit.Assert; import org.junit.Test; import com.googlecode.dex2jar.ir.expr.Local; import com.googlecode.dex2jar.ir.expr.Value; import com.googlecode.dex2jar.ir.stmt.LabelStmt; import com.googlecode.dex2jar.ir.stmt.Stmt; import com.googlecode.dex2jar.ir.stmt.Stmt.ST; import com.googlecode.dex2jar.ir.ts.UnSSATransformer; public class UnSSATransformerTransformerTest extends BaseTransformerTest<UnSSATransformer> { @Test public void test00Base() { initMethod(true, "V"); Local a = addLocal("a"); Local b = addLocal("b"); Local phi = addLocal("p"); LabelStmt L1 = newLabel(); Stmt s1 = addStmt(nAssign(a, nString("123"))); addStmt(nIf(niGt(nInt(100), nInt(0)), L1)); Stmt s2 = addStmt(nAssign(b, nString("456"))); addStmt(L1); attachPhi(L1,nAssign(phi, nPhi(a, b))); addStmt(nReturn(phi)); transform(); Assert.assertEquals("insert assign after s1", ST.ASSIGN, s1.getNext().st); Assert.assertEquals("insert assign after s1", ST.ASSIGN, s2.getNext().st); // Assert.assertEquals("local should index to 0", 0, b._ls_index); } @Test public void test01SSAProblem() { initMethod(true, "I"); Local a = addLocal("a"); Local b = addLocal("b"); Local phi = addLocal("p"); LabelStmt L0 = newLabel(); addStmt(nAssign(a, nInt(2))); addStmt(L0); attachPhi(L0, nAssign(phi, nPhi(a, b))); Stmt stmt = addStmt(nAssign(b, niAdd(phi, nInt(0)))); addStmt(nIf(niGt(nInt(100), nInt(0)), L0)); addStmt(nReturn(phi)); transform(); Assert.assertTrue("a new local should introduced to solve the problem", stmt.getPre() != L0); } @Test public void test02_3branches() { initMethod(true, "I"); Local a = addLocal("a"); Local b = addLocal("b"); Local c = addLocal("c"); Local d = addLocal("d"); Local phi = addLocal("p"); LabelStmt L0 = newLabel(); LabelStmt L1 = newLabel(); addStmt(nAssign(a, nInt(2))); addStmt(nIf(niGt(nInt(100), nInt(0)), L1)); addStmt(nAssign(b, nInt(3))); addStmt(nIf(niGt(nInt(100), nInt(0)), L0)); addStmt(nAssign(c, nInt(4))); addStmt(nLock(c)); addStmt(nGoto(L1)); addStmt(L0); addStmt(nAssign(d, nInt(5))); addStmt(nLock(d)); addStmt(L1); attachPhi(L1, nAssign(phi, nPhi(a, b))); addStmt(nReturn(phi)); transform(); } @Test public void test04OneInPhi() { initMethod(true, "V"); Local a = addLocal("a"); Local b = addLocal("b"); Local phi = addLocal("p"); LabelStmt L1 = newLabel(); Stmt s1 = addStmt(nAssign(a, nString("123"))); Stmt j = addStmt(nIf(niGt(nInt(100), nInt(0)), L1)); Stmt s2 = addStmt(nAssign(b, nString("456"))); addStmt(L1); attachPhi(L1, nAssign(phi, nPhi(a))); addStmt(nReturn(phi)); transform(); Assert.assertTrue("p=a should inserted", j.getPre() != s1); } @Test public void test05OneInPhiLoop() { initMethod(true, "V"); Local a = addLocal("a"); Local b = addLocal("b"); Local phi = addLocal("p"); Stmt s1 = addStmt(nAssign(a, nString("123"))); LabelStmt L1 = newLabel(); addStmt(L1); attachPhi(L1, nAssign(phi, nPhi(a))); addStmt(nVoidInvoke(nInvokeStatic(new Value[] { phi }, "LAAA;", "bMethod", new String[] { "Ljava/lang/String;" }, "V"))); addStmt(nAssign(b, nString("456"))); // phi is still live here Stmt s2 = addStmt(nVoidInvoke(nInvokeStatic(new Value[] { b }, "LBBB;", "cMethod", new String[] { "Ljava/lang/String;" }, "V"))); addStmt(nIf(niGt(nInt(100), nInt(0)), L1)); addStmt(nReturnVoid()); transform(); Assert.assertTrue("p=a should inserted", s1.getPre() != L1); } @Test public void test06TwoJump() { initMethod(true, "V"); Local a1 = addLocal("a1"); Local a2 = addLocal("a2"); Local a = addLocal("a"); Local b1 = addLocal("b1"); Local b2 = addLocal("b2"); Local b = addLocal("b"); addStmt(nAssign(a1, nString("123"))); addStmt(nAssign(b1, nString("123"))); LabelStmt L1 = newLabel(); addStmt(L1); attachPhi(L1, nAssign(a, nPhi(a1, a2))); attachPhi(L1, nAssign(b, nPhi(b1, b2))); addStmt(nAssign(a2, nString("456"))); addStmt(nIf(niGt(nInt(100), nInt(0)), L1)); addStmt(nAssign(b2, nString("456"))); addStmt(nIf(niGt(nInt(100), nInt(0)), L1)); addStmt(nReturnVoid()); transform(); // Assert.assertTrue("must assign different index", ls1._ls_index != ls2._ls_index); } @Test public void test07PhiInHandler() { initMethod(true, "I"); Local a1 = addLocal("a1"); Local a2 = addLocal("a2"); Local a = addLocal("a"); Local ex = addLocal("ex"); addStmt(Stmts.nAssign(a1, nInt(1))); LabelStmt L0 = newLabel(); LabelStmt L2 = newLabel(); LabelStmt L3 = newLabel(); addStmt(L0); addStmt(Stmts.nVoidInvoke(Exprs.nInvokeStatic(new Value[0], "La;", "m", new String[0], "V"))); addStmt(Stmts.nAssign(a2, nInt(2))); addStmt(Stmts.nVoidInvoke(Exprs.nInvokeStatic(new Value[0], "La;", "m", new String[0], "V"))); addStmt(L2); addStmt(Stmts.nReturn(a2)); addStmt(L3); Stmt ref = addStmt(Stmts.nIdentity(ex, Exprs.nExceptionRef("Ljava/lang/Exception;"))); attachPhi(L3, Stmts.nAssign(a, nPhi(a1, a2))); addStmt(Stmts.nVoidInvoke(Exprs.nInvokeStatic(new Value[] { a1 }, "La;", "m", new String[] { "I" }, "V"))); addStmt(Stmts.nReturn(a)); method.traps.add(new Trap(L0, L2, new LabelStmt[] { L3 }, new String[] { "Ljava/lang/Exception" })); transform(); Assert.assertTrue("the fix assign should insert after x=@ExceptionRef", L3.getNext() == ref); } }