Index Previous Next

Chained assignments

It's well known that an assignment expression results in a value which can in turn be used as the right-hand side of another assignment. This gives us the convenient abbreviation:

   public class test {
      public int x, y, z ;

      public void f() {
         x = y = z = 0 ;
      }
   }

for which the compiler produces this code:

   aload_0
   aload_0
   aload_0
   iconst_0
   dup_x1
   putfield thing/z I
   dup_x1
   putfield thing/y I
   putfield thing/x I
   return

The sequence

   aload_0
   aload_0
   iconst_0
   dup_x1

can be replaced with

   aload_0
   iconst_0
   dup2

where dup2 is used to duplicate the top two words on the stack, with a saving of one byte. This results in the following code:

   aload_0
   aload_0
   iconst_0
   dup2
   putfield thing/z I
   dup_x1
   putfield thing/y I
   putfield thing/x I
   return

Applying the same trick again results in a further reduction to:

   aload_0
   iconst_0
   dup2
   putfield thing/z I
   dup2
   putfield thing/y I
   putfield thing/x I
   return

The same technique could be applied for longer chains of assignments, but I expect that chains of more than two assignments are likely to be rare. As before rules have been included for other types of instructions to push an integer on the stack: iconst, bipush, sipush, ldc and iload. Also, boolean variables have been handled as well as ints.

Testing these optimisations with a million executions of the assignments gives the following results:

       Original    Bytes    Unoptimised       Optimised
         value     saved     time (ms)        time (ms)

             0       1          547              468
            12       1          554              486
           250       1          562              485
       250,000       1          554              554
     local int       1          572              499


Index Previous Next