| # Java Asserts in Chromium |
| This doc exists to explain how asserts in Java are enabled and disabled by |
| Chromium's build system. |
| |
| ## javac Assertion Bytecode |
| Whenever javac compiles a Java class, assertions are transformed into the |
| following bytecode: |
| |
| ``` |
| Code: |
| 0: getstatic #2 // Static field $assertionsDisabled |
| 3: ifne 20 // Conditional jump past assertion throw |
| 12: new #3 // Class java/lang/AssertionError |
| 19: athrow // Throwing AssertionError |
| 20: return |
| |
| // NOTE: this static block was made just to check the desiredAssertionStatus. |
| // There was no static block on the class before javac created one. |
| static {}; |
| Code: |
| 2: invokevirtual #6 // Method java/lang/Class.desiredAssertionStatus() |
| 5: ifne 12 |
| 8: iconst_1 |
| 9: goto 13 |
| 12: iconst_0 |
| 13: putstatic #2 // Static field $assertionsDisabled |
| 16: return |
| ``` |
| |
| TL;DR - every single assertion is gated behind a `assertionDisabled` flag check, |
| which is a static field that can be set by the JRE's |
| `setDefaultAssertionStatus`, `setPackageAssertionStatus`, and |
| `setClassAssertionStatus` methods. |
| |
| ## Assertion Enabling/Disabling |
| Our tools which consume javac output, namely R8 and D8, each have flags which |
| the build system uses to enable or disable asserts. We control this with the |
| `enable_java_asserts` gn arg. It does this by deleting the gating check on |
| `assertionsDisabled` when enabling, and by eliminating any reference to the |
| assert when disabling. |
| |
| ```java |
| // Example equivalents of: |
| a = foo(); |
| assert a != 0; |
| return a; |
| |
| // Traditional, unoptimized javac output. |
| a = foo(); |
| if (!assertionsDisabled && a == 0) { |
| throw new AssertionError(); |
| } |
| return a; |
| |
| // Optimized with assertions enabled. |
| a = foo(); |
| if (a == 0) { |
| throw new AssertionError(); |
| } |
| return a; |
| |
| // Optimized with assertions disabled. |
| a = foo(); |
| return a; |
| ``` |
| |
| ## Assertion Enabling on Canary |
| Recently we [enabled |
| asserts](https://chromium-review.googlesource.com/c/chromium/src/+/3307087) on |
| Canary. It spiked our crash rate, and it was decided to not do this again, as |
| it's bad user experience to crash the app incessantly for non-fatal issues. |
| |
| So, we asked the R8 team for a feature which would rewrite the bytecode of these |
| assertions, which they implemented for us. Now, instead of just turning it on |
| and throwing an `AssertionError`, [R8 would call a provided assertion |
| handler](https://r8.googlesource.com/r8/+/aefe7bc18a7ce19f3e9c6dac0bedf6d182bbe142/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java#124) |
| with the `AssertionError`. We then wrote a [silent assertion |
| reporter](https://chromium-review.googlesource.com/c/chromium/src/+/3746261) |
| and this reports Java `AssertionErrors` to our crash server without crashing |
| the browser. |