Inline calls Remove dynamic type checks Unroll loops Code motion

- 65 - Some optimizing compilers can reduce the necessary parts of compiled files. For example, the .class file includes a pool of constants a structure containing various constants, and an optimizing compiler can minimize the size of the constant pool by combining and reducing entries.

3.4.2.9 Alter access control to speed up invocations

At least one optimizing compiler the DashO optimizer by PreEmptive provides the option to alter the access control to methods. The rationale for this is that any non- public method has access control on that method since it is access restricted, i.e., the runtime system must verify at some point that the caller to a method has access to calling that method. However, public methods require no such runtime checks. So the thinking is that any non- public method must have some overhead compared to an identical method declared as public . The result is that the compiler supports normal compilation so that any incorrect accesses are caught at the compilation stage, and the subsequent compiled class can have all its methods changed to public . This is, of course, a security risk.

3.4.2.10 Inline calls

Every optimizing compiler supports inlining . However, the degree of inlining supported can vary enormously, as different compilers are more or less aggressive about inlining see the extended discussion in Section 3.5.2 . Inlining is the technique in which a method call is directly replaced with the code for that method; for example, the code as written may be: private int method1 { return method2 ; } private int method2 { return 5; } With inlining operating to optimize method1 , this code is compiled into the equivalent of: the call to method2 is replaced with the code in method2 private int method1 { return 5; } private int method2 { return 5; }

3.4.2.11 Remove dynamic type checks

Every compiler removes dynamic type checks when the compiler can establish they are unnecessary. The JDK compiler removes casts that are obviously unnecessary. For example, consider the following two lines of code: Integer i = new Integer3; Integer j = Integer i; The JDK compiler removes the obviously unnecessary cast here, and the code gets compiled as if the source was: Integer i = new Integer3; Integer j = i; This is very basic. A more sophisticated optimizing compiler can analyze a program far more intensively and eliminate further casting operations that the compiler can ascertain are always true. The instanceof operation is similar to casting the test applied by instanceof differs from a class cast test, in that a cast on null always succeeds, but null instanceof SomeClass always returns false and an optimizing compiler can also remove some tests involving instanceof . - 66 -

3.4.2.12 Unroll loops

Loop unrolling makes the loop body larger by explicitly repeating the body statements while changing the amount by which the loop variable increases or decreases. This reduces the number of tests and iterations the loop requires to be completed. This is extensively covered in Chapter 7 .

3.4.2.13 Code motion

Code motion moves calculations out of loops that need calculating only once. Consider the next code example: for int i = 0; i z.length; i++ z[i] = x Maths.absy; The elements of an array are being assigned the same value each time, but the assignment expression is still calculating the value each time. Applying code motion, this code is automatically converted to: int t1 = x Maths.absy; for int i = 0; i z.length; i++ z[i] = t1; Another place where code motion is useful is in eliminating or reducing redundant tests though compilers are usually less effective at this. Consider the following method: public String aMethodString first, String passed { StringBuffer copy = new StringBufferpassed; if first == null || first.length == 0 return passed; else { ...some manipulation of the string buffer to do something return copy.toString ; } } This method creates an unnecessary new object if the first string is null or zero length. This should be recoded or bytecodes should be generated, so that the new object creation is moved to the else clause: public String aMethodString first, String passed { if first == null || first.length == 0 return passed; else { StringBuffer copy = new StringBufferpassed; ...some manipulation of the string buffer to do something return copy.toString ; } } It would be nice, but difficult, for a compiler to apply this automatically, but this type of optimization probably needs to be applied manually. For the compiler to apply this sort of optimization, it needs to know that creating a new StringBuffer has no side effects, and so the creation can reasonably be moved to a different part of the code. - 67 - Both this technique and the next one are actually good coding practices.

3.4.2.14 Eliminate common subexpressions