summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Wharton <jakew@google.com>2020-04-24 15:23:51 -0400
committerJake Wharton <jakew@google.com>2020-04-24 15:43:45 -0400
commit17ce9e7df870bd7df43964be0acd0b2f7c4b01b5 (patch)
treecdb898e57428c2d325798b6922b2b61376b4f2e6
parent86e54b07373040f16b365a631a5b7ea3cf4db65c (diff)
downloaddata-binding-17ce9e7df870bd7df43964be0acd0b2f7c4b01b5.tar.gz
Reduce bytecode impact of mixed requirement views
When mixing optional and required views we used to skip storing into the 'id' local for optional views. id = R.id.one; View one = root.findViewById(id); if (one == null) break missingId; View two = root.findViewById(R.id.two); This uses separate registers for R.id.one and R.id.two requiring one more register in total for the method. .registers 4 const v0, 0x102001a .line 19 invoke-virtual {p0, v0}, Landroid/view/View;->findViewById(I)Landroid/view/View; move-result-object v1 if-nez v1, :cond_a goto :goto_1f :cond_a const v2, 0x102003c .line 22 invoke-virtual {p0, v2}, Landroid/view/View;->findViewById(I)Landroid/view/View; When the 'id' local is present, unconditionally storing the next ID into that local allows the register to be reused. id = R.id.one; View one = root.findViewById(id); if (one == null) break missingId; id = R.id.two; View two = root.findViewById(id); Produces: .registers 3 const v0, 0x102001a .line 19 invoke-virtual {p0, v0}, Landroid/view/View;->findViewById(I)Landroid/view/View; move-result-object v1 if-nez v1, :cond_a goto :goto_1f :cond_a const v0, 0x102003c .line 22 invoke-virtual {p0, v0}, Landroid/view/View;->findViewById(I)Landroid/view/View; Bug: 128314294 Test: ../base/bazel/bazel test //tools/base/build-system/integration-test/databinding:tests //tools/data-binding/... Change-Id: I6408d214ba549c443d3743151636eef391083d26
-rw-r--r--compilerCommon/src/main/kotlin/android/databinding/tool/writer/ViewBinderGenerateJava.kt8
1 files changed, 6 insertions, 2 deletions
diff --git a/compilerCommon/src/main/kotlin/android/databinding/tool/writer/ViewBinderGenerateJava.kt b/compilerCommon/src/main/kotlin/android/databinding/tool/writer/ViewBinderGenerateJava.kt
index ca545132..a6492e54 100644
--- a/compilerCommon/src/main/kotlin/android/databinding/tool/writer/ViewBinderGenerateJava.kt
+++ b/compilerCommon/src/main/kotlin/android/databinding/tool/writer/ViewBinderGenerateJava.kt
@@ -246,7 +246,8 @@ private class JavaFileGenerator(
/** Non-null when error-handling is being generated. */
val id: String?
- if (nonRootBindings.any { it.isRequired }) {
+ val hasRequiredBindings = nonRootBindings.any { it.isRequired }
+ if (hasRequiredBindings) {
addComment("The body of this method is generated in a way you would not otherwise write.")
addComment("This is done to optimize the compiled bytecode for size and performance.")
@@ -274,8 +275,11 @@ private class JavaFileGenerator(
val viewInitializer = if (binding === rootBinding) {
// If this corresponds to the root binding, we can re-use the input View argument.
rootParam.asViewReference(viewType)
- } else if (binding.isRequired) {
+ } else if (hasRequiredBindings) {
// Place the id value first into the local in case it's needed for error handling.
+ // We do this unconditionally (even for optional bindings) so that the Dalvik
+ // bytecode re-uses the same register rather than using one for optional IDs and
+ // one for required IDs.
addStatement("$id = $L", binding.id.asCode())
CodeBlock.of("$N.findViewById($id)", rootParam)
} else {