diff options
author | Jake Wharton <jakew@google.com> | 2020-04-24 15:23:51 -0400 |
---|---|---|
committer | Jake Wharton <jakew@google.com> | 2020-04-24 15:43:45 -0400 |
commit | 17ce9e7df870bd7df43964be0acd0b2f7c4b01b5 (patch) | |
tree | cdb898e57428c2d325798b6922b2b61376b4f2e6 | |
parent | 86e54b07373040f16b365a631a5b7ea3cf4db65c (diff) | |
download | data-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.kt | 8 |
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 { |