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