See https://issuetracker.google.com/issues/231837768
Should be fixed by this commit, which is not yet part of an Android Gradle plugin release.
As
dump-baseline.py
shows, this is another ordering issue; and
sort-baseline.py
can be used as a workaround.
$ cmp 1.profm 2.profm
1.profm 2.profm differ: byte 24, line 1
$ diff -Naur <( repro-apk dump-baseline 1.profm ) <( repro-apk dump-baseline 2.profm )
profm version=002
num_dex_files=2
profile_idx=0
- profile_key='classes2.dex'
- num_type_ids=2418
- num_class_ids=0
-profile_idx=1
profile_key='classes.dex'
num_type_ids=8122
num_class_ids=738
+profile_idx=1
+ profile_key='classes2.dex'
+ num_type_ids=2418
+ num_class_ids=0
$ repro-apk sort-baseline 1.profm 1s.profm
$ cmp 1s.profm 2.profm && echo OK
OK
The problem is that in ArtProfile.kt
:
val profileData = HashMap<DexFile, DexFileData>()
Which means the order of iterating over profileData
is non-deterministic.
In ArtProfileSerializer.kt
, METADATA_FOR_N
, V0_1_0_P
, and V0_0_9_OMR1
sort before iterating:
profileData.entries.sortedBy { it.key.name }
And V0_0_5_O
and V0_0_1_N
sort as well:
for ((dex, data) in profileData.toSortedMap(DexFile)) {
But METADATA_0_0_2
doesn't sort:
profileData.onEachIndexed { index, entry ->
And neither does V0_1_5_S
:
profileData.forEach { entry ->
profileData.onEachIndexed { index, entry ->
profileData.onEachIndexed { index, entry ->
Which is why their output is non-deterministic.
// NB: Android Studio can't find the imports; this does not affect the
// actual build since Gradle can find them just fine.
import com.android.tools.profgen.ArtProfileKt
import com.android.tools.profgen.ArtProfileSerializer
import com.android.tools.profgen.DexFile
project.afterEvaluate {
tasks.each { task ->
if (task.name.startsWith("compile") && task.name.endsWith("ReleaseArtProfile")) {
task.doLast {
outputs.files.each { file ->
if (file.name.endsWith(".profm")) {
println("Sorting ${file} ...")
def version = ArtProfileSerializer.valueOf("METADATA_0_0_2")
def profile = ArtProfileKt.ArtProfile(file)
def keys = new ArrayList(profile.profileData.keySet())
def sortedData = new LinkedHashMap()
Collections.sort keys, new DexFile.Companion()
keys.each { key -> sortedData[key] = profile.profileData[key] }
new FileOutputStream(file).with {
write(version.magicBytes$profgen)
write(version.versionBytes$profgen)
version.write$profgen(it, sortedData, "")
}
}
}
}
}
}
}
NB: this (ab)uses internal
functions/values.
The internal functions are not accessible from Kotlin, but you can use the
groovy code as a script plugin from build.gradle.kts
:
// NB: when using build.gradle.kts instead of build.gradle, save this file as
// app/fix-profm.gradle and add the following line to app/build.gradle.kts:
// apply(from = "fix-profm.gradle")
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
// NB: use this to specifiy the AGP version directly:
// classpath 'com.android.tools.build:gradle:7.4.0'
// NB: use this with gradle/libs.versions.toml (and modify as needed):
classpath "com.android.tools.build:gradle:${libs.versions.android.gradle.get()}"
}
}
// NB: Android Studio can't find the imports; this does not affect the
// actual build since Gradle can find them just fine.
import com.android.tools.profgen.ArtProfileKt
import com.android.tools.profgen.ArtProfileSerializer
import com.android.tools.profgen.DexFile
project.afterEvaluate {
tasks.each { task ->
if (task.name.startsWith("compile") && task.name.endsWith("ReleaseArtProfile")) {
task.doLast {
outputs.files.each { file ->
if (file.name.endsWith(".profm")) {
println("Sorting ${file} ...")
def version = ArtProfileSerializer.valueOf("METADATA_0_0_2")
def profile = ArtProfileKt.ArtProfile(file)
def keys = new ArrayList(profile.profileData.keySet())
def sortedData = new LinkedHashMap()
Collections.sort keys, new DexFile.Companion()
keys.each { key -> sortedData[key] = profile.profileData[key] }
new FileOutputStream(file).with {
write(version.magicBytes$profgen)
write(version.versionBytes$profgen)
version.write$profgen(it, sortedData, "")
}
}
}
}
}
}
}
Using
sort-baseline.py
from reproducible-apk-tools
in build.gradle
:
// NB: assumes reproducible-apk-tools is a submodule in the app repo's
// root dir; adjust the path accordingly if it is found elsewhere
project.afterEvaluate {
tasks.compileReleaseArtProfile.doLast {
outputs.files.each { file ->
if (file.toString().endsWith(".profm")) {
exec {
commandLine(
"../reproducible-apk-tools/inplace-fix.py",
"sort-baseline", file
)
}
}
}
}
}
Add this to build.gradle
:
tasks.whenTaskAdded { task ->
if (task.name.contains("ArtProfile")) {
task.enabled = false
}
}
or this to build.gradle.kts
:
tasks.whenTaskAdded {
if (name.contains("ArtProfile")) {
enabled = false
}
}
Before:
> Task :app:mergeReleaseArtProfile
> Task :app:compileReleaseArtProfile
After:
> Task :app:mergeReleaseArtProfile SKIPPED
> Task :app:compileReleaseArtProfile SKIPPED
assets/dexopt/baseline.prof
assets/dexopt/baseline.profm
NB: this is just one example we analysed, other apps may have other differences.
classes.dex
classes2.dex
classes3.dex
kotlin/internal/internal.kotlin_builtins
kotlin/kotlin.kotlin_builtins
kotlin/ranges/ranges.kotlin_builtins
kotlin/reflect/reflect.kotlin_builtins
These differences seem to be an expected result of the changes.
Lkotlin/io/path/DirectoryEntriesReader;
Lkotlin/io/path/FileVisitorBuilder;
Lkotlin/io/path/FileVisitorImpl;
Lkotlin/io/path/LinkFollowing;
Lkotlin/io/path/PathNode;
Lkotlin/io/path/PathTreeWalkKt;
Lkotlin/io/path/PathWalkOption;
Lkotlin/io/path/FileVisitorBuilderImpl;
Lkotlin/io/path/PathTreeWalk;
Lkotlin/io/path/PathTreeWalk$bfsIterator$1;
Lkotlin/io/path/PathTreeWalk$dfsIterator$1;
Lkotlin/jvm/optionals/OptionalsKt;
Lkotlin/ranges/OpenEndRange$DefaultImpls;
Lkotlin/ranges/OpenEndRange;
Lkotlin/ranges/ComparableOpenEndRange;
Lkotlin/ranges/OpenEndDoubleRange;
Lkotlin/ranges/OpenEndFloatRange;
kotlin.io.path.DirectoryEntriesReader.<init>:(Z)V
kotlin.io.path.DirectoryEntriesReader.getFollowLinks:()Z
kotlin.io.path.DirectoryEntriesReader.preVisitDirectory:(Ljava/lang/Object;Ljava/nio/file/attribute/BasicFileAttributes;)Ljava/nio/file/FileVisitResult;
kotlin.io.path.DirectoryEntriesReader.preVisitDirectory:(Ljava/nio/file/Path;Ljava/nio/file/attribute/BasicFileAttributes;)Ljava/nio/file/FileVisitResult;
kotlin.io.path.DirectoryEntriesReader.readEntries:(Lkotlin/io/path/PathNode;)Ljava/util/List;
kotlin.io.path.DirectoryEntriesReader.visitFile:(Ljava/lang/Object;Ljava/nio/file/attribute/BasicFileAttributes;)Ljava/nio/file/FileVisitResult;
kotlin.io.path.DirectoryEntriesReader.visitFile:(Ljava/nio/file/Path;Ljava/nio/file/attribute/BasicFileAttributes;)Ljava/nio/file/FileVisitResult;
kotlin.io.path.FileVisitorImpl.<init>:(Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)V
kotlin.io.path.FileVisitorImpl.postVisitDirectory:(Ljava/lang/Object;Ljava/io/IOException;)Ljava/nio/file/FileVisitResult;
kotlin.io.path.FileVisitorImpl.postVisitDirectory:(Ljava/nio/file/Path;Ljava/io/IOException;)Ljava/nio/file/FileVisitResult;
kotlin.io.path.FileVisitorImpl.preVisitDirectory:(Ljava/lang/Object;Ljava/nio/file/attribute/BasicFileAttributes;)Ljava/nio/file/FileVisitResult;
kotlin.io.path.FileVisitorImpl.preVisitDirectory:(Ljava/nio/file/Path;Ljava/nio/file/attribute/BasicFileAttributes;)Ljava/nio/file/FileVisitResult;
kotlin.io.path.FileVisitorImpl.visitFile:(Ljava/lang/Object;Ljava/nio/file/attribute/BasicFileAttributes;)Ljava/nio/file/FileVisitResult;
kotlin.io.path.FileVisitorImpl.visitFile:(Ljava/nio/file/Path;Ljava/nio/file/attribute/BasicFileAttributes;)Ljava/nio/file/FileVisitResult;
kotlin.io.path.FileVisitorImpl.visitFileFailed:(Ljava/lang/Object;Ljava/io/IOException;)Ljava/nio/file/FileVisitResult;
kotlin.io.path.FileVisitorImpl.visitFileFailed:(Ljava/nio/file/Path;Ljava/io/IOException;)Ljava/nio/file/FileVisitResult;
kotlin.io.path.LinkFollowing.<clinit>:()V
kotlin.io.path.LinkFollowing.<init>:()V
kotlin.io.path.LinkFollowing.toLinkOptions:(Z)[Ljava/nio/file/LinkOption;
kotlin.io.path.LinkFollowing.toVisitOptions:(Z)Ljava/util/Set;
kotlin.io.path.PathNode.<init>:(Ljava/nio/file/Path;Ljava/lang/Object;Lkotlin/io/path/PathNode;)V
kotlin.io.path.PathNode.getContentIterator:()Ljava/util/Iterator;
kotlin.io.path.PathNode.getKey:()Ljava/lang/Object;
kotlin.io.path.PathNode.getParent:()Lkotlin/io/path/PathNode;
kotlin.io.path.PathNode.getPath:()Ljava/nio/file/Path;
kotlin.io.path.PathNode.setContentIterator:(Ljava/util/Iterator;)V
kotlin.io.path.PathTreeWalkKt.access$createsCycle:(Lkotlin/io/path/PathNode;)Z
kotlin.io.path.PathTreeWalkKt.access$keyOf:(Ljava/nio/file/Path;[Ljava/nio/file/LinkOption;)Ljava/lang/Object;
kotlin.io.path.PathTreeWalkKt.createsCycle:(Lkotlin/io/path/PathNode;)Z
kotlin.io.path.PathTreeWalkKt.keyOf:(Ljava/nio/file/Path;[Ljava/nio/file/LinkOption;)Ljava/lang/Object;
kotlin.io.path.PathWalkOption.$values:()[Lkotlin/io/path/PathWalkOption;
kotlin.io.path.PathWalkOption.<clinit>:()V
kotlin.io.path.PathWalkOption.<init>:(Ljava/lang/String;I)V
kotlin.io.path.PathWalkOption.valueOf:(Ljava/lang/String;)Lkotlin/io/path/PathWalkOption;
kotlin.io.path.PathWalkOption.values:()[Lkotlin/io/path/PathWalkOption;
kotlin.io.path.FileVisitorBuilderImpl.<init>:()V
kotlin.io.path.FileVisitorBuilderImpl.checkIsNotBuilt:()V
kotlin.io.path.FileVisitorBuilderImpl.checkNotDefined:(Ljava/lang/Object;Ljava/lang/String;)V
kotlin.io.path.FileVisitorBuilderImpl.build:()Ljava/nio/file/FileVisitor;
kotlin.io.path.FileVisitorBuilderImpl.onPostVisitDirectory:(Lkotlin/jvm/functions/Function2;)V
kotlin.io.path.FileVisitorBuilderImpl.onPreVisitDirectory:(Lkotlin/jvm/functions/Function2;)V
kotlin.io.path.FileVisitorBuilderImpl.onVisitFile:(Lkotlin/jvm/functions/Function2;)V
kotlin.io.path.FileVisitorBuilderImpl.onVisitFileFailed:(Lkotlin/jvm/functions/Function2;)V
kotlin.io.path.PathTreeWalk.<init>:(Ljava/nio/file/Path;[Lkotlin/io/path/PathWalkOption;)V
kotlin.io.path.PathTreeWalk.access$getFollowLinks:(Lkotlin/io/path/PathTreeWalk;)Z
kotlin.io.path.PathTreeWalk.access$getIncludeDirectories:(Lkotlin/io/path/PathTreeWalk;)Z
kotlin.io.path.PathTreeWalk.access$getLinkOptions:(Lkotlin/io/path/PathTreeWalk;)[Ljava/nio/file/LinkOption;
kotlin.io.path.PathTreeWalk.access$getStart$p:(Lkotlin/io/path/PathTreeWalk;)Ljava/nio/file/Path;
kotlin.io.path.PathTreeWalk.bfsIterator:()Ljava/util/Iterator;
kotlin.io.path.PathTreeWalk.dfsIterator:()Ljava/util/Iterator;
kotlin.io.path.PathTreeWalk.getFollowLinks:()Z
kotlin.io.path.PathTreeWalk.getIncludeDirectories:()Z
kotlin.io.path.PathTreeWalk.getLinkOptions:()[Ljava/nio/file/LinkOption;
kotlin.io.path.PathTreeWalk.isBFS:()Z
kotlin.io.path.PathTreeWalk.yieldIfNeeded:(Lkotlin/sequences/SequenceScope;Lkotlin/io/path/PathNode;Lkotlin/io/path/DirectoryEntriesReader;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
kotlin.io.path.PathTreeWalk.iterator:()Ljava/util/Iterator;
kotlin.io.path.PathsKt__PathUtilsKt.fileVisitor:(Lkotlin/jvm/functions/Function1;)Ljava/nio/file/FileVisitor;
kotlin.io.path.PathsKt__PathUtilsKt.visitFileTree:(Ljava/nio/file/Path;IZLkotlin/jvm/functions/Function1;)V
kotlin.io.path.PathsKt__PathUtilsKt.visitFileTree:(Ljava/nio/file/Path;Ljava/nio/file/FileVisitor;IZ)V
kotlin.io.path.PathsKt__PathUtilsKt.visitFileTree$default:(Ljava/nio/file/Path;IZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
kotlin.io.path.PathsKt__PathUtilsKt.visitFileTree$default:(Ljava/nio/file/Path;Ljava/nio/file/FileVisitor;IZILjava/lang/Object;)V
kotlin.io.path.PathsKt__PathUtilsKt.walk:(Ljava/nio/file/Path;[Lkotlin/io/path/PathWalkOption;)Lkotlin/sequences/Sequence;
kotlin.io.path.PathTreeWalk$bfsIterator$1.<init>:(Lkotlin/io/path/PathTreeWalk;Lkotlin/coroutines/Continuation;)V
kotlin.io.path.PathTreeWalk$bfsIterator$1.create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
kotlin.io.path.PathTreeWalk$bfsIterator$1.invoke:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
kotlin.io.path.PathTreeWalk$bfsIterator$1.invoke:(Lkotlin/sequences/SequenceScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
kotlin.io.path.PathTreeWalk$bfsIterator$1.invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;
kotlin.io.path.PathTreeWalk$dfsIterator$1.<init>:(Lkotlin/io/path/PathTreeWalk;Lkotlin/coroutines/Continuation;)V
kotlin.io.path.PathTreeWalk$dfsIterator$1.create:(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
kotlin.io.path.PathTreeWalk$dfsIterator$1.invoke:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
kotlin.io.path.PathTreeWalk$dfsIterator$1.invoke:(Lkotlin/sequences/SequenceScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
kotlin.io.path.PathTreeWalk$dfsIterator$1.invokeSuspend:(Ljava/lang/Object;)Ljava/lang/Object;
j$.util.Optional.orElse:(Ljava/lang/Object;)Ljava/lang/Object;
kotlin.jvm.optionals.OptionalsKt.asSequence:(Lj$/util/Optional;)Lkotlin/sequences/Sequence;
kotlin.jvm.optionals.OptionalsKt.getOrDefault:(Lj$/util/Optional;Ljava/lang/Object;)Ljava/lang/Object;
kotlin.jvm.optionals.OptionalsKt.getOrElse:(Lj$/util/Optional;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
kotlin.jvm.optionals.OptionalsKt.getOrNull:(Lj$/util/Optional;)Ljava/lang/Object;
kotlin.jvm.optionals.OptionalsKt.toCollection:(Lj$/util/Optional;Ljava/util/Collection;)Ljava/util/Collection;
kotlin.jvm.optionals.OptionalsKt.toList:(Lj$/util/Optional;)Ljava/util/List;
kotlin.jvm.optionals.OptionalsKt.toSet:(Lj$/util/Optional;)Ljava/util/Set;
kotlin.ranges.OpenEndRange$DefaultImpls.contains:(Lkotlin/ranges/OpenEndRange;Ljava/lang/Comparable;)Z
kotlin.ranges.OpenEndRange$DefaultImpls.isEmpty:(Lkotlin/ranges/OpenEndRange;)Z
kotlin.ranges.RangesKt__RangesKt.contains:(Lkotlin/ranges/ClosedRange;Ljava/lang/Object;)Z
kotlin.ranges.RangesKt__RangesKt.contains:(Lkotlin/ranges/OpenEndRange;Ljava/lang/Object;)Z
kotlin.ranges.RangesKt__RangesKt.rangeUntil:(DD)Lkotlin/ranges/OpenEndRange;
kotlin.ranges.RangesKt__RangesKt.rangeUntil:(FF)Lkotlin/ranges/OpenEndRange;
kotlin.ranges.RangesKt__RangesKt.rangeUntil:(Ljava/lang/Comparable;Ljava/lang/Comparable;)Lkotlin/ranges/OpenEndRange;
kotlin.ranges.URangesKt___URangesKt.rangeUntil-5PvTz6A:(SS)Lkotlin/ranges/UIntRange;
kotlin.ranges.URangesKt___URangesKt.rangeUntil-J1ME1BU:(II)Lkotlin/ranges/UIntRange;
kotlin.ranges.URangesKt___URangesKt.rangeUntil-Kr8caGY:(BB)Lkotlin/ranges/UIntRange;
kotlin.ranges.URangesKt___URangesKt.rangeUntil-eb3DHEI:(JJ)Lkotlin/ranges/ULongRange;
kotlin.reflect.KCallable$DefaultImpls.getName$annotations:()V
kotlin.streams.jdk8.StreamsKt.$r8$lambda$D6rJ2g9z2pCQAEMFkqgtKPOz0JA:(Lkotlin/sequences/Sequence;)Lj$/util/Spliterator;
kotlin.streams.jdk8.StreamsKt.asStream$lambda$4:(Lkotlin/sequences/Sequence;)Lj$/util/Spliterator;
kotlin.math.MathKt__MathJVMKt.cbrt:(D)D
kotlin.math.MathKt__MathJVMKt.cbrt:(F)F
kotlin.ranges.ComparableOpenEndRange.<init>:(Ljava/lang/Comparable;Ljava/lang/Comparable;)V
kotlin.ranges.ComparableOpenEndRange.contains:(Ljava/lang/Comparable;)Z
kotlin.ranges.ComparableOpenEndRange.equals:(Ljava/lang/Object;)Z
kotlin.ranges.ComparableOpenEndRange.getEndExclusive:()Ljava/lang/Comparable;
kotlin.ranges.ComparableOpenEndRange.getStart:()Ljava/lang/Comparable;
kotlin.ranges.ComparableOpenEndRange.hashCode:()I
kotlin.ranges.ComparableOpenEndRange.isEmpty:()Z
kotlin.ranges.ComparableOpenEndRange.toString:()Ljava/lang/String;
kotlin.ranges.OpenEndDoubleRange.<init>:(DD)V
kotlin.ranges.OpenEndDoubleRange.lessThanOrEquals:(DD)Z
kotlin.ranges.OpenEndDoubleRange.contains:(D)Z
kotlin.ranges.OpenEndDoubleRange.contains:(Ljava/lang/Comparable;)Z
kotlin.ranges.OpenEndDoubleRange.equals:(Ljava/lang/Object;)Z
kotlin.ranges.OpenEndDoubleRange.getEndExclusive:()Ljava/lang/Comparable;
kotlin.ranges.OpenEndDoubleRange.getEndExclusive:()Ljava/lang/Double;
kotlin.ranges.OpenEndDoubleRange.getStart:()Ljava/lang/Comparable;
kotlin.ranges.OpenEndDoubleRange.getStart:()Ljava/lang/Double;
kotlin.ranges.OpenEndDoubleRange.hashCode:()I
kotlin.ranges.OpenEndDoubleRange.isEmpty:()Z
kotlin.ranges.OpenEndDoubleRange.toString:()Ljava/lang/String;
kotlin.ranges.OpenEndFloatRange.<init>:(FF)V
kotlin.ranges.OpenEndFloatRange.lessThanOrEquals:(FF)Z
kotlin.ranges.OpenEndFloatRange.contains:(F)Z
kotlin.ranges.OpenEndFloatRange.contains:(Ljava/lang/Comparable;)Z
kotlin.ranges.OpenEndFloatRange.equals:(Ljava/lang/Object;)Z
kotlin.ranges.OpenEndFloatRange.getEndExclusive:()Ljava/lang/Comparable;
kotlin.ranges.OpenEndFloatRange.getEndExclusive:()Ljava/lang/Float;
kotlin.ranges.OpenEndFloatRange.getStart:()Ljava/lang/Comparable;
kotlin.ranges.OpenEndFloatRange.getStart:()Ljava/lang/Float;
kotlin.ranges.OpenEndFloatRange.hashCode:()I
kotlin.ranges.OpenEndFloatRange.isEmpty:()Z
kotlin.ranges.OpenEndFloatRange.toString:()Ljava/lang/String;
kotlin.ranges.RangesKt___RangesKt.byteRangeContains:(Lkotlin/ranges/OpenEndRange;I)Z
kotlin.ranges.RangesKt___RangesKt.byteRangeContains:(Lkotlin/ranges/OpenEndRange;J)Z
kotlin.ranges.RangesKt___RangesKt.byteRangeContains:(Lkotlin/ranges/OpenEndRange;S)Z
kotlin.ranges.RangesKt___RangesKt.contains:(Lkotlin/ranges/IntRange;B)Z
kotlin.ranges.RangesKt___RangesKt.contains:(Lkotlin/ranges/IntRange;J)Z
kotlin.ranges.RangesKt___RangesKt.contains:(Lkotlin/ranges/IntRange;S)Z
kotlin.ranges.RangesKt___RangesKt.contains:(Lkotlin/ranges/LongRange;B)Z
kotlin.ranges.RangesKt___RangesKt.contains:(Lkotlin/ranges/LongRange;I)Z
kotlin.ranges.RangesKt___RangesKt.contains:(Lkotlin/ranges/LongRange;S)Z
kotlin.ranges.RangesKt___RangesKt.doubleRangeContains:(Lkotlin/ranges/OpenEndRange;F)Z
kotlin.ranges.RangesKt___RangesKt.intRangeContains:(Lkotlin/ranges/OpenEndRange;B)Z
kotlin.ranges.RangesKt___RangesKt.intRangeContains:(Lkotlin/ranges/OpenEndRange;J)Z
kotlin.ranges.RangesKt___RangesKt.intRangeContains:(Lkotlin/ranges/OpenEndRange;S)Z
kotlin.ranges.RangesKt___RangesKt.longRangeContains:(Lkotlin/ranges/OpenEndRange;B)Z
kotlin.ranges.RangesKt___RangesKt.longRangeContains:(Lkotlin/ranges/OpenEndRange;I)Z
kotlin.ranges.RangesKt___RangesKt.longRangeContains:(Lkotlin/ranges/OpenEndRange;S)Z
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(CC)Lkotlin/ranges/CharRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(BB)Lkotlin/ranges/IntRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(BI)Lkotlin/ranges/IntRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(BS)Lkotlin/ranges/IntRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(IB)Lkotlin/ranges/IntRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(II)Lkotlin/ranges/IntRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(IS)Lkotlin/ranges/IntRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(SB)Lkotlin/ranges/IntRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(SI)Lkotlin/ranges/IntRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(SS)Lkotlin/ranges/IntRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(BJ)Lkotlin/ranges/LongRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(IJ)Lkotlin/ranges/LongRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(JB)Lkotlin/ranges/LongRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(JI)Lkotlin/ranges/LongRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(JJ)Lkotlin/ranges/LongRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(JS)Lkotlin/ranges/LongRange;
kotlin.ranges.RangesKt___RangesKt.rangeUntil:(SJ)Lkotlin/ranges/LongRange;
kotlin.ranges.RangesKt___RangesKt.shortRangeContains:(Lkotlin/ranges/OpenEndRange;B)Z
kotlin.ranges.RangesKt___RangesKt.shortRangeContains:(Lkotlin/ranges/OpenEndRange;I)Z
kotlin.ranges.RangesKt___RangesKt.shortRangeContains:(Lkotlin/ranges/OpenEndRange;J)Z
kotlin.ranges.CharRange.getEndExclusive$annotations:()V
kotlin.ranges.CharRange.getEndExclusive:()Ljava/lang/Character;
kotlin.ranges.CharRange.getEndExclusive:()Ljava/lang/Comparable;
kotlin.ranges.IntRange.getEndExclusive$annotations:()V
kotlin.ranges.IntRange.getEndExclusive:()Ljava/lang/Comparable;
kotlin.ranges.IntRange.getEndExclusive:()Ljava/lang/Integer;
kotlin.ranges.LongRange.getEndExclusive$annotations:()V
kotlin.ranges.LongRange.getEndExclusive:()Ljava/lang/Comparable;
kotlin.ranges.LongRange.getEndExclusive:()Ljava/lang/Long;
kotlin.ranges.UIntRange.getEndExclusive-pVg5ArA$annotations:()V
kotlin.ranges.UIntRange.getEndExclusive:()Ljava/lang/Comparable;
kotlin.ranges.UIntRange.getEndExclusive-pVg5ArA:()I
kotlin.ranges.ULongRange.getEndExclusive-s-VKNKU$annotations:()V
kotlin.ranges.ULongRange.getEndExclusive:()Ljava/lang/Comparable;
kotlin.ranges.ULongRange.getEndExclusive-s-VKNKU:()J
kotlin.ranges.RangesKt__RangesKt.contains:(Ljava/lang/Iterable;Ljava/lang/Object;)Z
kotlin.streams.jdk8.StreamsKt.$r8$lambda$bdU4-xB_0bnfvMo-xyX7v8aTfMQ:(Lkotlin/sequences/Sequence;)Lj$/util/Spliterator;
kotlin.streams.jdk8.StreamsKt.asStream$lambda-4:(Lkotlin/sequences/Sequence;)Lj$/util/Spliterator;
The procyon
output shows various changes like this one:
private static final Object[] copyToArrayImpl(final Collection collection, final Object[] ar
Intrinsics.checkNotNullParameter((Object)collection, "collection");
Intrinsics.checkNotNullParameter((Object)array, "array");
- return CollectionToArray.toArray(collection, array);
+ final Object[] array2 = CollectionToArray.toArray(collection, array);
+ Intrinsics.checkNotNull((Object)array2, "null cannot be cast to non-null type kotlin.Array<T of kotlin.collections.CollectionsKt__CollectionsJVMKt.copyToArrayImpl>");
+ return array2;
}
These differences seem to be an expected result of the changes.
According to this stack overflow answer:
These files contain data for declarations of standard ("built-in") Kotlin classes which are not compiled to .class files, but rather are mapped to the existing types on the platform (in this case, JVM). For example, kotlin/kotlin.kotlin_builtins contains the information for non-physical classes in package kotlin: Int, String, Enum, Annotation, Collection, etc.
Repeating remarks from this issue:
I'm quite sure that disabling ART will give us a performance penalty, so we shouldn't disable it.
It doesn't disable the Android Runtime (ART), just baseline profiles.
According to the docs:
Baseline Profiles improve code execution speed by around 30% from the first launch by avoiding interpretation and just-in-time (JIT) compilation steps for included code paths.
So it may very well indeed result in a performance penalty, but I have found no real-world
data on whether 30% is accurate or not. And all the docs say that developers need to
define these profiles, but I don't see e.g. a baseline-prof.txt
in your repo, so I
have no idea what the baseline.prof{,m}
is currently based on and whether it's actually
doing anything useful. Do you have any info on that?
I've never seen differences in
baseline.prof
that were not the result of differences in one of the.dex
files.And if the
.dex
files are different, removing the.prof
still doesn't make the build reproducible.@penn5 If your
.dex
files are identical, I'd love to see the.prof
files (or a text dump of their contents).