soot-oss / soot

Soot - A Java optimization framework
GNU Lesser General Public License v2.1
2.87k stars 706 forks source link

SharedInitializationLocalSplitter maybe produce more complex code. And what's 'sils'? #1699

Open canliture opened 3 years ago

canliture commented 3 years ago

Describe the bug SharedInitializationLocalSplitter may transform codes into more complex codes in Soot version 4.3.0-Snapshot

Input file

// Here is the code to be tested in file Test.java in the directory './target/test-classes/mydir'
public class Test {

    public int test(boolean b) {
        int x = 100;
        while (b) {
            if (x < 200) {
                x = 100;
            } else {
                x = 200;
            }
        }
        return x;
    }
}

// Here is the minimal code to drive the test in another file 'MyTest.java'
public class MyTest {

    @Test
    public void test() {
        // just one file Test.java shown above to be transformed in the directory 'mydir'
        Options.v().set_process_dir(Arrays.asList("./target/test-classes/mydir"));

        Options.v().set_output_format(Options.output_format_jimple);

        Scene.v().loadNecessaryClasses();

        PackManager.v().runPacks();

        PackManager.v().writeOutput();
    }
}

To reproduce Running MyTest#test method to test, can produce 'Test.jimple' in the default directory 'sootOutput'. The produced content is:

public class Test extends java.lang.Object
{

    public void <init>()
    {
        Test r0;

        r0 := @this: Test;

        specialinvoke r0.<java.lang.Object: void <init>()>();

        return;
    }

    public int test(boolean)
    {
        short s0, s1, s2;
        Test r0;
        boolean z0;

        r0 := @this: Test;

        z0 := @parameter0: boolean;

        s0 = 100;

        s2 = 100;

        s1 = 100;

     label1:
        if z0 == 0 goto label3;

        if s1 >= 200 goto label2;

        s0 = 100;

        s2 = 100;

        s1 = 100;

        goto label1;

     label2:
        s0 = 200;

        s2 = 200;

        s1 = 200;

        goto label1;

     label3:
        return s2;
    }
}

In the 'test' method in the jimple file, we can see continuous 3 redundant assignments:

s0 = 200;
s2 = 200;
s1 = 200;

Expected behavior From a view on programming language semantics, the produced jimple may be correct. But SharedInitializationLocalSplitter optimizer let the codes more complex.

However, In Soot version 4.2.1, it produces optimized codes that are not redundant:

// ignore other codes
public int test() {
    Test r0;
    short s0;
    boolean $z0;

    r0 := @this: Test;

    s0 = 100;

 label1:
    $z0 = r0.<Test: boolean b>;

    if $z0 == 0 goto label3;

    if s0 >= 200 goto label2;

    s0 = 100;

    goto label1;

 label2:
    s0 = 200;

    goto label1;

 label3:
    return s0;
}

Stacktrace or some my thinkings By spending time debugging the code between versions 4.2.1 and 4.3.0-snapshot, I found a difference on the method JimpleBodyPack#applyPhaseOptions between two versions that leads to two different output jimple file.

My problem I want to know:

I reviewed the code in SharedInitializationLocalSplitter#internalTransform. It just collects Units that uses Locals, and the Locals defined in the form 'x = Constant' (x is a Local and Constant is any constant),and inserts a new generated Local definition that assigned by the Constant, and replaces the use place with the generated Local. Like this:

x = 100;
if x >= 200 goto label;

will be transformed into

x = 100;
x_1 = 100;
if x_1 >= 200 goto label;

Maybe what I understand is not correct by reviewing the code.

I can't find documents about "jb.sils" at Soot command-line options

I don't know what 'sils' means? What place it will be useful?

linghuiluo commented 3 years ago

see discussion here https://github.com/soot-oss/soot/issues/1614#issuecomment-853287543