java - Does the compiler/JIT recognize redundant checks? -


lets have multiple applications layers, external libraries , java standard libraries , dealing string.

at each , every command when hand in nullpointer, application going throw exception. prevent that, supposed check null object , handle yourself.

now means check null, external libraries check null , java standard libraries check null , potentially low level c code checks null.

isn't redundant ? somehow optimized compiler , branch prediciton handle cases ?

as indicated comments , other answers: there many degrees of freedom , variables involved here. on highest level, refers design principles, aiming @ avoiding "meaningful" null values, , thus, explicit null checks. (this difficult sometimes. semantically meaningful cases of null built standard api). said redundant null checks can not avoided, because 1 never knows method called. on lower, technical levels, distinction between javac compiler , jit pointed out. on lowest level, things branch prediction may come play (this has become remarkably famous due array processing question...).


referring jit, curious 1 case may particularly interesting pattern described - namely, whether redundant null checks eliminated during method inlining.

i tried create simple test this. it's harder expected create sensible , meaningful test here: idea create very simple version of chain of method calls suggested:

public static int processstringa(dummystring string) {     if (string == null) return -2;     return processstringb(string); }  public static int processstringb(dummystring string) {     if (string == null) return -3;     return processstringc(string); }  public static int processstringc(dummystring string) {     if (string == null) return -4;     return string.value; } 

i spread on several classes, , added "dummy instructions" make less trivial (but still allow inlining), , ran following test eventually:

import java.util.arraylist; import java.util.list; import java.util.random;   public class nestednullchecktest {     public static void main(string[] args)     {         (int i=0; i<1000; i++)         {             runtest();         }     }      private static void runtest()     {         list<dummystring> list = createlist();         int blackhole = 0;         (dummystring string : list)         {             blackhole += processstringtest(string);         }         system.out.println("result "+blackhole);     }       private static int processstringtest(dummystring string)     {         if (string == null)         {             return -1;         }         return nestednullchecka.processstringa(string);     }       private static list<dummystring> createlist()     {         list<dummystring> list = new arraylist<dummystring>();         random random = new random(0);          (int i=0; i<100000; i++)         {             if (random.nextdouble() < 0.1)             {                 list.add(null);             }             else             {                 list.add(new dummystring(i));             }         }         return list;     } }  class dummystring {     int value;     dummystring(int value)     {         this.value = value;     } }  class nestednullchecka {     public static int processstringa(dummystring string)     {         if (string == null)         {             return -2;         }         string.value += 1;         return nestednullcheckb.processstringb(string);     } }   class nestednullcheckb {     public static int processstringb(dummystring string)     {         if (string == null)         {             return -3;         }         string.value -= 2;         return nestednullcheckc.processstringc(string);     } }   class nestednullcheckc {     public static int processstringc(dummystring string)     {         if (string == null)         {             return -4;         }         string.value *= 2;         return string.value;     } } 

running

java -server -xx:+unlockdiagnosticvmoptions -xx:+traceclassloading -xx:+logcompilation -xx:+printassembly nestednullchecktest  

eventually spilled out following assembly processstringtest method:

decoding compiled method 0x00b51488: code: [entry point] [verified entry point] [constants]   # {method} {0x3d90046c} &apos;processstringtest&apos; &apos;(ldummystring;)i&apos; in &apos;nestednullchecktest&apos;   # parm0:    ecx       = &apos;dummystring&apos;   #           [sp+0x10]  (sp of caller)   0x00b51580: sub    $0xc,%esp   0x00b51586: mov    %ebp,0x8(%esp)     ;*synchronization entry                                         ; - nestednullchecktest::processstringtest@-1 (line 30)    0x00b5158a: test   %ecx,%ecx   0x00b5158c: je     0x00b515a4         ;*ifnonnull                                         ; - nestednullchecktest::processstringtest@1 (line 30)    0x00b5158e: mov    0x8(%ecx),%eax   0x00b51591: shl    %eax   0x00b51593: add    $0xfffffffe,%eax   ;*imul                                         ; - nestednullcheckc::processstringc@13 (line 103)                                         ; - nestednullcheckb::processstringb@18 (line 90)                                         ; - nestednullchecka::processstringa@18 (line 76)                                         ; - nestednullchecktest::processstringtest@7 (line 34)    0x00b51596: mov    %eax,0x8(%ecx)     ;*putfield value                                         ; - nestednullcheckc::processstringc@14 (line 103)                                         ; - nestednullcheckb::processstringb@18 (line 90)                                         ; - nestednullchecka::processstringa@18 (line 76)                                         ; - nestednullchecktest::processstringtest@7 (line 34)    0x00b51599: add    $0x8,%esp   0x00b5159c: pop    %ebp   0x00b5159d: test   %eax,0x970000      ;   {poll_return}   0x00b515a3: ret       0x00b515a4: mov    $0xffffffff,%eax   0x00b515a9: jmp    0x00b51599   0x00b515ab: hlt       ...   0x00b515bf: hlt     [exception handler] [stub code]   0x00b515c0: jmp    0x00af5e40         ;   {no_reloc} [deopt handler code]   0x00b515c5: push   $0xb515c5          ;   {section_word}   0x00b515ca: jmp    0x00adbfc0         ;   {runtime_call}   0x00b515cf: hlt     

take huge grain of salt - 1 consider artifact of inappropriate test - @ least dummy example, 1 can say:

yes, jit compiler (sometimes) eliminates redundant checks (for example, during method inlining)

there 1 null check, , 1 return instruction, returning -1, topmost method call.

one dig through hoptspot code find optimization pass does compaction step, general (somewhat broad) answer jit remarkably smart in many cases, , does eliminate checks "obviously" redundant.


Comments

Popular posts from this blog

ios - RestKit 0.20 — CoreData: error: Failed to call designated initializer on NSManagedObject class (again) -

java - Digest auth with Spring Security using javaconfig -

laravel - PDOException in Connector.php line 55: SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES) -