1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
build / android / docs / java_asserts.md [blame]
# 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.