
Change-Id: Ibd45b235c9547dd83b27fedbd414fa5c5eb6a42a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3781549 Reviewed-by: Samuel Huang <huangs@chromium.org> Auto-Submit: Sam Maier <smaier@chromium.org> Commit-Queue: Samuel Huang <huangs@chromium.org> Cr-Commit-Position: refs/heads/main@{#1027416}
81 lines
2.8 KiB
Markdown
81 lines
2.8 KiB
Markdown
# 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.
|