# R8 Optimization: Null Data Flow Analysis (Part 2)

DevFeed: [R8 Optimization: Null Data Flow Analysis (Part 2)](<https://devfeed.tech/articles/r8-optimization-null-data-flow-analysis-part-2-20962.md>)

Original publisher: [Read original article](<https://jakewharton.com/r8-optimization-null-data-flow-analysis-part-2/>)

Published: 2019-01-15T00:00:00Z

Content type: article

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [Optimization](<https://devfeed.tech/topics/optimization.md>), [R8](<https://devfeed.tech/topics/r8.md>), [Android](<https://devfeed.tech/topics/android.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Java](<https://devfeed.tech/topics/java.md>)

Tags: [analysis](<https://devfeed.tech/tags/analysis.md>), [android](<https://devfeed.tech/tags/android.md>), [code](<https://devfeed.tech/tags/code.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [exception](<https://devfeed.tech/tags/exception.md>), [generation](<https://devfeed.tech/tags/generation.md>), [inlining](<https://devfeed.tech/tags/inlining.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [r8](<https://devfeed.tech/tags/r8.md>), [source](<https://devfeed.tech/tags/source.md>), [validation](<https://devfeed.tech/tags/validation.md>)

## AI overview

This article explains how R8 uses nullability information in its intermediate representation to perform null data flow analysis and optimize Kotlin code. It shows how R8 can simplify or eliminate null checks after method inlining, including defensive checks generated by the Kotlin compiler for public APIs.

## Source excerpt

Note: This post is part of a series on D8 and R8, Android's new dexer and optimizer, respectively. For an intro to D8 read "Android's Java 8 support". For an intro to R8 read "R8 Optimization: Staticization". Part 1 of this post demonstrated R8's ability to eliminate null checks after method inlining. This was accomplished by virtue of nullability information being present in R8's (and D8's) intermediate representation (IR). When the arguments flowing into a method were always non-null or always null, the now-inlined null check can be computed at compile-time. Examples in the last two posts have mostly used Kotlin. To improve readability of their bytecode, I've been removing a section of it. The last post started with an example of a coalesce function being called from a main function. fun <T : Any> coalesce(a: T?, b: T?): T? = a ?: b fun main(args: Array<String>) { println(coalesce("one", "two")) println(coalesce(null, "two")) } Multiple versions of the compiled bytecode of this function were shown in that post and they all started with sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream;. This is the bytecode looking up the static System.out field on which it can eventually invoke the println method. If you compile, dex, and dump the bytecode of the Kotlin source above, however, the first bytecodes are something quite different. $ kotlinc *.kt $ java -jar d8.jar \ --lib $ANDROID_HOME/platforms/android-28/android.jar \ --release \ --output . \ *.class kotlin-stdlib-1.3.11.jar $ $ANDROID_HOME/build-tools/28.0.3/dexdump -d classes.dex [00023c] NullsKt.main:([Ljava/lang/String;)V 0000: const-string v0, "args" 0002: invoke-static {v2, v0}, Lkotlin/jvm/internal/Intrinsics;.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V 0005: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; ... Instead of bytecodes representing the body of the function we wrote, the Kotlin compiler first emits a call to the standard library's Intrinstrics.checkParameter