How do Proguard remove a class method?

Asked

Viewed 318 times

15

I’m not getting Proguard 4.10 to make a method static turn inline. I can only do that with instance methods.

For example, this little bit:

public final class Calc {
    private int x = 0;
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int i = s.nextInt();

        Calc c = new Calc();
        int res = c.getX();
        if ((c.getX() & 1) != 0)
            res++;
        else
            res += 2;
        c.setX(res);

        System.out.println(res);
    }
}

Once processed by Proguard transforms into (disregarding obfuscation):

public final class Calc {
    private int x = 0;
}

public class Main {
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int i = s.nextInt();

        Calc c = new Calc();
        int res = c.x;
        if ((c.x & 1) != 0)
            res++;
        else
            res += 2;
        c.x = res;

        System.out.println(res);
    }
}

However, I adapt the classes, and transform the methods into static, that stretch below does not change (disregarding the obfuscation):

public final class Calc {
    private static int x = 0;
    public static int getX() {
        return x;
    }
    public static void setX(int x) {
        Calc.x = x;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int i = s.nextInt();

        int res = Calc.getX();
        if ((Calc.getX() & 1) != 0)
            res++;
        else
            res += 2;
        Calc.setX(res);

        System.out.println(res);
    }
}

To answer any questions, here is the configuration I am using in both cases:

-dontskipnonpubliclibraryclassmembers
-optimizationpasses 9
-allowaccessmodification
-mergeinterfacesaggressively
-dontusemixedcaseclassnames
-dontpreverify
-keepclasseswithmembers public class * {
    public static void main(java.lang.String[]);
}
-keep class * extends java.sql.Driver
-keep class * extends javax.swing.plaf.ComponentUI {
    public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent);
}
-keepclasseswithmembers,allowshrinking class * {
    native <methods>;
}

Am I missing something? There is no option to make Proguard optimize and make methods static inline?

Already these three documentations (besides many others) and I found nothing mentioning this case. It would be a limitation of Proguard?

Optimizations

Usage

Examples

  • I don’t know if you’ve solved it yet, but see if it helps you:&#xD;&#xD; http://stackoverflow.com/questions/18452928/remove-unused-classes-with-proguard-for-android

  • @Albertolourenço Valeu, but it’s not quite that yet :( I need to make a method static of a class be replaced by its content. But, thanks! :)

1 answer

5


I hope I can help you after so long, follow my answer:

Am I missing something? Is there any option to make the Proguard optimize and make Static inline methods?

No, the Proguard doesn’t make inlining of class methods (or superclasses) which have statistic initiators, their static access methods can fire a static initializer, may cause problems in the application outside the scope of the "compiler", for example:

The static declaration of x:

private static int x = 0;

Causes Calc has a static initializer implicit:

public final class Calc {
    private static int x;
    static { // inicializador estatico implicito 
     x = 0; 
    }
   // ... continua ...
}

Suppose we have a static initializer in class or superclasses, :

static { 
 setupDatabaseConfig(); 
}

I know it’s not your case, but making sure no problems occur has been inserted this cutoff criterion until it refines to "Escape Analysis" of inlining optimizations and that can ensure that no collateral problems occur in eligible situations.

I confess that I did some tests (with your example) in the last version (5.2) of Proguard and did not succeed in inlining. But I still recommend the latest version (because there were refinements).


Follows the method of Proguard, which is safeguarded by inlining in static methods and in uninitialized subsets:
Stretch of Methodinliner.java:

 // Only inline the method if it comes from the a class with at most
    // a subset of the initialized superclasses.
    ((accessFlags & ClassConstants.ACC_STATIC) == 0 ||
     programClass.equals(targetClass)                        ||
     initializedSuperClasses(targetClass).containsAll(initializedSuperClasses(programClass))))


ps: This being the case I can compile a version of Proguard ignoring the criterion of deleting static inlining initializers and you can use it for specific purposes.

  • 3

    Reginaldo, I am shocked by your level of knowledge on the subject! Thank you very much! I appreciate the "custom version" of Proguard, but the design runs on different machines, and must use the standard version. But, I was curious about one thing: the simple access to a class A field from another class B is no longer enough to trigger the static initializer of A? For example class A { public Static int x; ... } class B { ... void m() { A.x = 9; } ... }

  • 1

    @carlosrafaelgn, at runtime any class loaded to the classloader will have its static initializer executed, the problem occurs when performing a static analysis of a global subroutine (Static), when we do not know exactly the moment of its activation, in escape analysis we consider that "Pointer has escaped", so static method -usually are not optimized- by its overall aspect, the same (inlined) could be being called at a static boot, so Proguard only inline into non-static classes and subsets initialized methods.

  • Got it! The problem is in the phase of static analysis! Again, thank you!!! D

Browser other questions tagged

You are not signed in. Login or sign up in order to post.