Don't compile methods with irreducible loops and String.<init>.
The current code doesn't work when dex register aliases.
bug: 78493232
Test: m
Change-Id: I1c296f6dc914388844ae5eb7d84f3bd7d81e1f87
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 9647dd5..a36e803 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1360,9 +1360,15 @@
if (arg_this->IsNewInstance()) {
ssa_builder_->AddUninitializedString(arg_this->AsNewInstance());
} else {
+ // The only reason a HPhi can flow in a String.<init> is when there is an
+ // irreducible loop, which will create HPhi for all dex registers at loop entry.
DCHECK(arg_this->IsPhi());
- // NewInstance is not the direct input of the StringFactory call. It might
- // be redundant but optimizing this case is not worth the effort.
+ DCHECK(graph_->HasIrreducibleLoops());
+ // Don't bother compiling a method in that situation. While we could look at all
+ // phis related to the HNewInstance, it's not worth the trouble.
+ MaybeRecordStat(compilation_stats_,
+ MethodCompilationStat::kNotCompiledIrreducibleAndStringInit);
+ return false;
}
// Walk over all vregs and replace any occurrence of `arg_this` with `invoke`.
diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h
index 9a26f2f..f246228 100644
--- a/compiler/optimizing/optimizing_compiler_stats.h
+++ b/compiler/optimizing/optimizing_compiler_stats.h
@@ -50,6 +50,7 @@
kNotCompiledThrowCatchLoop,
kNotCompiledAmbiguousArrayOp,
kNotCompiledHugeMethod,
+ kNotCompiledIrreducibleAndStringInit,
kNotCompiledLargeMethodNoBranches,
kNotCompiledMalformedOpcode,
kNotCompiledNoCodegen,
diff --git a/test/563-checker-fakestring/smali/TestCase.smali b/test/563-checker-fakestring/smali/TestCase.smali
index adafb78..8898c48 100644
--- a/test/563-checker-fakestring/smali/TestCase.smali
+++ b/test/563-checker-fakestring/smali/TestCase.smali
@@ -133,17 +133,8 @@
.end method
-# Test that the compiler does not assume that the first argument of String.<init>
-# is a NewInstance by inserting an irreducible loop between them (b/26676472).
-
-# We verify the type of the input instruction (Phi) in debuggable mode, because
-# it is eliminated by later stages of SsaBuilder otherwise.
-
-## CHECK-START-DEBUGGABLE: java.lang.String TestCase.thisNotNewInstance1(byte[], boolean) register (after)
-## CHECK-DAG: InvokeStaticOrDirect env:[[<<Phi:l\d+>>,{{.*]]}}
-## CHECK-DAG: <<Phi>> Phi
-
-.method public static thisNotNewInstance1([BZ)Ljava/lang/String;
+# Test #1 for irreducible loops and String.<init>.
+.method public static irreducibleLoopAndStringInit1([BZ)Ljava/lang/String;
.registers 5
new-instance v0, Ljava/lang/String;
@@ -164,11 +155,8 @@
.end method
-## CHECK-START-DEBUGGABLE: java.lang.String TestCase.thisNotNewInstance2(byte[], boolean) register (after)
-## CHECK-DAG: InvokeStaticOrDirect env:[[<<Phi:l\d+>>,{{.*]]}}
-## CHECK-DAG: <<Phi>> Phi
-
-.method public static thisNotNewInstance2([BZ)Ljava/lang/String;
+# Test #2 for irreducible loops and String.<init>.
+.method public static irreducibleLoopAndStringInit2([BZ)Ljava/lang/String;
.registers 5
new-instance v0, Ljava/lang/String;
@@ -188,3 +176,26 @@
return-object v0
.end method
+
+# Test #3 for irreducible loops and String.<init> alias.
+.method public static irreducibleLoopAndStringInit3([BZ)Ljava/lang/String;
+ .registers 5
+
+ new-instance v0, Ljava/lang/String;
+ move-object v2, v0
+
+ # Irreducible loop
+ if-eqz p1, :loop_entry
+ :loop_header
+ const v1, 0x1
+ xor-int p1, p1, v1
+ :loop_entry
+ if-eqz p1, :string_init
+ goto :loop_header
+
+ :string_init
+ const-string v1, "UTF8"
+ invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
+ return-object v2
+
+.end method
diff --git a/test/563-checker-fakestring/src/Main.java b/test/563-checker-fakestring/src/Main.java
index 78cb37a..d38b7f4 100644
--- a/test/563-checker-fakestring/src/Main.java
+++ b/test/563-checker-fakestring/src/Main.java
@@ -65,14 +65,21 @@
}
{
- Method m = c.getMethod("thisNotNewInstance1", byte[].class, boolean.class);
+ Method m = c.getMethod("irreducibleLoopAndStringInit1", byte[].class, boolean.class);
String result = (String) m.invoke(null, new Object[] { testData, true });
assertEqual(testString, result);
result = (String) m.invoke(null, new Object[] { testData, false });
assertEqual(testString, result);
}
{
- Method m = c.getMethod("thisNotNewInstance2", byte[].class, boolean.class);
+ Method m = c.getMethod("irreducibleLoopAndStringInit2", byte[].class, boolean.class);
+ String result = (String) m.invoke(null, new Object[] { testData, true });
+ assertEqual(testString, result);
+ result = (String) m.invoke(null, new Object[] { testData, false });
+ assertEqual(testString, result);
+ }
+ {
+ Method m = c.getMethod("irreducibleLoopAndStringInit3", byte[].class, boolean.class);
String result = (String) m.invoke(null, new Object[] { testData, true });
assertEqual(testString, result);
result = (String) m.invoke(null, new Object[] { testData, false });