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