1*6777b538SAndroid Build Coastguard Worker# Java Asserts in Chromium 2*6777b538SAndroid Build Coastguard WorkerThis doc exists to explain how asserts in Java are enabled and disabled by 3*6777b538SAndroid Build Coastguard WorkerChromium's build system. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker## javac Assertion Bytecode 6*6777b538SAndroid Build Coastguard WorkerWhenever javac compiles a Java class, assertions are transformed into the 7*6777b538SAndroid Build Coastguard Workerfollowing bytecode: 8*6777b538SAndroid Build Coastguard Worker 9*6777b538SAndroid Build Coastguard Worker``` 10*6777b538SAndroid Build Coastguard Worker Code: 11*6777b538SAndroid Build Coastguard Worker 0: getstatic #2 // Static field $assertionsDisabled 12*6777b538SAndroid Build Coastguard Worker 3: ifne 20 // Conditional jump past assertion throw 13*6777b538SAndroid Build Coastguard Worker 12: new #3 // Class java/lang/AssertionError 14*6777b538SAndroid Build Coastguard Worker 19: athrow // Throwing AssertionError 15*6777b538SAndroid Build Coastguard Worker 20: return 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker// NOTE: this static block was made just to check the desiredAssertionStatus. 18*6777b538SAndroid Build Coastguard Worker// There was no static block on the class before javac created one. 19*6777b538SAndroid Build Coastguard Worker static {}; 20*6777b538SAndroid Build Coastguard Worker Code: 21*6777b538SAndroid Build Coastguard Worker 2: invokevirtual #6 // Method java/lang/Class.desiredAssertionStatus() 22*6777b538SAndroid Build Coastguard Worker 5: ifne 12 23*6777b538SAndroid Build Coastguard Worker 8: iconst_1 24*6777b538SAndroid Build Coastguard Worker 9: goto 13 25*6777b538SAndroid Build Coastguard Worker 12: iconst_0 26*6777b538SAndroid Build Coastguard Worker 13: putstatic #2 // Static field $assertionsDisabled 27*6777b538SAndroid Build Coastguard Worker 16: return 28*6777b538SAndroid Build Coastguard Worker``` 29*6777b538SAndroid Build Coastguard Worker 30*6777b538SAndroid Build Coastguard WorkerTL;DR - every single assertion is gated behind a `assertionDisabled` flag check, 31*6777b538SAndroid Build Coastguard Workerwhich is a static field that can be set by the JRE's 32*6777b538SAndroid Build Coastguard Worker`setDefaultAssertionStatus`, `setPackageAssertionStatus`, and 33*6777b538SAndroid Build Coastguard Worker`setClassAssertionStatus` methods. 34*6777b538SAndroid Build Coastguard Worker 35*6777b538SAndroid Build Coastguard Worker## Assertion Enabling/Disabling 36*6777b538SAndroid Build Coastguard WorkerOur tools which consume javac output, namely R8 and D8, each have flags which 37*6777b538SAndroid Build Coastguard Workerthe build system uses to enable or disable asserts. We control this with the 38*6777b538SAndroid Build Coastguard Worker`enable_java_asserts` gn arg. It does this by deleting the gating check on 39*6777b538SAndroid Build Coastguard Worker`assertionsDisabled` when enabling, and by eliminating any reference to the 40*6777b538SAndroid Build Coastguard Workerassert when disabling. 41*6777b538SAndroid Build Coastguard Worker 42*6777b538SAndroid Build Coastguard Worker```java 43*6777b538SAndroid Build Coastguard Worker// Example equivalents of: 44*6777b538SAndroid Build Coastguard Workera = foo(); 45*6777b538SAndroid Build Coastguard Workerassert a != 0; 46*6777b538SAndroid Build Coastguard Workerreturn a; 47*6777b538SAndroid Build Coastguard Worker 48*6777b538SAndroid Build Coastguard Worker// Traditional, unoptimized javac output. 49*6777b538SAndroid Build Coastguard Workera = foo(); 50*6777b538SAndroid Build Coastguard Workerif (!assertionsDisabled && a == 0) { 51*6777b538SAndroid Build Coastguard Worker throw new AssertionError(); 52*6777b538SAndroid Build Coastguard Worker} 53*6777b538SAndroid Build Coastguard Workerreturn a; 54*6777b538SAndroid Build Coastguard Worker 55*6777b538SAndroid Build Coastguard Worker// Optimized with assertions enabled. 56*6777b538SAndroid Build Coastguard Workera = foo(); 57*6777b538SAndroid Build Coastguard Workerif (a == 0) { 58*6777b538SAndroid Build Coastguard Worker throw new AssertionError(); 59*6777b538SAndroid Build Coastguard Worker} 60*6777b538SAndroid Build Coastguard Workerreturn a; 61*6777b538SAndroid Build Coastguard Worker 62*6777b538SAndroid Build Coastguard Worker// Optimized with assertions disabled. 63*6777b538SAndroid Build Coastguard Workera = foo(); 64*6777b538SAndroid Build Coastguard Workerreturn a; 65*6777b538SAndroid Build Coastguard Worker``` 66*6777b538SAndroid Build Coastguard Worker 67*6777b538SAndroid Build Coastguard Worker## Assertion Enabling on Canary 68*6777b538SAndroid Build Coastguard WorkerRecently we [enabled 69*6777b538SAndroid Build Coastguard Workerasserts](https://chromium-review.googlesource.com/c/chromium/src/+/3307087) on 70*6777b538SAndroid Build Coastguard WorkerCanary. It spiked our crash rate, and it was decided to not do this again, as 71*6777b538SAndroid Build Coastguard Workerit's bad user experience to crash the app incessantly for non-fatal issues. 72*6777b538SAndroid Build Coastguard Worker 73*6777b538SAndroid Build Coastguard WorkerSo, we asked the R8 team for a feature which would rewrite the bytecode of these 74*6777b538SAndroid Build Coastguard Workerassertions, which they implemented for us. Now, instead of just turning it on 75*6777b538SAndroid Build Coastguard Workerand throwing an `AssertionError`, [R8 would call a provided assertion 76*6777b538SAndroid Build Coastguard Workerhandler](https://r8.googlesource.com/r8/+/aefe7bc18a7ce19f3e9c6dac0bedf6d182bbe142/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java#124) 77*6777b538SAndroid Build Coastguard Workerwith the `AssertionError`. We then wrote a [silent assertion 78*6777b538SAndroid Build Coastguard Workerreporter](https://chromium-review.googlesource.com/c/chromium/src/+/3746261) 79*6777b538SAndroid Build Coastguard Workerand this reports Java `AssertionErrors` to our crash server without crashing 80*6777b538SAndroid Build Coastguard Workerthe browser. 81