Rewrite Class.forName() in presence of catch handlers
Bug: 182543182
Change-Id: I3cca8e66cc0dbdca8cd5dc94ac6fbe9c2b2cb9bf
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index 802fdb3..683cf92 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InitClass;
import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -42,12 +43,9 @@
}
Set<Value> affectedValues = Sets.newIdentityHashSet();
ProgramMethod context = code.context();
- for (BasicBlock block : code.blocks) {
- // Conservatively bail out if the containing block has catch handlers.
- // TODO(b/118509730): unless join of all catch types is ClassNotFoundException ?
- if (block.hasCatchHandlers()) {
- continue;
- }
+ BasicBlockIterator blockIterator = code.listIterator();
+ while (blockIterator.hasNext()) {
+ BasicBlock block = blockIterator.next();
InstructionListIterator it = block.listIterator(code);
while (it.hasNext()) {
InvokeMethod invoke = it.nextUntil(x -> x.isInvokeStatic() || x.isInvokeVirtual());
@@ -61,14 +59,14 @@
context,
invoke.asInvokeStatic(),
rewriteSingleGetClassOrForNameToConstClass(
- appView, code, it, invoke, affectedValues));
+ appView, code, blockIterator, it, invoke, affectedValues));
} else {
applyTypeForGetClassTo(
appView,
context,
invoke.asInvokeVirtual(),
rewriteSingleGetClassOrForNameToConstClass(
- appView, code, it, invoke, affectedValues));
+ appView, code, blockIterator, it, invoke, affectedValues));
}
}
}
@@ -82,10 +80,12 @@
private static BiConsumer<DexType, DexClass> rewriteSingleGetClassOrForNameToConstClass(
AppView<AppInfoWithLiveness> appView,
IRCode code,
+ BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
Set<Value> affectedValues) {
return (type, baseClass) -> {
+ InitClass initClass = null;
if (invoke.getInvokedMethod().match(appView.dexItemFactory().classMethods.forName)) {
// Bail-out if the optimization could increase the size of the main dex.
if (baseClass.isProgramClass()
@@ -106,25 +106,42 @@
return;
}
- instructionIterator.addBefore(
+ initClass =
InitClass.builder()
.setFreshOutValue(code, TypeElement.getInt())
.setType(type)
.setPosition(invoke)
- .build());
+ .build();
}
}
// If there are no users of the const-class then simply remove the instruction.
if (!invoke.hasOutValue() || !invoke.outValue().hasAnyUsers()) {
- instructionIterator.removeOrReplaceByDebugLocalRead();
+ if (initClass != null) {
+ instructionIterator.replaceCurrentInstruction(initClass);
+ } else {
+ instructionIterator.removeOrReplaceByDebugLocalRead();
+ }
return;
}
// Otherwise insert a const-class instruction.
+ BasicBlock block = invoke.getBlock();
affectedValues.addAll(invoke.outValue().affectedValues());
instructionIterator.replaceCurrentInstructionWithConstClass(
appView, code, type, invoke.getLocalInfo());
+
+ if (initClass != null) {
+ if (block.hasCatchHandlers()) {
+ instructionIterator
+ .splitCopyCatchHandlers(code, blockIterator, appView.options())
+ .listIterator(code)
+ .add(initClass);
+ } else {
+ instructionIterator.add(initClass);
+ }
+ }
+
if (appView.options().isGeneratingClassFiles()) {
code.method()
.upgradeClassFileVersion(