Menu

Another Optimisation Idea

2005-04-25
2012-12-17
  • Robin Watts

    Robin Watts - 2005-04-25

    Hi,

    I've read the FAQ question 3, and its not clear to me if this suggestion is implemented already or not - if it is, then sorry for wasting your time.

    To cut a long story short... I've got some code that does:

      tag = block[i];
      switch (tag)
      {
         case 0:
            method0(arg1, arg2, arg3, arg4);
            break;
         case 1:
            method1(arg1, arg2, arg3, arg4);
            break;
         case 2:
            method2(arg1, arg2, arg3, arg4);
            break;
         case 3:
         default:
            method3(arg1, arg2, arg3, arg4);
            break;
      }

    I won't post the disassembly of this here, but basically, every arm of the switch starts with the same 5 instructions.

    Would it be possible for proguard to spot this and to pull those instructions out to before the switch bytecode? It'd need some checking done to see that those instructions don't affect the value that the switch is working on, but it'd be dead useful.

    Thanks

    Robin

    P.S. #include "std-proguard-rave" here. It's really an excellent tool already!

     
    • Eric Lafortune

      Eric Lafortune - 2005-04-25

      This is an interesting idea that is not implemented yet. The check would require some thought. I was already planning to merge code at the other end of the branches, since branches often share some code at the tail end, simply jumping to the same instruction afterwards. But first, I'll have to get the next version stabilized.

      Glad you like ProGuard. Cheers,

      Eric.

       
    • Robin Watts

      Robin Watts - 2005-04-26

      Thanks. I look forward to forthcoming versions then!
      If there is anything I can do to help, please don't hesitate to say.

      Some other ideas (which you've probably thought of long before me, but I mention them here just on the offchance):

      1) Its probably obvious, but the same optimisation would apply to code like:

      if (test)
         fred(arg1, arg2, arg3)
      else
        george(arg1, arg2, arg3)

      which in C could be written:

        ((test) ? fred : george)(arg1, arg2, arg3);

      2) Variables 0,1,2,3 are 'special' in that they only take 1 byte instructions to access them. In non-static functions 0 is assigned to 'this', but we have
      freedom to pick what variables we put in the others.

      Would it be possible to see which variables are used most in a routine, and to shuffle the assignments so that they are (0), 1, 2, 3 ?

      (This would make the code smaller, and (in simple non-JITed stuff) maybe faster?)

      Even better (but the verifier may complain at this) can variables be 'reused' where there scope does
      not overlap?

      3) Lots of compiled java seems to do:

      aload 0;
      do something;
      aload 0;
      do something else;
      aload 0;
      do another thing;
      aload 0;
      do yet another thing ;

      There is scope to turn that into:

      aload 0;
      dup
      dup2
      do something;
      do something else;
      do another thing;
      do yet another thing;

      That saves 1 byte (for the aload 0 case) but more for the aload n case (where n > 3).

      Thanks again,

      Robin

       
      • Gili Tzabari

        Gili Tzabari - 2005-04-26

        Not to butt in too much here, but wouldn't it be great if two people worked on ProGuard instead of just one? You could get twice as much done :)

         
        • Eric Lafortune

          Eric Lafortune - 2005-04-26

          Ah, twice as much, if only... Actually, I still prefer to work alone on this project. I really like doing things my way, without the compromises and overhead of larger scale development.

          Eric.

           
      • Eric Lafortune

        Eric Lafortune - 2005-04-26

        I've considered idea #2 -- I'm a bit concerned about the amount of effort for a few bytes gain. The preverifier can be picky, so you'd have to be careful. Note that the parameters already use variables 1, 2, etc., so there's not that much leeway.

        A simple instance of idea #3 is already being performed, with subsequent store/load instruction pairs. Doing this across instructions would be more challenging, but the technique would open up more possibilities.

        Cheers,

        Eric.

        PS: Shame the instruction set isn't as elegant as the ARM instruction set. :-)

         
    • Robin Watts

      Robin Watts - 2005-04-26

      > P.S. Shame the instruction set isn't as elegant as the ARM instruction set. :-)

      Spooky!

       
    • Robin Watts

      Robin Watts - 2005-05-03

      Another random idea:

      I have the following code:

      found = false;
      for ( i = 32 ; i >= 0; i--)
      {
          if (array[i] != null)
          {
             found = true;
             break;
          }
      }
      if (found == false)
      {
         ...
      }

      Once compiled, the break will turn into a goto to exit the loop. It jumps immediately to the test
      which can never be true.

      A cunning optimisation would be to make the break jump past the trailing if.

      I appreciate that thats possibly an order of magnitude harder to code for than most of the other optimisations mentioned, and its not clear how often this kind of thing will appear in general code.

      Better to mention it here and probably have it deemed too hard/insignificant than not to mention it and for it to be easier/more useful than I thought, I guess...

      Ta,

      Robin

       
      • Eric Lafortune

        Eric Lafortune - 2005-05-03

        In ProGuard version 3.2, branches are simplified after a control flow analysis (using partial evaluation, i.e. simulation of the execution using abstract values). At that point, the collected information is too general to simplify this particular construct. It would be difficult indeed.

        Eric.