Extend MethodConversionOptions with desired backend
This makes it possible to specify whether a piece of IR should be converted to cf or dex independent of the backend of the overall compilation.
Bug: 205810841
Change-Id: I9515706409a9e0639a945321d8f5fad0d05d157f
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 4358a27..3033fb7 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -35,6 +35,8 @@
import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.ClassNameMapper;
@@ -503,10 +505,14 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
verifyFramesOrRemove(method, appView, getCodeLens(appView));
return internalBuildPossiblyWithLocals(
- method, method, appView, appView.codeLens(), null, null, origin, null);
+ method, method, appView, appView.codeLens(), null, null, origin, null, conversionOptions);
}
@Override
@@ -531,7 +537,8 @@
valueNumberGenerator,
callerPosition,
origin,
- protoChanges);
+ protoChanges,
+ new ThrowingMethodConversionOptions(appView.options()));
}
private void verifyFramesOrRemove(ProgramMethod method, AppView<?> appView, GraphLens codeLens) {
@@ -552,7 +559,8 @@
NumberGenerator valueNumberGenerator,
Position callerPosition,
Origin origin,
- RewrittenPrototypeDescription protoChanges) {
+ RewrittenPrototypeDescription protoChanges,
+ MutableMethodConversionOptions conversionOptions) {
if (!method.getDefinition().keepLocals(appView.options())) {
return internalBuild(
Collections.emptyList(),
@@ -563,7 +571,8 @@
valueNumberGenerator,
callerPosition,
origin,
- protoChanges);
+ protoChanges,
+ conversionOptions);
} else {
return internalBuildWithLocals(
context,
@@ -573,7 +582,8 @@
valueNumberGenerator,
callerPosition,
origin,
- protoChanges);
+ protoChanges,
+ conversionOptions);
}
}
@@ -586,7 +596,8 @@
NumberGenerator valueNumberGenerator,
Position callerPosition,
Origin origin,
- RewrittenPrototypeDescription protoChanges) {
+ RewrittenPrototypeDescription protoChanges,
+ MutableMethodConversionOptions conversionOptions) {
try {
return internalBuild(
Collections.unmodifiableList(localVariables),
@@ -597,7 +608,8 @@
valueNumberGenerator,
callerPosition,
origin,
- protoChanges);
+ protoChanges,
+ conversionOptions);
} catch (InvalidDebugInfoException e) {
appView.options().warningInvalidDebugInfo(method, origin, e);
return internalBuild(
@@ -609,7 +621,8 @@
valueNumberGenerator,
callerPosition,
origin,
- protoChanges);
+ protoChanges,
+ conversionOptions);
}
}
@@ -623,7 +636,8 @@
NumberGenerator valueNumberGenerator,
Position callerPosition,
Origin origin,
- RewrittenPrototypeDescription protoChanges) {
+ RewrittenPrototypeDescription protoChanges,
+ MutableMethodConversionOptions conversionOptions) {
CfSourceCode source =
new CfSourceCode(
this,
@@ -642,7 +656,7 @@
IRBuilder.createForInlining(
method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges);
}
- return builder.build(context);
+ return builder.build(context, conversionOptions);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index 0f4233d..8152305 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -12,13 +12,22 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
public abstract class Code extends CachedHashValueDexItem {
- public abstract IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin);
+ public final IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ return buildIR(method, appView, origin, new MutableMethodConversionOptions(appView.options()));
+ }
+
+ public abstract IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions);
public IRCode buildInliningIR(
ProgramMethod context,
diff --git a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
index a544337..56a5988 100644
--- a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
@@ -24,6 +24,8 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SyntheticStraightLineSourceCode;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.NamingLens;
@@ -134,12 +136,16 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
DexMethod originalMethod =
appView.graphLens().getOriginalMethodSignature(method.getReference());
DefaultInstanceInitializerSourceCode source =
new DefaultInstanceInitializerSourceCode(originalMethod);
- return IRBuilder.create(method, appView, source, origin).build(method);
+ return IRBuilder.create(method, appView, source, origin).build(method, conversionOptions);
}
@Override
@@ -158,7 +164,7 @@
new DefaultInstanceInitializerSourceCode(originalMethod, callerPosition);
return IRBuilder.createForInlining(
method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges)
- .build(context);
+ .build(context, new ThrowingMethodConversionOptions(appView.options()));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index 3c3ce77..6eb2f08 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -26,6 +26,8 @@
import com.android.tools.r8.ir.conversion.DexSourceCode;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.ArrayUtils;
@@ -366,7 +368,11 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
DexSourceCode source =
new DexSourceCode(
this,
@@ -374,7 +380,7 @@
appView.graphLens().getOriginalMethodSignature(method.getReference()),
null,
appView.dexItemFactory());
- return IRBuilder.create(method, appView, source, origin).build(method);
+ return IRBuilder.create(method, appView, source, origin).build(method, conversionOptions);
}
@Override
@@ -396,7 +402,7 @@
appView.dexItemFactory());
return IRBuilder.createForInlining(
method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges)
- .build(context);
+ .build(context, new ThrowingMethodConversionOptions(appView.options()));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index c33d18d..3871952 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -43,12 +43,9 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexAnnotation.AnnotatedKind;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
-import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
-import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
import com.android.tools.r8.ir.optimize.NestUtils;
@@ -57,7 +54,6 @@
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
import com.android.tools.r8.ir.optimize.info.MutableMethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
-import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
import com.android.tools.r8.kotlin.KotlinMethodLevelInfo;
import com.android.tools.r8.naming.ClassNameMapper;
@@ -736,16 +732,6 @@
code = newCode;
}
- public void setCode(
- IRCode ir,
- BytecodeMetadataProvider bytecodeMetadataProvider,
- RegisterAllocator registerAllocator,
- AppView<?> appView) {
- checkIfObsolete();
- DexBuilder builder = new DexBuilder(ir, bytecodeMetadataProvider, registerAllocator);
- setCode(builder.build(), appView);
- }
-
public void unsetCode() {
checkIfObsolete();
code = null;
diff --git a/src/main/java/com/android/tools/r8/graph/InvalidCode.java b/src/main/java/com/android/tools/r8/graph/InvalidCode.java
index 5363897..2b9de26 100644
--- a/src/main/java/com/android/tools/r8/graph/InvalidCode.java
+++ b/src/main/java/com/android/tools/r8/graph/InvalidCode.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
@@ -23,7 +24,11 @@
private InvalidCode() {}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index b2efb1b..0922945 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -60,6 +60,7 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SourcePosition;
import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.MethodPosition;
@@ -240,8 +241,12 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
- return asCfCode().buildIR(method, appView, origin);
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
+ return asCfCode().buildIR(method, appView, origin, conversionOptions);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index 3cb1a4c..f60161d 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.kotlin.KotlinMethodLevelInfo;
@@ -27,8 +28,14 @@
}
public IRCode buildIR(AppView<?> appView) {
+ return buildIR(appView, new MutableMethodConversionOptions(appView.options()));
+ }
+
+ public IRCode buildIR(AppView<?> appView, MutableMethodConversionOptions conversionOptions) {
DexEncodedMethod method = getDefinition();
- return method.hasCode() ? method.getCode().buildIR(this, appView, getOrigin()) : null;
+ return method.hasCode()
+ ? method.getCode().buildIR(this, appView, getOrigin(), conversionOptions)
+ : null;
}
public IRCode buildInliningIR(
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
index 3420b1b..55e6f8c 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.structural.HashingVisitor;
@@ -48,7 +49,11 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
throw new Unreachable("Should not be called");
}
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
index 03b811f..5b02c12 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
@@ -19,6 +19,8 @@
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SyntheticStraightLineSourceCode;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.NamingLens;
@@ -52,9 +54,13 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
ThrowNullSourceCode source = new ThrowNullSourceCode(method);
- return IRBuilder.create(method, appView, source, origin).build(method);
+ return IRBuilder.create(method, appView, source, origin).build(method, conversionOptions);
}
@Override
@@ -70,7 +76,7 @@
ThrowNullSourceCode source = new ThrowNullSourceCode(method, callerPosition);
return IRBuilder.createForInlining(
method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges)
- .build(context);
+ .build(context, new ThrowingMethodConversionOptions(appView.options()));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
index d961949..c9c8e34 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
@@ -37,7 +38,11 @@
// Implement Code.
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
index fcae6d5..9787686 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
@@ -34,6 +34,7 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.code.Return;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.CfVersionUtils;
@@ -193,7 +194,11 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
assert !classInitializers.isEmpty();
Position callerPosition =
@@ -227,7 +232,8 @@
valueNumberGenerator,
blockNumberGenerator,
metadata,
- origin);
+ origin,
+ conversionOptions);
ListIterator<BasicBlock> blockIterator = code.listIterator();
InstructionListIterator instructionIterator = blockIterator.next().listIterator(code);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/LiveProtoFieldObject.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/LiveProtoFieldObject.java
index 4727869..4d10e4f 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/LiveProtoFieldObject.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/LiveProtoFieldObject.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
-import com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.DexItemBasedConstString;
import com.android.tools.r8.ir.code.IRCode;
@@ -32,7 +31,6 @@
public Instruction buildIR(AppView<?> appView, IRCode code) {
Value value =
code.createValue(TypeElement.stringClassType(appView, Nullability.definitelyNotNull()));
- ThrowingInfo throwingInfo = ThrowingInfo.defaultForConstString(appView.options());
if (appView.options().isMinifying()) {
return new DexItemBasedConstString(value, field, FieldNameComputationInfo.forFieldName());
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
index d51e318..82a2ef7 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.TypeConstraintResolver;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
@@ -113,7 +114,8 @@
}
@Override
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
// We cannot share ArrayGet instructions without knowledge of the type of the array input.
// If multiple primitive array types flow to the same ArrayGet instruction the art verifier
// gets confused.
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
index 3835b3d..a0bf286 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
@@ -84,8 +85,9 @@
}
@Override
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
- if (super.identicalAfterRegisterAllocation(other, allocator)) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
+ if (super.identicalAfterRegisterAllocation(other, allocator, conversionOptions)) {
// The array length instruction doesn't carry the element type. The art verifier doesn't
// allow an array length instruction into which arrays of two different base types can
// flow. Therefore, as a safe approximation we only consider array length instructions
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
index 9994dde..aa70b4f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.TypeConstraintResolver;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
@@ -173,7 +174,8 @@
}
@Override
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
// We cannot share ArrayPut instructions without knowledge of the type of the array input.
// If multiple primitive array types flow to the same ArrayPut instruction the art verifier
// gets confused.
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index e5f15bd..b664c13 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -120,14 +120,6 @@
public enum ThrowingInfo {
NO_THROW,
CAN_THROW;
-
- public static ThrowingInfo defaultForConstString(InternalOptions options) {
- return options.isGeneratingClassFiles() ? NO_THROW : CAN_THROW;
- }
-
- public static ThrowingInfo defaultForInstruction(Instruction instruction) {
- return instruction.instructionTypeCanThrow() ? CAN_THROW : NO_THROW;
- }
}
public enum EdgeType {
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 6a237d0..5175138 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -21,6 +21,8 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.Phi.RegisterReadType;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.CfgPrinter;
@@ -110,6 +112,7 @@
public static final int INSTRUCTION_NUMBER_DELTA = 2;
private final ProgramMethod method;
+ private final MutableMethodConversionOptions conversionOptions;
public LinkedList<BasicBlock> blocks;
public final NumberGenerator valueNumberGenerator;
@@ -135,11 +138,13 @@
NumberGenerator valueNumberGenerator,
NumberGenerator basicBlockNumberGenerator,
IRMetadata metadata,
- Origin origin) {
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
assert metadata != null;
assert options != null;
assert blocks.size() == basicBlockNumberGenerator.peek();
this.options = options;
+ this.conversionOptions = conversionOptions;
this.method = method;
this.blocks = blocks;
this.valueNumberGenerator = valueNumberGenerator;
@@ -167,6 +172,14 @@
return blocks.getFirst();
}
+ public MethodConversionOptions getConversionOptions() {
+ return conversionOptions;
+ }
+
+ public void mutateConversionOptions(Consumer<MutableMethodConversionOptions> mutator) {
+ mutator.accept(conversionOptions);
+ }
+
/**
* Compute the set of live values at the entry to each block using a backwards data-flow analysis.
*/
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
index e0ca6cd..68d7ffc 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
@@ -153,8 +154,9 @@
}
@Override
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
- if (!super.identicalAfterRegisterAllocation(other, allocator)) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
+ if (!super.identicalAfterRegisterAllocation(other, allocator, conversionOptions)) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index ec25297..564eaf1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -26,12 +26,14 @@
import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.optimize.DeadCodeRemover.DeadInstructionResult;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.CfgPrinter;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
import com.google.common.collect.ImmutableSet;
@@ -501,7 +503,8 @@
return a.outType() == b.outType();
}
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
if (other.getClass() != getClass()) {
return false;
}
@@ -541,8 +544,10 @@
}
}
// Finally check that the dex instructions for the generated code actually are the same.
- if (allocator.options().isGeneratingDex()
- && !DexBuilder.identicalInstructionsAfterBuildingDexCode(this, other, allocator)) {
+ InternalOptions options = allocator.options();
+ if (conversionOptions.isGeneratingDex()
+ && !DexBuilder.identicalInstructionsAfterBuildingDexCode(
+ this, other, allocator, conversionOptions)) {
return false;
}
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index 06173d4..2fc4aff 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.UnknownValue;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.optimize.DefaultInliningOracle;
import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
@@ -187,8 +188,9 @@
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter);
@Override
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
- if (!super.identicalAfterRegisterAllocation(other, allocator)) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
+ if (!super.identicalAfterRegisterAllocation(other, allocator, conversionOptions)) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveException.java b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
index dd74687..e5f3722 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MoveException.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
@@ -85,7 +85,7 @@
InternalOptions options = appView.options();
if (options.debug
|| code.context().getDefinition().getOptimizationInfo().isReachabilitySensitive()
- || options.isGeneratingClassFiles()) {
+ || code.getConversionOptions().isGeneratingClassFiles()) {
return DeadInstructionResult.notDead();
}
return DeadInstructionResult.deadIfOutValueIsDead();
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
index b32a651..b28f281 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
@@ -149,8 +150,9 @@
}
@Override
- public boolean identicalAfterRegisterAllocation(Instruction other, RegisterAllocator allocator) {
- if (!super.identicalAfterRegisterAllocation(other, allocator)) {
+ public boolean identicalAfterRegisterAllocation(
+ Instruction other, RegisterAllocator allocator, MethodConversionOptions conversionOptions) {
+ if (!super.identicalAfterRegisterAllocation(other, allocator, conversionOptions)) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index e95d612..fa3c642 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -144,7 +144,8 @@
this.bytecodeMetadataBuilder = BytecodeMetadata.builder(bytecodeMetadataProvider);
}
- public CfCode build(DeadCodeRemover deadCodeRemover, MethodConversionOptions conversionOptions) {
+ public CfCode build(DeadCodeRemover deadCodeRemover) {
+ code.traceBlocks();
computeInitializers();
TypeVerificationHelper typeVerificationHelper = new TypeVerificationHelper(appView, code);
typeVerificationHelper.computeVerificationTypes();
@@ -178,7 +179,7 @@
loadStoreHelper.insertPhiMoves(registerAllocator);
- if (conversionOptions.isPeepholeOptimizationsEnabled()) {
+ if (code.getConversionOptions().isPeepholeOptimizationsEnabled()) {
for (int i = 0; i < PEEPHOLE_OPTIMIZATION_PASSES; i++) {
CodeRewriter.collapseTrivialGotos(code);
PeepholeOptimizer.removeIdenticalPredecessorBlocks(code, registerAllocator);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
index c4ac3ff..2bd4cfa 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
@@ -93,6 +93,7 @@
private final RegisterAllocator registerAllocator;
private final InternalOptions options;
+ private final MethodConversionOptions conversionOptions;
// List of information about switch payloads that have to be created at the end of the
// dex code.
@@ -128,20 +129,23 @@
public DexBuilder(
IRCode ir,
BytecodeMetadataProvider bytecodeMetadataProvider,
- RegisterAllocator registerAllocator) {
- this(ir, bytecodeMetadataProvider, registerAllocator, registerAllocator.options());
- assert ir != null;
+ RegisterAllocator registerAllocator,
+ InternalOptions options) {
+ this(ir, bytecodeMetadataProvider, registerAllocator, options, ir.getConversionOptions());
}
- private DexBuilder(
+ public DexBuilder(
IRCode ir,
BytecodeMetadataProvider bytecodeMetadataProvider,
RegisterAllocator registerAllocator,
- InternalOptions options) {
+ InternalOptions options,
+ MethodConversionOptions conversionOptions) {
+ assert ir == null || conversionOptions == ir.getConversionOptions();
this.ir = ir;
this.bytecodeMetadataBuilder = BytecodeMetadata.builder(bytecodeMetadataProvider);
this.registerAllocator = registerAllocator;
this.options = options;
+ this.conversionOptions = conversionOptions;
if (isBuildingForComparison()) {
instructionToInfo = new Info[1];
}
@@ -150,9 +154,15 @@
public static boolean identicalInstructionsAfterBuildingDexCode(
com.android.tools.r8.ir.code.Instruction a,
com.android.tools.r8.ir.code.Instruction b,
- RegisterAllocator allocator) {
+ RegisterAllocator allocator,
+ MethodConversionOptions conversionOptions) {
DexBuilder builder =
- new DexBuilder(null, BytecodeMetadataProvider.empty(), allocator, allocator.options());
+ new DexBuilder(
+ null,
+ BytecodeMetadataProvider.empty(),
+ allocator,
+ allocator.options(),
+ conversionOptions);
Info infoA = buildInfoForComparison(a, builder);
Info infoB = buildInfoForComparison(b, builder);
return infoA.identicalInstructions(infoB, builder);
@@ -647,7 +657,8 @@
public void addReturn(Return ret, Instruction dex) {
if (nextBlock != null
- && ret.identicalAfterRegisterAllocation(nextBlock.entry(), registerAllocator)) {
+ && ret.identicalAfterRegisterAllocation(
+ nextBlock.entry(), registerAllocator, conversionOptions)) {
addNothing(ret);
} else {
add(ret, dex);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 4d1cfc2..301de1a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -118,6 +118,7 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.code.ValueTypeConstraint;
import com.android.tools.r8.ir.code.Xor;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -606,7 +607,7 @@
* @param context Under what context this IRCode is built. Either the current method or caller.
* @return The list of basic blocks. First block is the main entry.
*/
- public IRCode build(ProgramMethod context) {
+ public IRCode build(ProgramMethod context, MutableMethodConversionOptions conversionOptions) {
assert source != null;
source.setUp();
@@ -706,7 +707,8 @@
valueNumberGenerator,
basicBlockNumberGenerator,
metadata,
- origin);
+ origin,
+ conversionOptions);
// Verify critical edges are split so we have a place to insert phi moves if necessary.
assert ir.verifySplitCriticalEdges();
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 3da2a7e..b51a072 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -11,16 +11,13 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
@@ -33,18 +30,8 @@
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.InstanceFieldValueAnalysis;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValueAnalysis;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
-import com.android.tools.r8.ir.analysis.type.TypeElement;
-import com.android.tools.r8.ir.code.AlwaysMaterializingDefinition;
-import com.android.tools.r8.ir.code.AlwaysMaterializingUser;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.InvokeStatic;
-import com.android.tools.r8.ir.code.NumericType;
-import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.conversion.MethodConversionOptions.DefaultMethodConversionOptions;
-import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
@@ -75,7 +62,6 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.MemberValuePropagation;
import com.android.tools.r8.ir.optimize.NaturalIntLoopRemover;
-import com.android.tools.r8.ir.optimize.PeepholeOptimizer;
import com.android.tools.r8.ir.optimize.RedundantFieldLoadAndStoreElimination;
import com.android.tools.r8.ir.optimize.ReflectionOptimizer;
import com.android.tools.r8.ir.optimize.ServiceLoaderRewriter;
@@ -92,8 +78,6 @@
import com.android.tools.r8.ir.optimize.outliner.Outliner;
import com.android.tools.r8.ir.optimize.string.StringBuilderOptimizer;
import com.android.tools.r8.ir.optimize.string.StringOptimizer;
-import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
-import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.naming.IdentifierNameStringMarker;
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
@@ -123,13 +107,10 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Supplier;
import java.util.stream.Collectors;
public class IRConverter {
- private static final int PEEPHOLE_OPTIMIZATION_PASSES = 2;
-
public final AppView<?> appView;
private final Timing timing;
@@ -915,11 +896,10 @@
assert code.isConsistentSSA();
Timing timing = Timing.empty();
deadCodeRemover.run(code, timing);
- code.traceBlocks();
- RegisterAllocator registerAllocator =
- performRegisterAllocation(
- code, method, DefaultMethodConversionOptions.getInstance(), timing);
- method.setCode(code, BytecodeMetadataProvider.empty(), registerAllocator, appView);
+ method.setCode(
+ new IRToDexFinalizer(appView, codeRewriter, deadCodeRemover)
+ .finalizeCode(code, BytecodeMetadataProvider.empty(), timing),
+ appView);
if (Log.ENABLED) {
Log.debug(getClass(), "Resulting dex code for %s:\n%s",
method.toSourceString(), logCode(options, method));
@@ -1094,8 +1074,6 @@
ProgramMethod context = code.context();
DexEncodedMethod method = context.getDefinition();
DexProgramClass holder = context.getHolder();
- MutableMethodConversionOptions conversionOptions =
- new MutableMethodConversionOptions(methodProcessor);
assert holder != null;
Timing timing = Timing.create(context.toSourceString(), options);
@@ -1178,7 +1156,6 @@
ClassInitializerDefaultsResult.empty(),
feedback,
methodProcessor,
- conversionOptions,
BytecodeMetadataProvider.builder(),
timing);
timing.end();
@@ -1493,7 +1470,6 @@
classInitializerDefaultsResult,
feedback,
methodProcessor,
- conversionOptions,
bytecodeMetadataProviderBuilder,
timing);
timing.end();
@@ -1517,19 +1493,11 @@
previous =
printMethod(code, "IR after computation of optimization info summary (SSA)", previous);
- if (options.canHaveNumberConversionRegisterAllocationBug()) {
- timing.begin("Check number conversion issue");
- codeRewriter.workaroundNumberConversionRegisterAllocationBug(code);
- timing.end();
- }
-
printMethod(code, "Optimized IR (SSA)", previous);
timing.begin("Finalize IR");
finalizeIR(
- context,
code,
feedback,
- conversionOptions,
bytecodeMetadataProviderBuilder.build(),
timing);
timing.end();
@@ -1553,14 +1521,13 @@
ClassInitializerDefaultsResult classInitializerDefaultsResult,
OptimizationFeedback feedback,
MethodProcessor methodProcessor,
- MutableMethodConversionOptions conversionOptions,
BytecodeMetadataProvider.Builder bytecodeMetadataProviderBuilder,
Timing timing) {
appView.withArgumentPropagator(
argumentPropagator -> argumentPropagator.scan(method, code, methodProcessor, timing));
if (methodProcessor.isPrimaryMethodProcessor()) {
- enumUnboxer.analyzeEnums(code, conversionOptions);
+ enumUnboxer.analyzeEnums(code, methodProcessor);
}
if (inliner != null) {
@@ -1624,69 +1591,50 @@
}
deadCodeRemover.run(code, timing);
finalizeIR(
- code.context(),
code,
feedback,
- DefaultMethodConversionOptions.getInstance(),
BytecodeMetadataProvider.empty(),
timing);
}
public void finalizeIR(
- ProgramMethod method,
IRCode code,
OptimizationFeedback feedback,
- MethodConversionOptions conversionOptions,
BytecodeMetadataProvider bytecodeMetadataProvider,
Timing timing) {
- code.traceBlocks();
if (options.isGeneratingClassFiles()) {
- finalizeToCf(code, feedback, conversionOptions, bytecodeMetadataProvider);
+ finalizeToCf(code, feedback, bytecodeMetadataProvider, timing);
} else {
assert options.isGeneratingDex();
- finalizeToDex(code, feedback, conversionOptions, bytecodeMetadataProvider, timing);
+ finalizeToDex(code, feedback, bytecodeMetadataProvider, timing);
}
}
private void finalizeToCf(
IRCode code,
OptimizationFeedback feedback,
- MethodConversionOptions conversionOptions,
- BytecodeMetadataProvider bytecodeMetadataProvider) {
- ProgramMethod method = code.context();
- assert !method.getDefinition().getCode().isDexCode();
- CfBuilder builder = new CfBuilder(appView, method, code, bytecodeMetadataProvider);
- CfCode result = builder.build(deadCodeRemover, conversionOptions);
- method.getDefinition().setCode(result, appView);
+ BytecodeMetadataProvider bytecodeMetadataProvider,
+ Timing timing) {
+ DexEncodedMethod method = code.method();
+ method.setCode(
+ new IRToCfFinalizer(appView, deadCodeRemover)
+ .finalizeCode(code, bytecodeMetadataProvider, timing),
+ appView);
markProcessed(code, feedback);
}
private void finalizeToDex(
IRCode code,
OptimizationFeedback feedback,
- MethodConversionOptions conversionOptions,
BytecodeMetadataProvider bytecodeMetadataProvider,
Timing timing) {
DexEncodedMethod method = code.method();
- // Workaround massive dex2oat memory use for self-recursive methods.
- CodeRewriter.disableDex2OatInliningForSelfRecursiveMethods(appView, code);
- // Workaround MAX_INT switch issue.
- codeRewriter.rewriteSwitchForMaxInt(code);
- // Perform register allocation.
- RegisterAllocator registerAllocator =
- performRegisterAllocation(code, method, conversionOptions, timing);
- timing.begin("Build DEX code");
- method.setCode(code, bytecodeMetadataProvider, registerAllocator, appView);
- timing.end();
- updateHighestSortingStrings(method);
- if (Log.ENABLED) {
- Log.debug(getClass(), "Resulting dex code for %s:\n%s",
- method.toSourceString(), logCode(options, method));
- }
- printMethod(code, "Final IR (non-SSA)", null);
- timing.begin("Marking processed");
+ method.setCode(
+ new IRToDexFinalizer(appView, codeRewriter, deadCodeRemover)
+ .finalizeCode(code, bytecodeMetadataProvider, timing),
+ appView);
markProcessed(code, feedback);
- timing.end();
+ updateHighestSortingStrings(method);
}
public void markProcessed(IRCode code, OptimizationFeedback feedback) {
@@ -1727,209 +1675,6 @@
}
}
- private RegisterAllocator performRegisterAllocation(
- IRCode code,
- DexEncodedMethod method,
- MethodConversionOptions conversionOptions,
- Timing timing) {
- // Always perform dead code elimination before register allocation. The register allocator
- // does not allow dead code (to make sure that we do not waste registers for unneeded values).
- assert deadCodeRemover.verifyNoDeadCode(code);
- materializeInstructionBeforeLongOperationsWorkaround(code);
- workaroundForwardingInitializerBug(code);
- timing.begin("Allocate registers");
- LinearScanRegisterAllocator registerAllocator = new LinearScanRegisterAllocator(appView, code);
- registerAllocator.allocateRegisters();
- timing.end();
- if (options.canHaveExceptionTargetingLoopHeaderBug()) {
- codeRewriter.workaroundExceptionTargetingLoopHeaderBug(code);
- }
- printMethod(code, "After register allocation (non-SSA)", null);
- if (conversionOptions.isPeepholeOptimizationsEnabled()) {
- timing.begin("Peephole optimize");
- for (int i = 0; i < PEEPHOLE_OPTIMIZATION_PASSES; i++) {
- CodeRewriter.collapseTrivialGotos(code);
- PeepholeOptimizer.optimize(code, registerAllocator);
- }
- timing.end();
- }
- timing.begin("Clean up");
- CodeRewriter.removeUnneededMovesOnExitingPaths(code, registerAllocator);
- CodeRewriter.collapseTrivialGotos(code);
- timing.end();
- if (Log.ENABLED) {
- Log.debug(getClass(), "Final (non-SSA) flow graph for %s:\n%s",
- method.toSourceString(), code);
- }
- return registerAllocator;
- }
-
- private void workaroundForwardingInitializerBug(IRCode code) {
- if (!options.canHaveForwardingInitInliningBug()) {
- return;
- }
- // Only constructors.
- if (!code.method().isInstanceInitializer()) {
- return;
- }
- // Only constructors with certain signatures.
- DexTypeList paramTypes = code.method().getReference().proto.parameters;
- if (paramTypes.size() != 3 ||
- paramTypes.values[0] != options.itemFactory.doubleType ||
- paramTypes.values[1] != options.itemFactory.doubleType ||
- !paramTypes.values[2].isClassType()) {
- return;
- }
- // Only if the constructor contains a super constructor call taking only parameters as
- // inputs.
- for (BasicBlock block : code.blocks) {
- InstructionListIterator it = block.listIterator(code);
- Instruction superConstructorCall =
- it.nextUntil(
- (i) ->
- i.isInvokeDirect()
- && i.asInvokeDirect().getInvokedMethod().name
- == options.itemFactory.constructorMethodName
- && i.asInvokeDirect().arguments().size() == 4
- && i.asInvokeDirect().arguments().stream().allMatch(Value::isArgument));
- if (superConstructorCall != null) {
- // We force a materializing const instruction in front of the super call to make
- // sure that there is at least one temporary register in the method. That disables
- // the inlining that is crashing on these devices.
- ensureInstructionBefore(code, superConstructorCall, it);
- break;
- }
- }
- }
-
- /**
- * For each block, we look to see if the header matches:
- *
- * <pre>
- * pseudo-instructions*
- * v2 <- long-{mul,div} v0 v1
- * pseudo-instructions*
- * v5 <- long-{add,sub} v3 v4
- * </pre>
- *
- * where v2 ~=~ v3 or v2 ~=~ v4 (with ~=~ being equal or an alias of) and the block is not a
- * fallthrough target.
- */
- private void materializeInstructionBeforeLongOperationsWorkaround(IRCode code) {
- if (!options.canHaveDex2OatLinkedListBug()) {
- return;
- }
- DexItemFactory factory = options.itemFactory;
- final Supplier<DexMethod> javaLangLangSignum =
- Suppliers.memoize(
- () ->
- factory.createMethod(
- factory.createString("Ljava/lang/Long;"),
- factory.createString("signum"),
- factory.intDescriptor,
- new DexString[] {factory.longDescriptor}));
- for (BasicBlock block : code.blocks) {
- InstructionListIterator it = block.listIterator(code);
- Instruction firstMaterializing = it.nextUntil(IRConverter::isNotPseudoInstruction);
- if (!isLongMul(firstMaterializing)) {
- continue;
- }
- Instruction secondMaterializing = it.nextUntil(IRConverter::isNotPseudoInstruction);
- if (!isLongAddOrSub(secondMaterializing)) {
- continue;
- }
- if (isFallthoughTarget(block)) {
- continue;
- }
- Value outOfMul = firstMaterializing.outValue();
- for (Value inOfAddOrSub : secondMaterializing.inValues()) {
- if (isAliasOf(inOfAddOrSub, outOfMul)) {
- it = block.listIterator(code);
- it.nextUntil(i -> i == firstMaterializing);
- Value longValue = firstMaterializing.inValues().get(0);
- InvokeStatic invokeLongSignum =
- new InvokeStatic(
- javaLangLangSignum.get(), null, Collections.singletonList(longValue));
- ensureThrowingInstructionBefore(code, firstMaterializing, it, invokeLongSignum);
- return;
- }
- }
- }
- }
-
- private static boolean isAliasOf(Value usedValue, Value definingValue) {
- while (true) {
- if (usedValue == definingValue) {
- return true;
- }
- Instruction definition = usedValue.definition;
- if (definition == null || !definition.isMove()) {
- return false;
- }
- usedValue = definition.asMove().src();
- }
- }
-
- private static boolean isNotPseudoInstruction(Instruction instruction) {
- return !(instruction.isDebugInstruction() || instruction.isMove());
- }
-
- private static boolean isLongMul(Instruction instruction) {
- return instruction != null
- && instruction.isMul()
- && instruction.asBinop().getNumericType() == NumericType.LONG
- && instruction.outValue() != null;
- }
-
- private static boolean isLongAddOrSub(Instruction instruction) {
- return instruction != null
- && (instruction.isAdd() || instruction.isSub())
- && instruction.asBinop().getNumericType() == NumericType.LONG;
- }
-
- private static boolean isFallthoughTarget(BasicBlock block) {
- for (BasicBlock pred : block.getPredecessors()) {
- if (pred.exit().fallthroughBlock() == block) {
- return true;
- }
- }
- return false;
- }
-
- private void ensureThrowingInstructionBefore(
- IRCode code, Instruction addBefore, InstructionListIterator it, Instruction instruction) {
- Instruction check = it.previous();
- assert addBefore == check;
- BasicBlock block = check.getBlock();
- if (block.hasCatchHandlers()) {
- // Split so the existing instructions retain their handlers and the new instruction has none.
- BasicBlock split = it.split(code);
- assert split.hasCatchHandlers();
- assert !block.hasCatchHandlers();
- it = block.listIterator(code, block.getInstructions().size() - 1);
- }
- instruction.setPosition(addBefore.getPosition());
- it.add(instruction);
- }
-
- private static void ensureInstructionBefore(
- IRCode code, Instruction addBefore, InstructionListIterator it) {
- // Force materialize a constant-zero before the long operation.
- Instruction check = it.previous();
- assert addBefore == check;
- // Forced definition of const-zero
- Value fixitValue = code.createValue(TypeElement.getInt());
- Instruction fixitDefinition = new AlwaysMaterializingDefinition(fixitValue);
- fixitDefinition.setBlock(addBefore.getBlock());
- fixitDefinition.setPosition(addBefore.getPosition());
- it.add(fixitDefinition);
- // Forced user of the forced definition to ensure it has a user and thus live range.
- Instruction fixitUser = new AlwaysMaterializingUser(fixitValue);
- fixitUser.setBlock(addBefore.getBlock());
- fixitUser.setPosition(addBefore.getPosition());
- it.add(fixitUser);
- }
-
private void printC1VisualizerHeader(DexEncodedMethod method) {
if (printer != null) {
printer.begin("compilation");
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRFinalizer.java b/src/main/java/com/android/tools/r8/ir/conversion/IRFinalizer.java
new file mode 100644
index 0000000..c0c6808
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRFinalizer.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.conversion;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.optimize.DeadCodeRemover;
+import com.android.tools.r8.utils.Timing;
+
+public abstract class IRFinalizer<C extends Code> {
+
+ protected final AppView<?> appView;
+ protected final DeadCodeRemover deadCodeRemover;
+
+ public IRFinalizer(AppView<?> appView, DeadCodeRemover deadCodeRemover) {
+ this.appView = appView;
+ this.deadCodeRemover = deadCodeRemover;
+ }
+
+ public abstract C finalizeCode(
+ IRCode code, BytecodeMetadataProvider bytecodeMetadataProvider, Timing timing);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRToCfFinalizer.java b/src/main/java/com/android/tools/r8/ir/conversion/IRToCfFinalizer.java
new file mode 100644
index 0000000..74d0376
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRToCfFinalizer.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.conversion;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.optimize.DeadCodeRemover;
+import com.android.tools.r8.utils.Timing;
+
+public class IRToCfFinalizer extends IRFinalizer<CfCode> {
+
+ public IRToCfFinalizer(AppView<?> appView, DeadCodeRemover deadCodeRemover) {
+ super(appView, deadCodeRemover);
+ }
+
+ @Override
+ public CfCode finalizeCode(
+ IRCode code, BytecodeMetadataProvider bytecodeMetadataProvider, Timing timing) {
+ ProgramMethod method = code.context();
+ return new CfBuilder(appView, method, code, bytecodeMetadataProvider).build(deadCodeRemover);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRToDexFinalizer.java b/src/main/java/com/android/tools/r8/ir/conversion/IRToDexFinalizer.java
new file mode 100644
index 0000000..c709bf5
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRToDexFinalizer.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.conversion;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexCode;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.optimize.CodeRewriter;
+import com.android.tools.r8.ir.optimize.DeadCodeRemover;
+import com.android.tools.r8.ir.optimize.PeepholeOptimizer;
+import com.android.tools.r8.ir.optimize.RuntimeWorkaroundCodeRewriter;
+import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
+import com.android.tools.r8.ir.regalloc.RegisterAllocator;
+import com.android.tools.r8.logging.Log;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Timing;
+
+public class IRToDexFinalizer extends IRFinalizer<DexCode> {
+
+ private static final int PEEPHOLE_OPTIMIZATION_PASSES = 2;
+
+ private final CodeRewriter codeRewriter;
+ private final InternalOptions options;
+
+ public IRToDexFinalizer(
+ AppView<?> appView, CodeRewriter codeRewriter, DeadCodeRemover deadCodeRemover) {
+ super(appView, deadCodeRemover);
+ this.codeRewriter = codeRewriter;
+ this.options = appView.options();
+ }
+
+ @Override
+ public DexCode finalizeCode(
+ IRCode code, BytecodeMetadataProvider bytecodeMetadataProvider, Timing timing) {
+ DexEncodedMethod method = code.method();
+ code.traceBlocks();
+ RuntimeWorkaroundCodeRewriter.workaroundNumberConversionRegisterAllocationBug(code, options);
+ // Workaround massive dex2oat memory use for self-recursive methods.
+ RuntimeWorkaroundCodeRewriter.workaroundDex2OatInliningIssue(appView, code);
+ // Workaround MAX_INT switch issue.
+ RuntimeWorkaroundCodeRewriter.workaroundSwitchMaxIntBug(code, codeRewriter, options);
+ RuntimeWorkaroundCodeRewriter.workaroundDex2OatLinkedListBug(code, options);
+ RuntimeWorkaroundCodeRewriter.workaroundForwardingInitializerBug(code, options);
+ RuntimeWorkaroundCodeRewriter.workaroundExceptionTargetingLoopHeaderBug(code, options);
+ // Perform register allocation.
+ RegisterAllocator registerAllocator = performRegisterAllocation(code, method, timing);
+ return new DexBuilder(code, bytecodeMetadataProvider, registerAllocator, options).build();
+ }
+
+ private RegisterAllocator performRegisterAllocation(
+ IRCode code, DexEncodedMethod method, Timing timing) {
+ // Always perform dead code elimination before register allocation. The register allocator
+ // does not allow dead code (to make sure that we do not waste registers for unneeded values).
+ assert deadCodeRemover.verifyNoDeadCode(code);
+ timing.begin("Allocate registers");
+ LinearScanRegisterAllocator registerAllocator = new LinearScanRegisterAllocator(appView, code);
+ registerAllocator.allocateRegisters();
+ timing.end();
+ if (code.getConversionOptions().isPeepholeOptimizationsEnabled()) {
+ timing.begin("Peephole optimize");
+ for (int i = 0; i < PEEPHOLE_OPTIMIZATION_PASSES; i++) {
+ CodeRewriter.collapseTrivialGotos(code);
+ PeepholeOptimizer.optimize(code, registerAllocator);
+ }
+ timing.end();
+ }
+ timing.begin("Clean up");
+ CodeRewriter.removeUnneededMovesOnExitingPaths(code, registerAllocator);
+ CodeRewriter.collapseTrivialGotos(code);
+ timing.end();
+ if (Log.ENABLED) {
+ Log.debug(
+ getClass(), "Final (non-SSA) flow graph for %s:\n%s", method.toSourceString(), code);
+ }
+ return registerAllocator;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodConversionOptions.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodConversionOptions.java
index 1dd9510..472f838 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodConversionOptions.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodConversionOptions.java
@@ -4,45 +4,64 @@
package com.android.tools.r8.ir.conversion;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.InternalOptions;
+
public abstract class MethodConversionOptions {
+ public abstract boolean isGeneratingClassFiles();
+
+ public final boolean isGeneratingDex() {
+ return !isGeneratingClassFiles();
+ }
+
public abstract boolean isPeepholeOptimizationsEnabled();
public static class MutableMethodConversionOptions extends MethodConversionOptions {
- private final MethodProcessor methodProcessor;
private boolean enablePeepholeOptimizations = true;
+ private boolean isGeneratingClassFiles;
- public MutableMethodConversionOptions(MethodProcessor methodProcessor) {
- this.methodProcessor = methodProcessor;
+ public MutableMethodConversionOptions(InternalOptions options) {
+ this.isGeneratingClassFiles = options.isGeneratingClassFiles();
}
- public void disablePeepholeOptimizations() {
+ public void disablePeepholeOptimizations(MethodProcessor methodProcessor) {
assert methodProcessor.isPrimaryMethodProcessor();
enablePeepholeOptimizations = false;
}
+ public MutableMethodConversionOptions setIsGeneratingClassFiles(
+ boolean isGeneratingClassFiles) {
+ this.isGeneratingClassFiles = isGeneratingClassFiles;
+ return this;
+ }
+
+ @Override
+ public boolean isGeneratingClassFiles() {
+ return isGeneratingClassFiles;
+ }
+
@Override
public boolean isPeepholeOptimizationsEnabled() {
- assert enablePeepholeOptimizations || methodProcessor.isPrimaryMethodProcessor();
return enablePeepholeOptimizations;
}
}
- public static class DefaultMethodConversionOptions extends MethodConversionOptions {
+ public static class ThrowingMethodConversionOptions extends MutableMethodConversionOptions {
- private static final DefaultMethodConversionOptions INSTANCE =
- new DefaultMethodConversionOptions();
+ public ThrowingMethodConversionOptions(InternalOptions options) {
+ super(options);
+ }
- private DefaultMethodConversionOptions() {}
-
- public static DefaultMethodConversionOptions getInstance() {
- return INSTANCE;
+ @Override
+ public boolean isGeneratingClassFiles() {
+ throw new Unreachable();
}
@Override
public boolean isPeepholeOptimizationsEnabled() {
- return true;
+ throw new Unreachable();
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java b/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java
index 845793f..6c4a72d 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java
@@ -50,13 +50,17 @@
private final IdentifierNameStringMarker identifierNameStringMarker;
private final ClassTypeElement stringType;
+ public StringSwitchRemover(AppView<?> appView) {
+ this(appView, null);
+ }
+
StringSwitchRemover(AppView<?> appView, IdentifierNameStringMarker identifierNameStringMarker) {
this.appView = appView;
this.identifierNameStringMarker = identifierNameStringMarker;
this.stringType = TypeElement.stringClassType(appView, definitelyNotNull());
}
- void run(IRCode code) {
+ public void run(IRCode code) {
if (!code.metadata().mayHaveStringSwitch()) {
assert Streams.stream(code.instructions()).noneMatch(Instruction::isStringSwitch);
return;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java b/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java
index b7909df..5373a30 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.google.common.base.Equivalence;
import java.util.Arrays;
@@ -17,10 +18,12 @@
private static final int UNKNOW_HASH = -1;
private static final int MAX_HASH_INSTRUCTIONS = 5;
private final RegisterAllocator allocator;
+ private final MethodConversionOptions conversionOptions;
private final int[] hashes;
BasicBlockInstructionsEquivalence(IRCode code, RegisterAllocator allocator) {
this.allocator = allocator;
+ this.conversionOptions = code.getConversionOptions();
hashes = new int[code.getCurrentBlockNumber() + 1];
Arrays.fill(hashes, UNKNOW_HASH);
}
@@ -34,7 +37,7 @@
for (int i = 0; i < instructions0.size(); i++) {
Instruction i0 = instructions0.get(i);
Instruction i1 = instructions1.get(i);
- if (!i0.identicalAfterRegisterAllocation(i1, allocator)) {
+ if (!i0.identicalAfterRegisterAllocation(i1, allocator, conversionOptions)) {
return false;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 204b1a6..a0aec41 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -39,7 +39,6 @@
import com.android.tools.r8.ir.analysis.value.ConstantOrNonConstantNumberValue;
import com.android.tools.r8.ir.analysis.value.SingleConstClassValue;
import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
-import com.android.tools.r8.ir.code.AlwaysMaterializingNop;
import com.android.tools.r8.ir.code.ArrayLength;
import com.android.tools.r8.ir.code.ArrayPut;
import com.android.tools.r8.ir.code.Assume;
@@ -158,7 +157,6 @@
private static final int MAX_FILL_ARRAY_SIZE = 8 * Constants.KILOBYTE;
// This constant was determined by experimentation.
private static final int STOP_SHARED_CONSTANT_THRESHOLD = 50;
- private static final int SELF_RECURSION_LIMIT = 4;
private final AppView<?> appView;
private final DexItemFactory dexItemFactory;
@@ -489,41 +487,6 @@
}
}
- // For method with many self-recursive calls, insert a try-catch to disable inlining.
- // Marshmallow dex2oat aggressively inlines and eats up all the memory on devices.
- public static void disableDex2OatInliningForSelfRecursiveMethods(
- AppView<?> appView, IRCode code) {
- if (!appView.options().canHaveDex2OatInliningIssue() || code.hasCatchHandlers()) {
- // Catch handlers disables inlining, so if the method already has catch handlers
- // there is nothing to do.
- return;
- }
- int selfRecursionFanOut = 0;
- Instruction lastSelfRecursiveCall = null;
- for (Instruction i : code.instructions()) {
- if (i.isInvokeMethod()
- && i.asInvokeMethod().getInvokedMethod() == code.method().getReference()) {
- selfRecursionFanOut++;
- lastSelfRecursiveCall = i;
- }
- }
- if (selfRecursionFanOut > SELF_RECURSION_LIMIT) {
- assert lastSelfRecursiveCall != null;
- // Split out the last recursive call in its own block.
- InstructionListIterator splitIterator =
- lastSelfRecursiveCall.getBlock().listIterator(code, lastSelfRecursiveCall);
- splitIterator.previous();
- BasicBlock newBlock = splitIterator.split(code, 1);
- // Generate rethrow block.
- DexType guard = appView.dexItemFactory().throwableType;
- BasicBlock rethrowBlock =
- BasicBlock.createRethrowBlock(code, lastSelfRecursiveCall.getPosition(), guard, appView);
- code.blocks.add(rethrowBlock);
- // Add catch handler to the block containing the last recursive call.
- newBlock.appendCatchHandler(rethrowBlock, guard);
- }
- }
-
// TODO(sgjesse); Move this somewhere else, and reuse it for some of the other switch rewritings.
public abstract static class InstructionBuilder<T> {
protected int blockNumber;
@@ -663,7 +626,7 @@
* Covert the switch instruction to a sequence of if instructions checking for a specified set of
* keys, followed by a new switch with the remaining keys.
*/
- private void convertSwitchToSwitchAndIfs(
+ void convertSwitchToSwitchAndIfs(
IRCode code,
ListIterator<BasicBlock> blocksIterator,
BasicBlock originalBlock,
@@ -945,57 +908,6 @@
return rewriteSwitchFull(code, switchCaseAnalyzer);
}
- public void rewriteSwitchForMaxInt(IRCode code) {
- if (options.canHaveSwitchMaxIntBug() && code.metadata().mayHaveSwitch()) {
- // Always rewrite for workaround switch bug.
- rewriteSwitchForMaxIntOnly(code);
- }
- }
-
- private void rewriteSwitchForMaxIntOnly(IRCode code) {
- boolean needToSplitCriticalEdges = false;
- ListIterator<BasicBlock> blocksIterator = code.listIterator();
- while (blocksIterator.hasNext()) {
- BasicBlock block = blocksIterator.next();
- InstructionListIterator iterator = block.listIterator(code);
- while (iterator.hasNext()) {
- Instruction instruction = iterator.next();
- assert !instruction.isStringSwitch();
- if (instruction.isIntSwitch()) {
- IntSwitch intSwitch = instruction.asIntSwitch();
- if (intSwitch.getKey(intSwitch.numberOfKeys() - 1) == Integer.MAX_VALUE) {
- if (intSwitch.numberOfKeys() == 1) {
- rewriteSingleKeySwitchToIf(code, block, iterator, intSwitch);
- } else {
- IntList newSwitchSequences = new IntArrayList(intSwitch.numberOfKeys() - 1);
- for (int i = 0; i < intSwitch.numberOfKeys() - 1; i++) {
- newSwitchSequences.add(intSwitch.getKey(i));
- }
- IntList outliers = new IntArrayList(1);
- outliers.add(Integer.MAX_VALUE);
- convertSwitchToSwitchAndIfs(
- code,
- blocksIterator,
- block,
- iterator,
- intSwitch,
- ImmutableList.of(newSwitchSequences),
- outliers);
- }
- needToSplitCriticalEdges = true;
- }
- }
- }
- }
-
- // Rewriting of switches introduces new branching structure. It relies on critical edges
- // being split on the way in but does not maintain this property. We therefore split
- // critical edges at exit.
- if (needToSplitCriticalEdges) {
- code.splitCriticalEdges();
- }
- }
-
private boolean rewriteSwitchFull(IRCode code, SwitchCaseAnalyzer switchCaseAnalyzer) {
boolean needToRemoveUnreachableBlocks = false;
ListIterator<BasicBlock> blocksIterator = code.listIterator();
@@ -1045,7 +957,7 @@
return !affectedValues.isEmpty();
}
- private void rewriteSingleKeySwitchToIf(
+ void rewriteSingleKeySwitchToIf(
IRCode code, BasicBlock block, InstructionListIterator iterator, IntSwitch theSwitch) {
// Rewrite the switch to an if.
int fallthroughBlockIndex = theSwitch.getFallthroughBlockIndex();
@@ -3870,78 +3782,4 @@
}
}
}
-
- // See comment for InternalOptions.canHaveNumberConversionRegisterAllocationBug().
- public void workaroundNumberConversionRegisterAllocationBug(IRCode code) {
- ListIterator<BasicBlock> blocks = code.listIterator();
- while (blocks.hasNext()) {
- BasicBlock block = blocks.next();
- InstructionListIterator it = block.listIterator(code);
- while (it.hasNext()) {
- Instruction instruction = it.next();
- if (instruction.isArithmeticBinop() || instruction.isNeg()) {
- for (Value value : instruction.inValues()) {
- // Insert a call to Double.isNaN on each value which come from a number conversion
- // to double and flows into an arithmetic instruction. This seems to break the traces
- // in the Dalvik JIT and avoid the bug where the generated ARM code can clobber float
- // values in a single-precision registers with double values written to
- // double-precision registers. See b/77496850 for examples.
- if (!value.isPhi()
- && value.definition.isNumberConversion()
- && value.definition.asNumberConversion().to == NumericType.DOUBLE) {
- InvokeStatic invokeIsNaN =
- new InvokeStatic(
- dexItemFactory.doubleMembers.isNaN, null, ImmutableList.of(value));
- invokeIsNaN.setPosition(instruction.getPosition());
-
- // Insert the invoke before the current instruction.
- it.previous();
- BasicBlock blockWithInvokeNaN =
- block.hasCatchHandlers() ? it.split(code, blocks) : block;
- if (blockWithInvokeNaN != block) {
- // If we split, add the invoke at the end of the original block.
- it = block.listIterator(code, block.getInstructions().size());
- it.previous();
- it.add(invokeIsNaN);
- // Continue iteration in the split block.
- block = blockWithInvokeNaN;
- it = block.listIterator(code);
- } else {
- // Otherwise, add it to the current block.
- it.add(invokeIsNaN);
- }
- // Skip over the instruction causing the invoke to be inserted.
- Instruction temp = it.next();
- assert temp == instruction;
- }
- }
- }
- }
- }
- }
-
- // If an exceptional edge could target a conditional-loop header ensure that we have a
- // materializing instruction on that path to work around a bug in some L x86_64 non-emulator VMs.
- // See b/111337896.
- public void workaroundExceptionTargetingLoopHeaderBug(IRCode code) {
- for (BasicBlock block : code.blocks) {
- if (block.hasCatchHandlers()) {
- for (BasicBlock handler : block.getCatchHandlers().getUniqueTargets()) {
- // We conservatively assume that a block with at least two normal predecessors is a loop
- // header. If we ever end up computing exact loop headers, use that here instead.
- // The loop is conditional if it has at least two normal successors.
- BasicBlock target = handler.endOfGotoChain();
- if (target != null
- && target.getPredecessors().size() > 1
- && target.getNormalPredecessors().size() > 1
- && target.getNormalSuccessors().size() > 1) {
- Instruction fixit = new AlwaysMaterializingNop();
- fixit.setBlock(handler);
- fixit.setPosition(handler.getPosition());
- handler.getInstructions().addFirst(fixit);
- }
- }
- }
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InstructionEquivalence.java b/src/main/java/com/android/tools/r8/ir/optimize/InstructionEquivalence.java
index 2f2523d..68207cd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InstructionEquivalence.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InstructionEquivalence.java
@@ -3,21 +3,25 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
+import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.google.common.base.Equivalence;
public class InstructionEquivalence extends Equivalence<Instruction> {
private final RegisterAllocator allocator;
+ private final MethodConversionOptions conversionOptions;
- InstructionEquivalence(RegisterAllocator allocator) {
+ InstructionEquivalence(RegisterAllocator allocator, IRCode code) {
this.allocator = allocator;
+ this.conversionOptions = code.getConversionOptions();
}
@Override
protected boolean doEquivalent(Instruction a, Instruction b) {
- return a.identicalAfterRegisterAllocation(b, allocator)
+ return a.identicalAfterRegisterAllocation(b, allocator, conversionOptions)
&& a.getBlock().getCatchHandlers().equals(b.getBlock().getCatchHandlers());
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
index f04e328..fa902a6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
@@ -59,6 +59,7 @@
import com.android.tools.r8.ir.code.ValueTypeConstraint;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SourceCode;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
@@ -1794,9 +1795,13 @@
}
@Override
- public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
OutlineSourceCode source = new OutlineSourceCode(outline, method.getReference());
- return IRBuilder.create(method, appView, source, origin).build(method);
+ return IRBuilder.create(method, appView, source, origin).build(method, conversionOptions);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
index a8cd620..ffda2f3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
@@ -46,7 +46,7 @@
/** Identify common prefixes in successor blocks and share them. */
private static void shareIdenticalBlockPrefix(IRCode code, RegisterAllocator allocator) {
- InstructionEquivalence equivalence = new InstructionEquivalence(allocator);
+ InstructionEquivalence equivalence = new InstructionEquivalence(allocator, code);
Set<BasicBlock> blocksToBeRemoved = Sets.newIdentityHashSet();
for (BasicBlock block : code.blocks) {
shareIdenticalBlockPrefixFromNormalSuccessors(
@@ -244,7 +244,7 @@
do {
Map<BasicBlock, BasicBlock> newBlocks = new IdentityHashMap<>();
for (BasicBlock block : blocks) {
- InstructionEquivalence equivalence = new InstructionEquivalence(allocator);
+ InstructionEquivalence equivalence = new InstructionEquivalence(allocator, code);
// Group interesting predecessor blocks by their last instruction.
Map<Wrapper<Instruction>, List<BasicBlock>> lastInstructionToBlocks = new HashMap<>();
for (BasicBlock pred : block.getPredecessors()) {
@@ -284,7 +284,7 @@
BasicBlock pred = predsWithSameLastInstruction.get(i);
assert pred.exit().isGoto() || pred.exit().isReturn();
commonSuffixSize =
- Math.min(commonSuffixSize, sharedSuffixSize(firstPred, pred, allocator));
+ Math.min(commonSuffixSize, sharedSuffixSize(firstPred, pred, allocator, code));
}
int sizeDelta = overhead - (predsWithSameLastInstruction.size() - 1) * commonSuffixSize;
@@ -403,7 +403,7 @@
}
private static int sharedSuffixSize(
- BasicBlock block0, BasicBlock block1, RegisterAllocator allocator) {
+ BasicBlock block0, BasicBlock block1, RegisterAllocator allocator, IRCode code) {
assert block0.exit().isGoto() || block0.exit().isReturn();
// If the blocks do not agree on locals at exit then they don't have any shared suffix.
if (!Objects.equals(localsAtBlockExit(block0), localsAtBlockExit(block1))) {
@@ -415,7 +415,7 @@
while (it0.hasPrevious() && it1.hasPrevious()) {
Instruction i0 = it0.previous();
Instruction i1 = it1.previous();
- if (!i0.identicalAfterRegisterAllocation(i1, allocator)) {
+ if (!i0.identicalAfterRegisterAllocation(i1, allocator, code.getConversionOptions())) {
return suffixSize;
}
suffixSize++;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RuntimeWorkaroundCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/RuntimeWorkaroundCodeRewriter.java
new file mode 100644
index 0000000..20b26b0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RuntimeWorkaroundCodeRewriter.java
@@ -0,0 +1,375 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.AlwaysMaterializingDefinition;
+import com.android.tools.r8.ir.code.AlwaysMaterializingNop;
+import com.android.tools.r8.ir.code.AlwaysMaterializingUser;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.IntSwitch;
+import com.android.tools.r8.ir.code.InvokeStatic;
+import com.android.tools.r8.ir.code.NumericType;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableList;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.ints.IntList;
+import java.util.Collections;
+import java.util.ListIterator;
+import java.util.function.Supplier;
+
+public class RuntimeWorkaroundCodeRewriter {
+
+ private static final int SELF_RECURSION_LIMIT = 4;
+
+ // For method with many self-recursive calls, insert a try-catch to disable inlining.
+ // Marshmallow dex2oat aggressively inlines and eats up all the memory on devices.
+ public static void workaroundDex2OatInliningIssue(AppView<?> appView, IRCode code) {
+ if (!appView.options().canHaveDex2OatInliningIssue() || code.hasCatchHandlers()) {
+ // Catch handlers disables inlining, so if the method already has catch handlers
+ // there is nothing to do.
+ return;
+ }
+ int selfRecursionFanOut = 0;
+ Instruction lastSelfRecursiveCall = null;
+ for (Instruction i : code.instructions()) {
+ if (i.isInvokeMethod()
+ && i.asInvokeMethod().getInvokedMethod() == code.method().getReference()) {
+ selfRecursionFanOut++;
+ lastSelfRecursiveCall = i;
+ }
+ }
+ if (selfRecursionFanOut > SELF_RECURSION_LIMIT) {
+ assert lastSelfRecursiveCall != null;
+ // Split out the last recursive call in its own block.
+ InstructionListIterator splitIterator =
+ lastSelfRecursiveCall.getBlock().listIterator(code, lastSelfRecursiveCall);
+ splitIterator.previous();
+ BasicBlock newBlock = splitIterator.split(code, 1);
+ // Generate rethrow block.
+ DexType guard = appView.dexItemFactory().throwableType;
+ BasicBlock rethrowBlock =
+ BasicBlock.createRethrowBlock(code, lastSelfRecursiveCall.getPosition(), guard, appView);
+ code.blocks.add(rethrowBlock);
+ // Add catch handler to the block containing the last recursive call.
+ newBlock.appendCatchHandler(rethrowBlock, guard);
+ }
+ }
+
+ /**
+ * For each block, we look to see if the header matches:
+ *
+ * <pre>
+ * pseudo-instructions*
+ * v2 <- long-{mul,div} v0 v1
+ * pseudo-instructions*
+ * v5 <- long-{add,sub} v3 v4
+ * </pre>
+ *
+ * where v2 ~=~ v3 or v2 ~=~ v4 (with ~=~ being equal or an alias of) and the block is not a
+ * fallthrough target.
+ */
+ public static void workaroundDex2OatLinkedListBug(IRCode code, InternalOptions options) {
+ if (!options.canHaveDex2OatLinkedListBug()) {
+ return;
+ }
+ DexItemFactory factory = options.itemFactory;
+ final Supplier<DexMethod> javaLangLangSignum =
+ Suppliers.memoize(
+ () ->
+ factory.createMethod(
+ factory.createString("Ljava/lang/Long;"),
+ factory.createString("signum"),
+ factory.intDescriptor,
+ new DexString[] {factory.longDescriptor}));
+ for (BasicBlock block : code.blocks) {
+ InstructionListIterator it = block.listIterator(code);
+ Instruction firstMaterializing =
+ it.nextUntil(RuntimeWorkaroundCodeRewriter::isNotPseudoInstruction);
+ if (!isLongMul(firstMaterializing)) {
+ continue;
+ }
+ Instruction secondMaterializing =
+ it.nextUntil(RuntimeWorkaroundCodeRewriter::isNotPseudoInstruction);
+ if (!isLongAddOrSub(secondMaterializing)) {
+ continue;
+ }
+ if (isFallthoughTarget(block)) {
+ continue;
+ }
+ Value outOfMul = firstMaterializing.outValue();
+ for (Value inOfAddOrSub : secondMaterializing.inValues()) {
+ if (isAliasOf(inOfAddOrSub, outOfMul)) {
+ it = block.listIterator(code);
+ it.nextUntil(i -> i == firstMaterializing);
+ Value longValue = firstMaterializing.inValues().get(0);
+ InvokeStatic invokeLongSignum =
+ new InvokeStatic(
+ javaLangLangSignum.get(), null, Collections.singletonList(longValue));
+ ensureThrowingInstructionBefore(code, firstMaterializing, it, invokeLongSignum);
+ return;
+ }
+ }
+ }
+ }
+
+ // If an exceptional edge could target a conditional-loop header ensure that we have a
+ // materializing instruction on that path to work around a bug in some L x86_64 non-emulator VMs.
+ // See b/111337896.
+ public static void workaroundExceptionTargetingLoopHeaderBug(
+ IRCode code, InternalOptions options) {
+ if (!options.canHaveExceptionTargetingLoopHeaderBug()) {
+ return;
+ }
+ for (BasicBlock block : code.blocks) {
+ if (block.hasCatchHandlers()) {
+ for (BasicBlock handler : block.getCatchHandlers().getUniqueTargets()) {
+ // We conservatively assume that a block with at least two normal predecessors is a loop
+ // header. If we ever end up computing exact loop headers, use that here instead.
+ // The loop is conditional if it has at least two normal successors.
+ BasicBlock target = handler.endOfGotoChain();
+ if (target != null
+ && target.getPredecessors().size() > 1
+ && target.getNormalPredecessors().size() > 1
+ && target.getNormalSuccessors().size() > 1) {
+ Instruction fixit = new AlwaysMaterializingNop();
+ fixit.setBlock(handler);
+ fixit.setPosition(handler.getPosition());
+ handler.getInstructions().addFirst(fixit);
+ }
+ }
+ }
+ }
+ }
+
+ public static void workaroundForwardingInitializerBug(IRCode code, InternalOptions options) {
+ if (!options.canHaveForwardingInitInliningBug()) {
+ return;
+ }
+ // Only constructors.
+ if (!code.method().isInstanceInitializer()) {
+ return;
+ }
+ // Only constructors with certain signatures.
+ DexTypeList paramTypes = code.method().getReference().proto.parameters;
+ if (paramTypes.size() != 3
+ || paramTypes.values[0] != options.itemFactory.doubleType
+ || paramTypes.values[1] != options.itemFactory.doubleType
+ || !paramTypes.values[2].isClassType()) {
+ return;
+ }
+ // Only if the constructor contains a super constructor call taking only parameters as
+ // inputs.
+ for (BasicBlock block : code.blocks) {
+ InstructionListIterator it = block.listIterator(code);
+ Instruction superConstructorCall =
+ it.nextUntil(
+ (i) ->
+ i.isInvokeDirect()
+ && i.asInvokeDirect().getInvokedMethod().name
+ == options.itemFactory.constructorMethodName
+ && i.asInvokeDirect().arguments().size() == 4
+ && i.asInvokeDirect().arguments().stream().allMatch(Value::isArgument));
+ if (superConstructorCall != null) {
+ // We force a materializing const instruction in front of the super call to make
+ // sure that there is at least one temporary register in the method. That disables
+ // the inlining that is crashing on these devices.
+ ensureInstructionBefore(code, superConstructorCall, it);
+ break;
+ }
+ }
+ }
+
+ public static void workaroundSwitchMaxIntBug(
+ IRCode code, CodeRewriter codeRewriter, InternalOptions options) {
+ if (options.canHaveSwitchMaxIntBug() && code.metadata().mayHaveSwitch()) {
+ // Always rewrite for workaround switch bug.
+ rewriteSwitchForMaxIntOnly(code, codeRewriter);
+ }
+ }
+
+ private static void rewriteSwitchForMaxIntOnly(IRCode code, CodeRewriter codeRewriter) {
+ boolean needToSplitCriticalEdges = false;
+ ListIterator<BasicBlock> blocksIterator = code.listIterator();
+ while (blocksIterator.hasNext()) {
+ BasicBlock block = blocksIterator.next();
+ InstructionListIterator iterator = block.listIterator(code);
+ while (iterator.hasNext()) {
+ Instruction instruction = iterator.next();
+ assert !instruction.isStringSwitch();
+ if (instruction.isIntSwitch()) {
+ IntSwitch intSwitch = instruction.asIntSwitch();
+ if (intSwitch.getKey(intSwitch.numberOfKeys() - 1) == Integer.MAX_VALUE) {
+ if (intSwitch.numberOfKeys() == 1) {
+ codeRewriter.rewriteSingleKeySwitchToIf(code, block, iterator, intSwitch);
+ } else {
+ IntList newSwitchSequences = new IntArrayList(intSwitch.numberOfKeys() - 1);
+ for (int i = 0; i < intSwitch.numberOfKeys() - 1; i++) {
+ newSwitchSequences.add(intSwitch.getKey(i));
+ }
+ IntList outliers = new IntArrayList(1);
+ outliers.add(Integer.MAX_VALUE);
+ codeRewriter.convertSwitchToSwitchAndIfs(
+ code,
+ blocksIterator,
+ block,
+ iterator,
+ intSwitch,
+ ImmutableList.of(newSwitchSequences),
+ outliers);
+ }
+ needToSplitCriticalEdges = true;
+ }
+ }
+ }
+ }
+
+ // Rewriting of switches introduces new branching structure. It relies on critical edges
+ // being split on the way in but does not maintain this property. We therefore split
+ // critical edges at exit.
+ if (needToSplitCriticalEdges) {
+ code.splitCriticalEdges();
+ }
+ }
+
+ // See comment for InternalOptions.canHaveNumberConversionRegisterAllocationBug().
+ public static void workaroundNumberConversionRegisterAllocationBug(
+ IRCode code, InternalOptions options) {
+ if (!options.canHaveNumberConversionRegisterAllocationBug()) {
+ return;
+ }
+
+ DexItemFactory dexItemFactory = options.dexItemFactory();
+ ListIterator<BasicBlock> blocks = code.listIterator();
+ while (blocks.hasNext()) {
+ BasicBlock block = blocks.next();
+ InstructionListIterator it = block.listIterator(code);
+ while (it.hasNext()) {
+ Instruction instruction = it.next();
+ if (instruction.isArithmeticBinop() || instruction.isNeg()) {
+ for (Value value : instruction.inValues()) {
+ // Insert a call to Double.isNaN on each value which come from a number conversion
+ // to double and flows into an arithmetic instruction. This seems to break the traces
+ // in the Dalvik JIT and avoid the bug where the generated ARM code can clobber float
+ // values in a single-precision registers with double values written to
+ // double-precision registers. See b/77496850 for examples.
+ if (!value.isPhi()
+ && value.definition.isNumberConversion()
+ && value.definition.asNumberConversion().to == NumericType.DOUBLE) {
+ InvokeStatic invokeIsNaN =
+ new InvokeStatic(
+ dexItemFactory.doubleMembers.isNaN, null, ImmutableList.of(value));
+ invokeIsNaN.setPosition(instruction.getPosition());
+
+ // Insert the invoke before the current instruction.
+ it.previous();
+ BasicBlock blockWithInvokeNaN =
+ block.hasCatchHandlers() ? it.split(code, blocks) : block;
+ if (blockWithInvokeNaN != block) {
+ // If we split, add the invoke at the end of the original block.
+ it = block.listIterator(code, block.getInstructions().size());
+ it.previous();
+ it.add(invokeIsNaN);
+ // Continue iteration in the split block.
+ block = blockWithInvokeNaN;
+ it = block.listIterator(code);
+ } else {
+ // Otherwise, add it to the current block.
+ it.add(invokeIsNaN);
+ }
+ // Skip over the instruction causing the invoke to be inserted.
+ Instruction temp = it.next();
+ assert temp == instruction;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static void ensureInstructionBefore(
+ IRCode code, Instruction addBefore, InstructionListIterator it) {
+ // Force materialize a constant-zero before the long operation.
+ Instruction check = it.previous();
+ assert addBefore == check;
+ // Forced definition of const-zero
+ Value fixitValue = code.createValue(TypeElement.getInt());
+ Instruction fixitDefinition = new AlwaysMaterializingDefinition(fixitValue);
+ fixitDefinition.setBlock(addBefore.getBlock());
+ fixitDefinition.setPosition(addBefore.getPosition());
+ it.add(fixitDefinition);
+ // Forced user of the forced definition to ensure it has a user and thus live range.
+ Instruction fixitUser = new AlwaysMaterializingUser(fixitValue);
+ fixitUser.setBlock(addBefore.getBlock());
+ fixitUser.setPosition(addBefore.getPosition());
+ it.add(fixitUser);
+ }
+
+ private static void ensureThrowingInstructionBefore(
+ IRCode code, Instruction addBefore, InstructionListIterator it, Instruction instruction) {
+ Instruction check = it.previous();
+ assert addBefore == check;
+ BasicBlock block = check.getBlock();
+ if (block.hasCatchHandlers()) {
+ // Split so the existing instructions retain their handlers and the new instruction has none.
+ BasicBlock split = it.split(code);
+ assert split.hasCatchHandlers();
+ assert !block.hasCatchHandlers();
+ it = block.listIterator(code, block.getInstructions().size() - 1);
+ }
+ instruction.setPosition(addBefore.getPosition());
+ it.add(instruction);
+ }
+
+ private static boolean isNotPseudoInstruction(Instruction instruction) {
+ return !(instruction.isDebugInstruction() || instruction.isMove());
+ }
+
+ private static boolean isAliasOf(Value usedValue, Value definingValue) {
+ while (true) {
+ if (usedValue == definingValue) {
+ return true;
+ }
+ Instruction definition = usedValue.definition;
+ if (definition == null || !definition.isMove()) {
+ return false;
+ }
+ usedValue = definition.asMove().src();
+ }
+ }
+
+ private static boolean isLongMul(Instruction instruction) {
+ return instruction != null
+ && instruction.isMul()
+ && instruction.asBinop().getNumericType() == NumericType.LONG
+ && instruction.outValue() != null;
+ }
+
+ private static boolean isLongAddOrSub(Instruction instruction) {
+ return instruction != null
+ && (instruction.isAdd() || instruction.isSub())
+ && instruction.asBinop().getNumericType() == NumericType.LONG;
+ }
+
+ private static boolean isFallthoughTarget(BasicBlock block) {
+ for (BasicBlock pred : block.getPredecessors()) {
+ if (pred.exit().fallthroughBlock() == block) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
index 23ae546..bde3a44 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.conversion.PostMethodProcessor.Builder;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
@@ -38,7 +37,7 @@
}
@Override
- public void analyzeEnums(IRCode code, MutableMethodConversionOptions conversionOptions) {
+ public void analyzeEnums(IRCode code, MethodProcessor methodProcessor) {
// Intentionally empty.
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index ae119f6..659d802 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.conversion.PostMethodProcessor.Builder;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
@@ -35,7 +34,7 @@
public abstract void prepareForPrimaryOptimizationPass(
GraphLens graphLensForPrimaryOptimizationPass);
- public abstract void analyzeEnums(IRCode code, MutableMethodConversionOptions conversionOptions);
+ public abstract void analyzeEnums(IRCode code, MethodProcessor methodProcessor);
public abstract void onMethodPruned(ProgramMethod method);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index 700c1d7..d926360 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -75,7 +75,6 @@
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.conversion.PostMethodProcessor.Builder;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
@@ -236,7 +235,7 @@
}
@Override
- public void analyzeEnums(IRCode code, MutableMethodConversionOptions conversionOptions) {
+ public void analyzeEnums(IRCode code, MethodProcessor methodProcessor) {
Set<DexType> eligibleEnums = Sets.newIdentityHashSet();
for (BasicBlock block : code.blocks) {
for (Instruction instruction : block.getInstructions()) {
@@ -307,7 +306,8 @@
}
}
if (methodsDependingOnLibraryModelisation.contains(code.context(), appView.graphLens())) {
- conversionOptions.disablePeepholeOptimizations();
+ code.mutateConversionOptions(
+ conversionOptions -> conversionOptions.disablePeepholeOptimizations(methodProcessor));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
index c2cbec9..dd73d7e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.Return;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
@@ -41,7 +42,11 @@
}
@Override
- public IRCode buildIR(ProgramMethod checkNotZeroMethod, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(
+ ProgramMethod checkNotZeroMethod,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
// Build IR from the checkNotNull() method.
IRCode code = checkNotNullMethod.buildIR(appView);
InstructionListIterator instructionIterator = code.instructionListIterator();
@@ -82,7 +87,8 @@
code.valueNumberGenerator,
code.basicBlockNumberGenerator,
code.metadata(),
- checkNotZeroMethod.getOrigin());
+ checkNotZeroMethod.getOrigin(),
+ conversionOptions);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java
index a2ecba8..efd09bc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java
@@ -18,7 +18,6 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.Assume;
import com.android.tools.r8.ir.code.BasicBlock;
-import com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.DominatorTree;
@@ -85,7 +84,6 @@
private final AppView<?> appView;
private final DexItemFactory factory;
- private final ThrowingInfo throwingInfo;
@VisibleForTesting
StringConcatenationAnalysis analysis;
final StringBuilderOptimizationConfiguration optimizationConfiguration;
@@ -108,7 +106,6 @@
public StringBuilderOptimizer(AppView<? extends AppInfo> appView) {
this.appView = appView;
this.factory = appView.dexItemFactory();
- this.throwingInfo = ThrowingInfo.defaultForConstString(appView.options());
this.optimizationConfiguration = new DefaultStringBuilderOptimizationConfiguration();
if (Log.ENABLED && Log.isLoggingEnabledFor(StringBuilderOptimizer.class)) {
histogramOfLengthOfAppendChains = new Object2IntArrayMap<>();
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 827f316..54de6c0 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -2508,11 +2508,7 @@
}
private static void addLiveRange(
- Value value,
- BasicBlock block,
- int end,
- List<LiveIntervals> liveIntervals,
- InternalOptions options) {
+ Value value, BasicBlock block, int end, List<LiveIntervals> liveIntervals, IRCode code) {
int firstInstructionInBlock = block.entry().getNumber();
int instructionsSize = block.getInstructions().size() * INSTRUCTION_NUMBER_DELTA;
int lastInstructionInBlock =
@@ -2548,8 +2544,8 @@
instructionNumber--;
}
intervals.addRange(new LiveRange(instructionNumber, end));
- assert unconstrainedForCf(intervals.getRegisterLimit(), options);
- if (options.isGeneratingDex() && !value.isPhi()) {
+ assert unconstrainedForCf(intervals.getRegisterLimit(), code);
+ if (code.getConversionOptions().isGeneratingDex() && !value.isPhi()) {
int constraint = value.definition.maxOutValueRegister();
intervals.addUse(new LiveIntervalsUse(instructionNumber, constraint));
}
@@ -2622,7 +2618,7 @@
if (phiOperands.contains(value)) {
end--;
}
- addLiveRange(value, block, end, liveIntervals, options);
+ addLiveRange(value, block, end, liveIntervals, code);
}
InstructionIterator iterator = block.iterator(block.getInstructions().size());
while (iterator.hasPrevious()) {
@@ -2642,20 +2638,20 @@
block,
instruction.getNumber() + INSTRUCTION_NUMBER_DELTA - 1,
liveIntervals,
- options);
- assert !options.isGeneratingClassFiles() || instruction.isArgument()
+ code);
+ assert !code.getConversionOptions().isGeneratingClassFiles() || instruction.isArgument()
: "Arguments should be the only potentially unused local in CF";
}
live.remove(definition);
}
for (Value use : instruction.inValues()) {
if (use.needsRegister()) {
- assert unconstrainedForCf(instruction.maxInValueRegister(), options);
+ assert unconstrainedForCf(instruction.maxInValueRegister(), code);
if (!live.contains(use)) {
live.add(use);
- addLiveRange(use, block, instruction.getNumber(), liveIntervals, options);
+ addLiveRange(use, block, instruction.getNumber(), liveIntervals, code);
}
- if (options.isGeneratingDex()) {
+ if (code.getConversionOptions().isGeneratingDex()) {
int inConstraint = instruction.maxInValueRegister();
LiveIntervals useIntervals = use.getLiveIntervals();
// Arguments are always kept in their original, incoming register. For every
@@ -2693,7 +2689,7 @@
block,
getLiveRangeEndOnExceptionalFlow(instruction, use),
liveIntervals,
- options);
+ code);
}
}
}
@@ -2707,7 +2703,7 @@
assert use.needsRegister();
if (!live.contains(use)) {
live.add(use);
- addLiveRange(use, block, number, liveIntervals, options);
+ addLiveRange(use, block, number, liveIntervals, code);
}
}
}
@@ -2723,8 +2719,8 @@
return end;
}
- private static boolean unconstrainedForCf(int constraint, InternalOptions options) {
- return !options.isGeneratingClassFiles() || constraint == Constants.U16BIT_MAX;
+ private static boolean unconstrainedForCf(int constraint, IRCode code) {
+ return code.getConversionOptions().isGeneratingDex() || constraint == Constants.U16BIT_MAX;
}
private void clearUserInfo() {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
index acf4d56..8c28b9e 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
@@ -18,6 +18,8 @@
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SourceCode;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
@@ -39,9 +41,13 @@
}
@Override
- public final IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ public final IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
return IRBuilder.create(method, appView, getSourceCodeProvider().get(method, null), origin)
- .build(method);
+ .build(method, conversionOptions);
}
@Override
@@ -62,7 +68,7 @@
origin,
valueNumberGenerator,
protoChanges)
- .build(context);
+ .build(context, new ThrowingMethodConversionOptions(appView.options()));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index dcf8dbd..b4fd639 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -2077,8 +2077,7 @@
// and the first register of the result could lead to the wrong exception
// being thrown on out of bounds.
public boolean canUseSameArrayAndResultRegisterInArrayGetWide() {
- assert isGeneratingDex();
- return getMinApiLevel().isGreaterThan(AndroidApiLevel.O_MR1);
+ return isGeneratingClassFiles() || getMinApiLevel().isGreaterThan(AndroidApiLevel.O_MR1);
}
// Some Lollipop versions of Art found in the wild perform invalid bounds
@@ -2309,8 +2308,7 @@
//
// Fixed in Android Q, see b/120985556.
public boolean canHaveArtInstanceOfVerifierBug() {
- assert isGeneratingDex();
- return getMinApiLevel().isLessThan(AndroidApiLevel.Q);
+ return isGeneratingDex() && getMinApiLevel().isLessThan(AndroidApiLevel.Q);
}
// Some Art Lollipop version do not deal correctly with long-to-int conversions.
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
index e4ee9bc..198139e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
import com.android.tools.r8.ir.regalloc.LiveIntervals;
import com.android.tools.r8.origin.Origin;
@@ -145,7 +146,8 @@
new NumberGenerator(),
basicBlockNumberGenerator,
IRMetadata.unknown(),
- Origin.unknown());
+ Origin.unknown(),
+ new MutableMethodConversionOptions(options));
PeepholeOptimizer.optimize(code, new MockLinearScanRegisterAllocator(appView, code));
// Check that all four constant number instructions remain.
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
index 868036c..c0cc06d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Throw;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
@@ -102,7 +103,8 @@
new NumberGenerator(),
basicBlockNumberGenerator,
IRMetadata.unknown(),
- Origin.unknown());
+ Origin.unknown(),
+ new MutableMethodConversionOptions(options));
CodeRewriter.collapseTrivialGotos(code);
assertTrue(code.entryBlock().isTrivialGoto());
assertTrue(blocks.contains(block0));
@@ -189,7 +191,8 @@
new NumberGenerator(),
basicBlockNumberGenerator,
IRMetadata.unknown(),
- Origin.unknown());
+ Origin.unknown(),
+ new MutableMethodConversionOptions(options));
CodeRewriter.collapseTrivialGotos(code);
assertTrue(block0.getInstructions().get(1).isIf());
assertEquals(block1, block0.getInstructions().get(1).asIf().fallthroughBlock());
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
index 9e9b1c4..4319780 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/IdenticalAfterRegisterAllocationTest.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.utils.InternalOptions;
import java.util.List;
import org.junit.Test;
@@ -86,6 +87,8 @@
assertTrue(value3.needsRegister());
// value1 and value2 represent different constants and the additions are therefore
// not equivalent.
- assertFalse(add0.identicalAfterRegisterAllocation(add1, allocator));
+ assertFalse(
+ add0.identicalAfterRegisterAllocation(
+ add1, allocator, new MutableMethodConversionOptions(allocator.options())));
}
}
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 249e78d..8e7929e 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -59,7 +59,9 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.code.ValueTypeConstraint;
+import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SourceCode;
import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
@@ -868,9 +870,16 @@
.disableAndroidApiLevelCheck()
.build();
ProgramMethod programMethod = new ProgramMethod(programClass, method);
- IRCode ir = code.buildIR(programMethod, appView, Origin.unknown());
+ IRCode ir =
+ code.buildIR(
+ programMethod,
+ appView,
+ Origin.unknown(),
+ new MutableMethodConversionOptions(options));
RegisterAllocator allocator = new LinearScanRegisterAllocator(appView, ir);
- method.setCode(ir, BytecodeMetadataProvider.empty(), allocator, appView);
+ method.setCode(
+ new DexBuilder(ir, BytecodeMetadataProvider.empty(), allocator, options).build(),
+ appView);
directMethods[i] = method;
}
programClass.getMethodCollection().addDirectMethods(Arrays.asList(directMethods));