summaryrefslogtreecommitdiff
path: root/compiler/optimizing/instruction_simplifier.cc
diff options
context:
space:
mode:
author Santiago Aboy Solanes <solanes@google.com> 2021-10-01 09:26:56 +0100
committer Treehugger Robot <treehugger-gerrit@google.com> 2021-10-26 13:51:31 +0000
commitd690f8ae8f8e2675bc52089a83ac18c749f8e6d2 (patch)
treedac10b65d901cad87d6dbb7b48453f6da214a76f /compiler/optimizing/instruction_simplifier.cc
parente91a954ee350cbc0b311f342c90697191e1ae495 (diff)
Inline across dex files for bootclaspath's methods
We can relax a bit the restriction for not inlining across dexfiles when we are AoT compiling and we need an environment. There's an added new restriction related to BSS entries. We could potentially inline across dex files for those cases too but are left to be solved in follow-up CLs. Bug: 154012332 Test: ART tests Change-Id: I5122b26c79b3e30d2643c0ccc05d595a0047953e
Diffstat (limited to 'compiler/optimizing/instruction_simplifier.cc')
-rw-r--r--compiler/optimizing/instruction_simplifier.cc45
1 files changed, 38 insertions, 7 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 91b2e8bdc6..3f1f3b0f8d 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -2645,12 +2645,15 @@ static bool TryReplaceStringBuilderAppend(HInvoke* invoke) {
// Collect args and check for unexpected uses.
// We expect one call to a constructor with no arguments, one constructor fence (unless
// eliminated), some number of append calls and one call to StringBuilder.toString().
+ bool constructor_inlined = false;
bool seen_constructor = false;
bool seen_constructor_fence = false;
bool seen_to_string = false;
uint32_t format = 0u;
uint32_t num_args = 0u;
HInstruction* args[StringBuilderAppend::kMaxArgs]; // Added in reverse order.
+ // When inlining, `maybe_new_array` tracks an environment use that we want to allow.
+ HInstruction* maybe_new_array = nullptr;
for (HBackwardInstructionIterator iter(block->GetInstructions()); !iter.Done(); iter.Advance()) {
HInstruction* user = iter.Current();
// Instructions of interest apply to `sb`, skip those that do not involve `sb`.
@@ -2731,13 +2734,25 @@ static bool TryReplaceStringBuilderAppend(HInvoke* invoke) {
format = (format << StringBuilderAppend::kBitsPerArg) | static_cast<uint32_t>(arg);
args[num_args] = as_invoke_virtual->InputAt(1u);
++num_args;
- } else if (user->IsInvokeStaticOrDirect() &&
- user->AsInvokeStaticOrDirect()->GetResolvedMethod() != nullptr &&
- user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() &&
- user->AsInvokeStaticOrDirect()->GetNumberOfArguments() == 1u) {
- // After arguments, we should see the constructor.
- // We accept only the constructor with no extra arguments.
- DCHECK(!seen_constructor);
+ } else if (!seen_constructor) {
+ // At this point, we should see the constructor. However, we might have inlined it so we have
+ // to take care of both cases. We accept only the constructor with no extra arguments. This
+ // means that if we inline it, we have to check it is setting its field to a new array.
+ if (user->IsInvokeStaticOrDirect() &&
+ user->AsInvokeStaticOrDirect()->GetResolvedMethod() != nullptr &&
+ user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() &&
+ user->AsInvokeStaticOrDirect()->GetNumberOfArguments() == 1u) {
+ constructor_inlined = false;
+ } else if (user->IsInstanceFieldSet() &&
+ user->AsInstanceFieldSet()->GetFieldType() == DataType::Type::kReference &&
+ user->AsInstanceFieldSet()->InputAt(0) == sb &&
+ user->AsInstanceFieldSet()->GetValue()->IsNewArray()) {
+ maybe_new_array = user->AsInstanceFieldSet()->GetValue();
+ constructor_inlined = true;
+ } else {
+ // We were expecting a constructor but we haven't seen it. Abort optimization.
+ return false;
+ }
DCHECK(!seen_constructor_fence);
seen_constructor = true;
} else if (user->IsConstructorFence()) {
@@ -2763,6 +2778,10 @@ static bool TryReplaceStringBuilderAppend(HInvoke* invoke) {
// Accept only calls on the StringBuilder (which shall all be removed).
// TODO: Carve-out for const-string? Or rely on environment pruning (to be implemented)?
if (holder->InputCount() == 0 || holder->InputAt(0) != sb) {
+ // When inlining the constructor, we have a NewArray as an environment use.
+ if (constructor_inlined && holder == maybe_new_array) {
+ continue;
+ }
return false;
}
}
@@ -2796,6 +2815,18 @@ static bool TryReplaceStringBuilderAppend(HInvoke* invoke) {
while (sb->HasNonEnvironmentUses()) {
block->RemoveInstruction(sb->GetUses().front().GetUser());
}
+ if (constructor_inlined) {
+ // We need to remove the inlined constructor instructions. That also removes all remaining
+ // environment uses.
+ DCHECK(sb->HasEnvironmentUses());
+ DCHECK(maybe_new_array != nullptr);
+ DCHECK(maybe_new_array->IsNewArray());
+ DCHECK(maybe_new_array->HasNonEnvironmentUses());
+ HInstruction* fence = maybe_new_array->GetUses().front().GetUser();
+ DCHECK(fence->IsConstructorFence());
+ block->RemoveInstruction(fence);
+ block->RemoveInstruction(maybe_new_array);
+ }
DCHECK(!sb->HasEnvironmentUses());
block->RemoveInstruction(sb);
return true;