Merge commit '24659d5eae579cd1db20ffe88f6a634a333e9bfe' into dev-release
Change-Id: I8edd1d5d428182ef95072c9061ff21a7c69414a4
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 3b8ba07..1deb035 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -138,6 +138,19 @@
private final com.android.tools.r8.position.Position diagnosticPosition;
private final BytecodeMetadata<CfInstruction> metadata;
+ public CfCode(CfCode code) {
+ this(
+ code.originalHolder,
+ code.maxStack,
+ code.maxLocals,
+ code.instructions,
+ code.tryCatchRanges,
+ code.localVariables,
+ code.diagnosticPosition,
+ code.metadata);
+ this.stackMapStatus = code.stackMapStatus;
+ }
+
public CfCode(
DexType originalHolder, int maxStack, int maxLocals, List<CfInstruction> instructions) {
this(
@@ -896,7 +909,7 @@
}
@Override
- public Code getCodeAsInlining(
+ public CfCode getCodeAsInlining(
DexMethod caller,
boolean isCallerD8R8Synthesized,
DexMethod callee,
diff --git a/src/main/java/com/android/tools/r8/graph/CfCodeWithLens.java b/src/main/java/com/android/tools/r8/graph/CfCodeWithLens.java
new file mode 100644
index 0000000..9ccdfa6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/CfCodeWithLens.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2024, 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.graph;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.graph.lens.GraphLens;
+import java.util.List;
+
+public class CfCodeWithLens extends CfCode {
+
+ private GraphLens codeLens;
+
+ public CfCodeWithLens(GraphLens codeLens, CfCode code) {
+ super(code);
+ this.codeLens = codeLens;
+ }
+
+ public CfCodeWithLens(
+ GraphLens codeLens,
+ DexType originalHolder,
+ int maxStack,
+ int maxLocals,
+ List<CfInstruction> instructions) {
+ super(originalHolder, maxStack, maxLocals, instructions);
+ this.codeLens = codeLens;
+ }
+
+ @Override
+ public GraphLens getCodeLens(AppView<?> appView) {
+ assert codeLens != null;
+ assert !codeLens.isIdentityLens();
+ return codeLens;
+ }
+
+ public void setCodeLens(GraphLens codeLens) {
+ this.codeLens = codeLens;
+ }
+
+ @Override
+ public CfCodeWithLens getCodeAsInlining(
+ DexMethod caller,
+ boolean isCallerD8R8Synthesized,
+ DexMethod callee,
+ boolean isCalleeD8R8Synthesized,
+ DexItemFactory factory) {
+ CfCode code =
+ super.getCodeAsInlining(
+ caller, isCallerD8R8Synthesized, callee, isCalleeD8R8Synthesized, factory);
+ return new CfCodeWithLens(codeLens, code);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteMergedInstanceInitializerCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteMergedInstanceInitializerCode.java
index e09f988..95a4920 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteMergedInstanceInitializerCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteMergedInstanceInitializerCode.java
@@ -20,11 +20,11 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.CfCodeWithLens;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.graph.lens.MethodLookupResult;
import com.android.tools.r8.ir.analysis.value.SingleConstValue;
import com.android.tools.r8.ir.analysis.value.SingleDexItemBasedStringValue;
@@ -166,17 +166,12 @@
// Return.
instructionBuilder.add(new CfReturnVoid());
- return new CfCode(
+ return new CfCodeWithLens(
+ lens,
originalMethodReference.getHolderType(),
maxStack.get(),
maxLocals,
- instructionBuilder.build()) {
-
- @Override
- public GraphLens getCodeLens(AppView<?> appView) {
- return lens;
- }
- };
+ instructionBuilder.build());
}
private static void addCfInstructionsForInstanceFieldAssignments(
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
index 6698a71..378b433 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
@@ -18,11 +18,11 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.CfCodeWithLens;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.horizontalclassmerging.VirtualMethodMerger.SuperMethodReference;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.utils.BooleanUtils;
@@ -153,13 +153,8 @@
} else {
instructions.add(new CfReturn(ValueType.fromDexType(method.getReturnType())));
}
- return new CfCode(originalMethod.getHolderType(), maxStack, maxLocals, instructions) {
-
- @Override
- public GraphLens getCodeLens(AppView<?> appView) {
- return lens;
- }
- };
+ return new CfCodeWithLens(
+ lens, originalMethod.getHolderType(), maxStack, maxLocals, instructions);
}
private static CfFrame createCfFrameForSwitchCase(ProgramMethod representative, int localsSize) {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
index a8e46f9..0c0f059 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
@@ -4,16 +4,33 @@
package com.android.tools.r8.horizontalclassmerging.code;
-import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClasspathMethod;
+import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.horizontalclassmerging.ConstructorEntryPoint;
-import com.android.tools.r8.ir.synthetic.AbstractSynthesizedCode;
+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.code.Position.SyntheticPosition;
+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.ir.conversion.SourceCode;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
-import java.util.function.Consumer;
-public class ConstructorEntryPointSynthesizedCode extends AbstractSynthesizedCode {
+public class ConstructorEntryPointSynthesizedCode extends Code {
+
private final DexMethod newConstructor;
private final DexField classIdField;
private final Int2ReferenceSortedMap<DexMethod> typeConstructors;
@@ -27,18 +44,7 @@
this.classIdField = classIdField;
}
- @Override
- public SourceCodeProvider getSourceCodeProvider() {
- return (ignored, position) ->
- new ConstructorEntryPoint(typeConstructors, newConstructor, classIdField, position);
- }
-
- @Override
- public Consumer<UseRegistry> getRegistryCallback(DexClassAndMethod method) {
- return this::registerReachableDefinitions;
- }
-
- private void registerReachableDefinitions(UseRegistry registry) {
+ private void registerReachableDefinitions(UseRegistry<?> registry) {
assert registry.getTraversalContinuation().shouldContinue();
for (DexMethod typeConstructor : typeConstructors.values()) {
registry.registerInvokeDirect(typeConstructor);
@@ -52,4 +58,91 @@
public boolean isHorizontalClassMergerCode() {
return true;
}
+
+ @Override
+ public final boolean isEmptyVoidMethod() {
+ return false;
+ }
+
+ @Override
+ public final IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
+ SyntheticPosition position =
+ SyntheticPosition.builder()
+ .setLine(0)
+ .setMethod(method.getReference())
+ .setIsD8R8Synthesized(true)
+ .build();
+ SourceCode sourceCode =
+ new ConstructorEntryPoint(typeConstructors, newConstructor, classIdField, position);
+ return IRBuilder.create(method, appView, sourceCode, origin).build(method, conversionOptions);
+ }
+
+ @Override
+ public final IRCode buildInliningIR(
+ ProgramMethod context,
+ ProgramMethod method,
+ AppView<?> appView,
+ GraphLens codeLens,
+ NumberGenerator valueNumberGenerator,
+ Position callerPosition,
+ Origin origin,
+ RewrittenPrototypeDescription protoChanges) {
+ SourceCode sourceCode =
+ new ConstructorEntryPoint(typeConstructors, newConstructor, classIdField, callerPosition);
+ return IRBuilder.createForInlining(
+ method, appView, codeLens, sourceCode, origin, valueNumberGenerator, protoChanges)
+ .build(context, MethodConversionOptions.nonConverting());
+ }
+
+ @Override
+ public final Code getCodeAsInlining(
+ DexMethod caller,
+ boolean isCallerD8R8Synthesized,
+ DexMethod callee,
+ boolean isCalleeD8R8Synthesized,
+ DexItemFactory factory) {
+ // This code object is synthesized so "inlining" just "strips" the callee position.
+ assert isCalleeD8R8Synthesized;
+ return this;
+ }
+
+ @Override
+ public final String toString() {
+ return toString(null, RetracerForCodePrinting.empty());
+ }
+
+ @Override
+ public final void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
+ registerReachableDefinitions(registry);
+ }
+
+ @Override
+ public final void registerCodeReferencesForDesugaring(
+ ClasspathMethod method, UseRegistry registry) {
+ registerReachableDefinitions(registry);
+ }
+
+ @Override
+ protected final int computeHashCode() {
+ throw new Unreachable();
+ }
+
+ @Override
+ protected final boolean computeEquals(Object other) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public final String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
+ return this.getClass().getSimpleName();
+ }
+
+ @Override
+ public final int estimatedDexCodeSizeUpperBoundInBytes() {
+ return Integer.MAX_VALUE;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/passes/CodeRewriterPassCollection.java b/src/main/java/com/android/tools/r8/ir/conversion/passes/CodeRewriterPassCollection.java
index 1610454..bb62066 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/passes/CodeRewriterPassCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/passes/CodeRewriterPassCollection.java
@@ -39,7 +39,9 @@
passes.add(new BranchSimplifier(appView));
passes.add(new SplitBranch(appView));
passes.add(new RedundantConstNumberRemover(appView));
- passes.add(new RedundantFieldLoadAndStoreElimination(appView));
+ if (!appView.options().debug) {
+ passes.add(new RedundantFieldLoadAndStoreElimination(appView));
+ }
passes.add(new BinopRewriter(appView));
return new CodeRewriterPassCollection(passes);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index 898bd66..064c4b2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -233,7 +233,7 @@
private final ProgramMethod method;
private final IRCode code;
private final int maxCapacityPerBlock;
- private final boolean release;
+ private final boolean release = true;
// Values that may require type propagation.
private final AffectedValues affectedValues = new AffectedValues();
@@ -254,7 +254,7 @@
this.code = code;
this.maxCapacityPerBlock =
Math.max(MIN_CAPACITY_PER_BLOCK, MAX_CAPACITY / code.blocks.size());
- this.release = !appView.options().debug;
+ assert !appView.options().debug;
}
class ExistingValue implements FieldValue {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
index 35e4f74..09b22db 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.contexts.CompilationContext.ProcessorContext;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCodeWithLens;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedField.Builder;
@@ -62,7 +63,6 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
-import com.android.tools.r8.ir.synthetic.EnumUnboxingCfCodeProvider.CfCodeWithLens;
import com.android.tools.r8.ir.synthetic.EnumUnboxingCfCodeProvider.EnumUnboxingMethodDispatchCfCodeProvider;
import com.android.tools.r8.ir.synthetic.ThrowCfCodeProvider;
import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
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
deleted file mode 100644
index 7a9429c..0000000
--- a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright (c) 2018, 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.synthetic;
-
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClasspathMethod;
-import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexClassAndMethod;
-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.ProgramMethod;
-import com.android.tools.r8.graph.UseRegistry;
-import com.android.tools.r8.graph.lens.GraphLens;
-import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
-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.code.Position.SyntheticPosition;
-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.ir.conversion.SourceCode;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.RetracerForCodePrinting;
-import java.util.function.Consumer;
-
-public abstract class AbstractSynthesizedCode extends Code {
-
- public interface SourceCodeProvider {
- SourceCode get(ProgramMethod context, Position callerPosition);
- }
-
- public abstract SourceCodeProvider getSourceCodeProvider();
-
- public abstract Consumer<UseRegistry> getRegistryCallback(DexClassAndMethod method);
-
- @Override
- public boolean isEmptyVoidMethod() {
- return false;
- }
-
- @Override
- public final IRCode buildIR(
- ProgramMethod method,
- AppView<?> appView,
- Origin origin,
- MutableMethodConversionOptions conversionOptions) {
- SyntheticPosition position =
- SyntheticPosition.builder()
- .setLine(0)
- .setMethod(method.getReference())
- .setIsD8R8Synthesized(true)
- .build();
- return IRBuilder.create(method, appView, getSourceCodeProvider().get(method, position), origin)
- .build(method, conversionOptions);
- }
-
- @Override
- public final IRCode buildInliningIR(
- ProgramMethod context,
- ProgramMethod method,
- AppView<?> appView,
- GraphLens codeLens,
- NumberGenerator valueNumberGenerator,
- Position callerPosition,
- Origin origin,
- RewrittenPrototypeDescription protoChanges) {
- return IRBuilder.createForInlining(
- method,
- appView,
- codeLens,
- getSourceCodeProvider().get(context, callerPosition),
- origin,
- valueNumberGenerator,
- protoChanges)
- .build(context, MethodConversionOptions.nonConverting());
- }
-
- @Override
- public final Code getCodeAsInlining(
- DexMethod caller,
- boolean isCallerD8R8Synthesized,
- DexMethod callee,
- boolean isCalleeD8R8Synthesized,
- DexItemFactory factory) {
- // This code object is synthesized so "inlining" just "strips" the callee position.
- assert isCalleeD8R8Synthesized;
- return this;
- }
-
- @Override
- public final String toString() {
- return toString(null, RetracerForCodePrinting.empty());
- }
-
- @Override
- public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
- internalRegisterCodeReferences(method, registry);
- }
-
- @Override
- public void registerCodeReferencesForDesugaring(ClasspathMethod method, UseRegistry registry) {
- internalRegisterCodeReferences(method, registry);
- }
-
- private void internalRegisterCodeReferences(DexClassAndMethod method, UseRegistry registry) {
- getRegistryCallback(method).accept(registry);
- }
-
- @Override
- protected final int computeHashCode() {
- throw new Unreachable();
- }
-
- @Override
- protected final boolean computeEquals(Object other) {
- throw new Unreachable();
- }
-
- @Override
- public final String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
- return this.getClass().getSimpleName();
- }
-
- @Override
- public int estimatedDexCodeSizeUpperBoundInBytes() {
- return Integer.MAX_VALUE;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
index ca847d1..2e5b45b 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
@@ -25,11 +25,11 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.CfCodeWithLens;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.code.IfType;
import com.android.tools.r8.ir.code.ValueType;
@@ -153,7 +153,7 @@
assert paramRegisterSize < 256;
int maxStack = 2 * paramRegisterSize + 16;
int maxLocals = paramRegisterSize + 16;
- return new CfCodeWithLens(getHolder(), maxStack, maxLocals, instructions);
+ return new CfCodeWithLens(null, getHolder(), maxStack, maxLocals, instructions);
}
private void addReturnInvoke(List<CfInstruction> instructions, DexMethod method) {
@@ -302,24 +302,4 @@
return standardCfCodeFromInstructions(instructions);
}
}
-
- public static class CfCodeWithLens extends CfCode {
-
- private GraphLens codeLens;
-
- public void setCodeLens(GraphLens codeLens) {
- this.codeLens = codeLens;
- }
-
- public CfCodeWithLens(
- DexType originalHolder, int maxStack, int maxLocals, List<CfInstruction> instructions) {
- super(originalHolder, maxStack, maxLocals, instructions);
- }
-
- @Override
- public GraphLens getCodeLens(AppView<?> appView) {
- assert codeLens != null;
- return codeLens;
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodBuilder.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodBuilder.java
index 71172bb..0718a90 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodBuilder.java
@@ -14,13 +14,14 @@
import com.android.tools.r8.cf.code.CfReturnVoid;
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
-import com.android.tools.r8.cf.code.CfTryCatch;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.CfCodeWithLens;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.utils.BooleanUtils;
import com.google.common.collect.ImmutableList;
@@ -43,6 +44,8 @@
private final DexItemFactory factory;
+ private GraphLens codeLens = null;
+
private DexMethod sourceMethod = null;
private DexMethod targetMethod = null;
@@ -81,6 +84,11 @@
return this;
}
+ public ForwardMethodBuilder setCodeLens(GraphLens codeLens) {
+ this.codeLens = codeLens;
+ return this;
+ }
+
public ForwardMethodBuilder setNonStaticSource(DexMethod method) {
sourceMethod = method;
staticSource = false;
@@ -205,15 +213,11 @@
}
instructions.add(new CfReturn(getSourceReturnType()));
}
- ImmutableList<CfTryCatch> tryCatchRanges = ImmutableList.of();
- ImmutableList<CfCode.LocalVariableInfo> localVariables = ImmutableList.of();
- return new CfCode(
- sourceMethod.holder,
- maxStack,
- maxLocals,
- instructions.build(),
- tryCatchRanges,
- localVariables);
+ if (codeLens != null) {
+ return new CfCodeWithLens(
+ codeLens, sourceMethod.holder, maxStack, maxLocals, instructions.build());
+ }
+ return new CfCode(sourceMethod.holder, maxStack, maxLocals, instructions.build());
}
@SuppressWarnings({"BadImport", "ReferenceEquality"})
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
deleted file mode 100644
index c1fbd37..0000000
--- a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright (c) 2017, 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.synthetic;
-
-import com.android.tools.r8.errors.Unimplemented;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.code.InvokeType;
-import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.utils.BooleanUtils;
-import com.google.common.collect.Lists;
-import java.util.ArrayList;
-import java.util.List;
-
-// Source code representing simple forwarding method.
-public final class ForwardMethodSourceCode extends SyntheticSourceCode {
-
- public static Builder builder(DexMethod method) {
- return new Builder(method);
- }
-
- public static class Builder {
-
- private DexType receiver;
- private DexMethod method;
- private DexType targetReceiver;
- private DexMethod target;
- private InvokeType invokeType;
- private boolean castResult;
- private boolean isInterface;
- private boolean extraNullParameter;
-
- public Builder(DexMethod method) {
- this.method = method;
- }
-
- public Builder setReceiver(DexType receiver) {
- this.receiver = receiver;
- return this;
- }
-
- public Builder setMethod(DexMethod method) {
- this.method = method;
- return this;
- }
-
- public Builder setTargetReceiver(DexType targetReceiver) {
- this.targetReceiver = targetReceiver;
- return this;
- }
-
- public Builder setTarget(DexMethod target) {
- this.target = target;
- return this;
- }
-
- public Builder setInvokeType(InvokeType invokeType) {
- this.invokeType = invokeType;
- return this;
- }
-
- public Builder setCastResult() {
- this.castResult = true;
- return this;
- }
-
- public Builder setIsInterface(boolean isInterface) {
- this.isInterface = isInterface;
- return this;
- }
-
- public Builder setExtraNullParameter() {
- this.extraNullParameter = true;
- return this;
- }
-
- public ForwardMethodSourceCode build(ProgramMethod context, Position position) {
- return new ForwardMethodSourceCode(
- receiver,
- method,
- targetReceiver,
- target,
- invokeType,
- position,
- isInterface,
- castResult,
- extraNullParameter);
- }
- }
-
- private final DexType targetReceiver;
- private final DexMethod target;
- private final InvokeType invokeType;
- private final boolean castResult;
- private final boolean isInterface;
- private final boolean extraNullParameter;
-
- ForwardMethodSourceCode(
- DexType receiver,
- DexMethod method,
- DexType targetReceiver,
- DexMethod target,
- InvokeType invokeType,
- Position position,
- boolean isInterface,
- boolean castResult,
- boolean extraNullParameter) {
- super(receiver, method, position);
- assert (targetReceiver == null) == (invokeType == InvokeType.STATIC);
-
- this.target = target;
- this.targetReceiver = targetReceiver;
- this.invokeType = invokeType;
- this.isInterface = isInterface;
- this.castResult = castResult;
- this.extraNullParameter = extraNullParameter;
- assert checkSignatures();
-
- switch (invokeType) {
- case DIRECT:
- case STATIC:
- case SUPER:
- case INTERFACE:
- case VIRTUAL:
- break;
- default:
- throw new Unimplemented("Invoke type " + invokeType + " is not yet supported.");
- }
- }
-
- @SuppressWarnings("ReferenceEquality")
- private boolean checkSignatures() {
- List<DexType> sourceParams = new ArrayList<>();
- if (receiver != null) {
- sourceParams.add(receiver);
- }
- sourceParams.addAll(Lists.newArrayList(proto.parameters.values));
- if (extraNullParameter) {
- sourceParams.remove(sourceParams.size() - 1);
- }
-
- List<DexType> targetParams = new ArrayList<>();
- if (targetReceiver != null) {
- targetParams.add(targetReceiver);
- }
- targetParams.addAll(Lists.newArrayList(target.proto.parameters.values));
-
- assert sourceParams.size() == targetParams.size();
- for (int i = 0; i < sourceParams.size(); i++) {
- DexType source = sourceParams.get(i);
- DexType target = targetParams.get(i);
-
- // We assume source is compatible with target if they both are classes.
- // This check takes care of receiver widening conversion but does not
- // many others, like conversion from an array to Object.
- assert (source.isClassType() && target.isClassType()) || source == target;
- }
-
- assert this.proto.returnType == target.proto.returnType || castResult;
- return true;
- }
-
- @Override
- @SuppressWarnings("ReferenceEquality")
- protected void prepareInstructions() {
- // Prepare call arguments.
- List<ValueType> argValueTypes = new ArrayList<>();
- List<Integer> argRegisters = new ArrayList<>();
-
- if (receiver != null) {
- argValueTypes.add(ValueType.OBJECT);
- argRegisters.add(getReceiverRegister());
- }
-
- DexType[] accessorParams = proto.parameters.values;
- for (int i = 0; i < accessorParams.length - BooleanUtils.intValue(extraNullParameter); i++) {
- argValueTypes.add(ValueType.fromDexType(accessorParams[i]));
- argRegisters.add(getParamRegister(i));
- }
-
- // Method call to the target method.
- add(
- builder ->
- builder.addInvoke(
- this.invokeType,
- this.target,
- this.target.proto,
- argValueTypes,
- argRegisters,
- this.isInterface));
-
- // Does the method return value?
- if (proto.returnType.isVoidType()) {
- add(IRBuilder::addReturn);
- } else {
- ValueType valueType = ValueType.fromDexType(proto.returnType);
- int tempValue = nextRegister(valueType);
- add(builder -> builder.addMoveResult(tempValue));
- if (this.proto.returnType != target.proto.returnType) {
- add(builder -> builder.addCheckCast(tempValue, this.proto.returnType));
- }
- add(builder -> builder.addReturn(tempValue));
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMerger.java
index 86b9848..bf712ad 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMerger.java
@@ -5,7 +5,6 @@
import static com.android.tools.r8.dex.Constants.TEMPORARY_INSTANCE_INITIALIZER_PREFIX;
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
-import static com.android.tools.r8.ir.code.InvokeType.DIRECT;
import static com.android.tools.r8.ir.code.InvokeType.STATIC;
import static com.android.tools.r8.ir.code.InvokeType.VIRTUAL;
import static java.util.function.Predicate.not;
@@ -13,6 +12,7 @@
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AccessControl;
+import com.android.tools.r8.graph.AccessFlags;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DefaultInstanceInitializerCode;
import com.android.tools.r8.graph.DexEncodedField;
@@ -76,12 +76,12 @@
private final DexProgramClass source;
private final DexProgramClass target;
- private final List<SynthesizedBridgeCode> synthesizedBridges;
+ private final List<IncompleteVerticalClassMergerBridgeCode> synthesizedBridges;
ClassMerger(
AppView<AppInfoWithLiveness> appView,
VerticalClassMergerGraphLens.Builder outerLensBuilder,
- List<SynthesizedBridgeCode> synthesizedBridges,
+ List<IncompleteVerticalClassMergerBridgeCode> synthesizedBridges,
VerticallyMergedClasses.Builder verticallyMergedClassesBuilder,
VerticalMergeGroup group) {
this.appView = appView;
@@ -252,8 +252,12 @@
assert availableMethodSignatures.test(resultingMethodReference);
resultingMethod =
virtualMethod.toTypeSubstitutedMethodAsInlining(
- resultingMethodReference, dexItemFactory);
- makeStatic(resultingMethod);
+ resultingMethodReference,
+ dexItemFactory,
+ builder ->
+ builder
+ .modifyAccessFlags(AccessFlags::setStatic)
+ .unsetIsLibraryMethodOverride());
} else {
// This virtual method could be called directly from a sub class via an invoke-super
// instruction. Therefore, we translate this virtual method into an instance method with a
@@ -550,15 +554,11 @@
accessFlags.setSynthetic();
accessFlags.unsetAbstract();
- assert invocationTarget.isStatic()
- || invocationTarget.isNonPrivateVirtualMethod()
- || invocationTarget.isNonStaticPrivateMethod();
- SynthesizedBridgeCode code =
- new SynthesizedBridgeCode(
+ assert invocationTarget.isStatic() || invocationTarget.isNonPrivateVirtualMethod();
+ IncompleteVerticalClassMergerBridgeCode code =
+ new IncompleteVerticalClassMergerBridgeCode(
method.getReference(),
- invocationTarget.isStatic()
- ? STATIC
- : (invocationTarget.isNonPrivateVirtualMethod() ? VIRTUAL : DIRECT),
+ invocationTarget.isStatic() ? STATIC : VIRTUAL,
target.isInterface());
// Add the bridge to the list of synthesized bridges such that the method signatures will
@@ -754,9 +754,4 @@
accessFlags.setPublic();
accessFlags.setFinal();
}
-
- private void makeStatic(DexEncodedMethod method) {
- method.getAccessFlags().setStatic();
- assert method.getCode().isCfCode();
- }
}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/ConnectedComponentVerticalClassMerger.java b/src/main/java/com/android/tools/r8/verticalclassmerging/ConnectedComponentVerticalClassMerger.java
index dc82f99..cc04384 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/ConnectedComponentVerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/ConnectedComponentVerticalClassMerger.java
@@ -20,7 +20,8 @@
private final VerticalClassMergerGraphLens.Builder lensBuilder;
// All the bridge methods that have been synthesized during vertical class merging.
- private final List<SynthesizedBridgeCode> synthesizedBridges = new ArrayList<>();
+ private final List<IncompleteVerticalClassMergerBridgeCode> synthesizedBridges =
+ new ArrayList<>();
private final VerticallyMergedClasses.Builder verticallyMergedClassesBuilder =
VerticallyMergedClasses.builder();
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/IncompleteVerticalClassMergerBridgeCode.java b/src/main/java/com/android/tools/r8/verticalclassmerging/IncompleteVerticalClassMergerBridgeCode.java
new file mode 100644
index 0000000..60694ae
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/IncompleteVerticalClassMergerBridgeCode.java
@@ -0,0 +1,139 @@
+// Copyright (c) 2024, 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.verticalclassmerging;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.ClasspathMethod;
+import com.android.tools.r8.graph.Code;
+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.ProgramMethod;
+import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.InvokeType;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
+import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
+
+/**
+ * A short-lived piece of code that will be converted into {@link CfCode} using the method {@link
+ * IncompleteVerticalClassMergerBridgeCode#toCfCode(DexItemFactory, VerticalClassMergerGraphLens)}.
+ */
+public class IncompleteVerticalClassMergerBridgeCode extends Code {
+
+ private DexMethod method;
+ private DexMethod invocationTarget;
+ private final InvokeType type;
+ private final boolean isInterface;
+
+ public IncompleteVerticalClassMergerBridgeCode(
+ DexMethod method, InvokeType type, boolean isInterface) {
+ this.method = method;
+ this.invocationTarget = null;
+ this.type = type;
+ this.isInterface = isInterface;
+ }
+
+ @Override
+ public Code getCodeAsInlining(
+ DexMethod caller,
+ boolean isCallerD8R8Synthesized,
+ DexMethod callee,
+ boolean isCalleeD8R8Synthesized,
+ DexItemFactory factory) {
+ // This code object is synthesized so "inlining" just "strips" the callee position.
+ assert isCalleeD8R8Synthesized;
+ return this;
+ }
+
+ public DexMethod getMethod() {
+ return method;
+ }
+
+ public DexMethod getTarget() {
+ return invocationTarget;
+ }
+
+ // By the time the synthesized code object is created, vertical class merging still has not
+ // finished. Therefore it is possible that the method signatures `method` and `invocationTarget`
+ // will change as a result of additional class merging operations. To deal with this, the
+ // vertical class merger explicitly invokes this method to update `method` and `invocation-
+ // Target` when vertical class merging has finished.
+ //
+ // Note that, without this step, these method signatures might refer to intermediate signatures
+ // that are only present in the middle of vertical class merging, which means that the graph
+ // lens will not work properly (since the graph lens generated by vertical class merging only
+ // expects to be applied to method signatures from *before* vertical class merging or *after*
+ // vertical class merging).
+ public void updateMethodSignatures(VerticalClassMergerGraphLens lens) {
+ invocationTarget = lens.getNextImplementationMethodSignature(method);
+ method = lens.getNextBridgeMethodSignature(method);
+ }
+
+ public CfCode toCfCode(DexItemFactory dexItemFactory, VerticalClassMergerGraphLens lens) {
+ return ForwardMethodBuilder.builder(dexItemFactory)
+ .applyIf(
+ type.isStatic(),
+ builder -> builder.setStaticTarget(invocationTarget, isInterface),
+ builder -> builder.setVirtualTarget(invocationTarget, isInterface))
+ .setNonStaticSource(method)
+ .setCodeLens(lens)
+ .build();
+ }
+
+ // Implement Code.
+
+ @Override
+ public IRCode buildIR(
+ ProgramMethod method,
+ AppView<?> appView,
+ Origin origin,
+ MutableMethodConversionOptions conversionOptions) {
+ throw new Unreachable();
+ }
+
+ @Override
+ protected boolean computeEquals(Object other) {
+ throw new Unreachable();
+ }
+
+ @Override
+ protected int computeHashCode() {
+ throw new Unreachable();
+ }
+
+ @Override
+ public int estimatedDexCodeSizeUpperBoundInBytes() {
+ throw new Unreachable();
+ }
+
+ @Override
+ public boolean isEmptyVoidMethod() {
+ throw new Unreachable();
+ }
+
+ @Override
+ public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public void registerCodeReferencesForDesugaring(ClasspathMethod method, UseRegistry registry) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public String toString() {
+ return "IncompleteVerticalClassMergerBridgeCode";
+ }
+
+ @Override
+ public String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
+ return toString();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/SynthesizedBridgeCode.java b/src/main/java/com/android/tools/r8/verticalclassmerging/SynthesizedBridgeCode.java
deleted file mode 100644
index edffcd5..0000000
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/SynthesizedBridgeCode.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.android.tools.r8.verticalclassmerging;
-
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClassAndMethod;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.UseRegistry;
-import com.android.tools.r8.graph.lens.GraphLens;
-import com.android.tools.r8.ir.code.InvokeType;
-import com.android.tools.r8.ir.synthetic.AbstractSynthesizedCode;
-import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
-import java.util.function.Consumer;
-
-public class SynthesizedBridgeCode extends AbstractSynthesizedCode {
-
- private DexMethod method;
- private DexMethod invocationTarget;
- private final InvokeType type;
- private final boolean isInterface;
- private VerticalClassMergerGraphLens codeLens;
-
- public SynthesizedBridgeCode(DexMethod method, InvokeType type, boolean isInterface) {
- this.method = method;
- this.invocationTarget = null;
- this.type = type;
- this.isInterface = isInterface;
- }
-
- public DexMethod getMethod() {
- return method;
- }
-
- public DexMethod getTarget() {
- return invocationTarget;
- }
-
- // By the time the synthesized code object is created, vertical class merging still has not
- // finished. Therefore it is possible that the method signatures `method` and `invocationTarget`
- // will change as a result of additional class merging operations. To deal with this, the
- // vertical class merger explicitly invokes this method to update `method` and `invocation-
- // Target` when vertical class merging has finished.
- //
- // Note that, without this step, these method signatures might refer to intermediate signatures
- // that are only present in the middle of vertical class merging, which means that the graph
- // lens will not work properly (since the graph lens generated by vertical class merging only
- // expects to be applied to method signatures from *before* vertical class merging or *after*
- // vertical class merging).
- public void updateMethodSignatures(VerticalClassMergerGraphLens lens) {
- codeLens = lens;
- invocationTarget = lens.getNextImplementationMethodSignature(method);
- method = lens.getNextBridgeMethodSignature(method);
- }
-
- @Override
- public GraphLens getCodeLens(AppView<?> appView) {
- return codeLens;
- }
-
- @Override
- public SourceCodeProvider getSourceCodeProvider() {
- ForwardMethodSourceCode.Builder forwardSourceCodeBuilder =
- ForwardMethodSourceCode.builder(method);
- forwardSourceCodeBuilder
- .setReceiver(method.holder)
- .setTargetReceiver(type.isStatic() ? null : method.holder)
- .setTarget(invocationTarget)
- .setInvokeType(type)
- .setIsInterface(isInterface);
- return forwardSourceCodeBuilder::build;
- }
-
- @Override
- public Consumer<UseRegistry> getRegistryCallback(DexClassAndMethod method) {
- return registry -> {
- assert registry.getTraversalContinuation().shouldContinue();
- switch (type) {
- case DIRECT:
- registry.registerInvokeDirect(invocationTarget);
- break;
- case STATIC:
- registry.registerInvokeStatic(invocationTarget);
- break;
- case VIRTUAL:
- registry.registerInvokeVirtual(invocationTarget);
- break;
- default:
- throw new Unreachable("Unexpected invocation type: " + type);
- }
- };
- }
-}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
index f94208d..d791b84 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
@@ -117,7 +117,7 @@
assert verifyGraphLens(lens, verticalClassMergerResult);
updateArtProfiles(profileCollectionAdditions, lens, verticalClassMergerResult);
appView.rewriteWithLens(lens, executorService, timing);
- updateKeepInfoForSynthesizedBridges(verticalClassMergerResult);
+ finalizeSynthesizedBridges(verticalClassMergerResult.getSynthesizedBridges(), lens);
appView.notifyOptimizationFinishedForTesting();
}
@@ -223,9 +223,9 @@
VerticalClassMergerResult verticalClassMergerResult) {
// Include bridges in art profiles.
if (!profileCollectionAdditions.isNop()) {
- List<SynthesizedBridgeCode> synthesizedBridges =
+ List<IncompleteVerticalClassMergerBridgeCode> synthesizedBridges =
verticalClassMergerResult.getSynthesizedBridges();
- for (SynthesizedBridgeCode synthesizedBridge : synthesizedBridges) {
+ for (IncompleteVerticalClassMergerBridgeCode synthesizedBridge : synthesizedBridges) {
profileCollectionAdditions.applyIfContextIsInProfile(
verticalClassMergerLens.getPreviousMethodSignature(synthesizedBridge.getMethod()),
additionsBuilder -> additionsBuilder.addRule(synthesizedBridge.getMethod()));
@@ -247,26 +247,24 @@
});
}
- private void updateKeepInfoForSynthesizedBridges(
- VerticalClassMergerResult verticalClassMergerResult) {
- // Copy keep info to newly synthesized methods.
+ private void finalizeSynthesizedBridges(
+ List<IncompleteVerticalClassMergerBridgeCode> bridges, VerticalClassMergerGraphLens lens) {
KeepInfoCollection keepInfo = appView.getKeepInfo();
- keepInfo.mutate(
- mutator -> {
- List<SynthesizedBridgeCode> synthesizedBridges =
- verticalClassMergerResult.getSynthesizedBridges();
- for (SynthesizedBridgeCode synthesizedBridge : synthesizedBridges) {
- ProgramMethod bridge =
- asProgramMethodOrNull(appView.definitionFor(synthesizedBridge.getMethod()));
- ProgramMethod target =
- asProgramMethodOrNull(appView.definitionFor(synthesizedBridge.getTarget()));
- if (bridge != null && target != null) {
- mutator.joinMethod(bridge, info -> info.merge(appView.getKeepInfo(target).joiner()));
- continue;
- }
- assert false;
- }
- });
+ for (IncompleteVerticalClassMergerBridgeCode code : bridges) {
+ ProgramMethod bridge = asProgramMethodOrNull(appView.definitionFor(code.getMethod()));
+ assert bridge != null;
+
+ ProgramMethod target = asProgramMethodOrNull(appView.definitionFor(code.getTarget()));
+ assert target != null;
+
+ // Finalize code.
+ bridge.setCode(code.toCfCode(dexItemFactory, lens), appView);
+
+ // Copy keep info to newly synthesized methods.
+ keepInfo.mutate(
+ mutator ->
+ mutator.joinMethod(bridge, info -> info.merge(appView.getKeepInfo(target).joiner())));
+ }
}
private boolean verifyGraphLens(
@@ -307,14 +305,15 @@
DexMethod renamedMethod = graphLens.getRenamedMethodSignature(originalMethod);
// Must be able to map back and forth.
- if (encodedMethod.hasCode() && encodedMethod.getCode() instanceof SynthesizedBridgeCode) {
+ if (encodedMethod.hasCode()
+ && encodedMethod.getCode() instanceof IncompleteVerticalClassMergerBridgeCode) {
// For virtual methods, the vertical class merger creates two methods in the sub class
// in order to deal with invoke-super instructions (one that is private and one that is
// virtual). Therefore, it is not possible to go back and forth. Instead, we check that
// the two methods map back to the same original method, and that the original method
// can be mapped to the implementation method.
DexMethod implementationMethod =
- ((SynthesizedBridgeCode) encodedMethod.getCode()).getTarget();
+ ((IncompleteVerticalClassMergerBridgeCode) encodedMethod.getCode()).getTarget();
DexMethod originalImplementationMethod =
graphLens.getOriginalMethodSignature(implementationMethod);
assert originalMethod.isIdenticalTo(originalImplementationMethod);
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerResult.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerResult.java
index 390131a..43bdbd7 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerResult.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerResult.java
@@ -11,12 +11,12 @@
public class VerticalClassMergerResult {
private final VerticalClassMergerGraphLens.Builder lensBuilder;
- private final List<SynthesizedBridgeCode> synthesizedBridges;
+ private final List<IncompleteVerticalClassMergerBridgeCode> synthesizedBridges;
private final VerticallyMergedClasses verticallyMergedClasses;
public VerticalClassMergerResult(
VerticalClassMergerGraphLens.Builder lensBuilder,
- List<SynthesizedBridgeCode> synthesizedBridges,
+ List<IncompleteVerticalClassMergerBridgeCode> synthesizedBridges,
VerticallyMergedClasses verticallyMergedClasses) {
this.lensBuilder = lensBuilder;
this.synthesizedBridges = synthesizedBridges;
@@ -29,7 +29,7 @@
public static Builder builder(
VerticalClassMergerGraphLens.Builder lensBuilder,
- List<SynthesizedBridgeCode> synthesizedBridges,
+ List<IncompleteVerticalClassMergerBridgeCode> synthesizedBridges,
VerticallyMergedClasses.Builder verticallyMergedClassesBuilder) {
return new Builder(lensBuilder, synthesizedBridges, verticallyMergedClassesBuilder);
}
@@ -38,7 +38,7 @@
return lensBuilder;
}
- List<SynthesizedBridgeCode> getSynthesizedBridges() {
+ List<IncompleteVerticalClassMergerBridgeCode> getSynthesizedBridges() {
return synthesizedBridges;
}
@@ -53,7 +53,7 @@
public static class Builder {
private final VerticalClassMergerGraphLens.Builder lensBuilder;
- private final List<SynthesizedBridgeCode> synthesizedBridges;
+ private final List<IncompleteVerticalClassMergerBridgeCode> synthesizedBridges;
private final VerticallyMergedClasses.Builder verticallyMergedClassesBuilder;
Builder(AppView<AppInfoWithLiveness> appView) {
@@ -65,7 +65,7 @@
Builder(
VerticalClassMergerGraphLens.Builder lensBuilder,
- List<SynthesizedBridgeCode> synthesizedBridges,
+ List<IncompleteVerticalClassMergerBridgeCode> synthesizedBridges,
VerticallyMergedClasses.Builder verticallyMergedClassesBuilder) {
this.lensBuilder = lensBuilder;
this.synthesizedBridges = synthesizedBridges;
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java
index d814695..c6c1f4d 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java
@@ -19,7 +19,7 @@
VerticalClassMergerGraphLens,
VerticallyMergedClasses> {
- private final List<SynthesizedBridgeCode> synthesizedBridges;
+ private final List<IncompleteVerticalClassMergerBridgeCode> synthesizedBridges;
VerticalClassMergerTreeFixer(
AppView<AppInfoWithLiveness> appView,
@@ -39,7 +39,7 @@
public VerticalClassMergerGraphLens run(ExecutorService executorService, Timing timing)
throws ExecutionException {
VerticalClassMergerGraphLens lens = super.run(executorService, timing);
- for (SynthesizedBridgeCode synthesizedBridge : synthesizedBridges) {
+ for (IncompleteVerticalClassMergerBridgeCode synthesizedBridge : synthesizedBridges) {
synthesizedBridge.updateMethodSignatures(lens);
}
return lens;
diff --git a/src/test/java/com/android/tools/r8/gson/GsonDefaultConstructorTest.java b/src/test/java/com/android/tools/r8/gson/GsonDefaultConstructorTest.java
index 5c61354..9d0b65d 100644
--- a/src/test/java/com/android/tools/r8/gson/GsonDefaultConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/gson/GsonDefaultConstructorTest.java
@@ -3,11 +3,19 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.gson;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+
import com.android.tools.r8.ProguardVersion;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.gson.GsonNoDefaultConstructorTest.Data;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
@@ -41,6 +49,14 @@
private static final String EXPECTED_OUTPUT = StringUtils.lines("Hello, world!");
+ private void inspect(CodeInspector inspector) {
+ ClassSubject dataSubject = inspector.clazz(Data.class);
+ assertThat(dataSubject, isPresentAndRenamed());
+ assertThat(dataSubject.uniqueFieldWithOriginalName("s"), isPresentAndRenamed());
+ assertThat(dataSubject.init(), isPresent());
+ assertThat(dataSubject.init("java.lang.String"), isAbsent());
+ }
+
@Test
public void testR8() throws Exception {
parameters.assumeR8TestParameters();
@@ -51,6 +67,8 @@
.addKeepMainRule(TestClass.class)
.setMinApi(parameters)
.run(parameters.getRuntime(), TestClass.class, enableUnsafe ? "enable" : "disable")
+ .inspect(this::serializedNamePresentAndRenamed)
+ .inspect(this::inspect)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
}
diff --git a/src/test/java/com/android/tools/r8/gson/GsonNoDefaultConstructorTest.java b/src/test/java/com/android/tools/r8/gson/GsonNoDefaultConstructorTest.java
index 5a0244a..b536709 100644
--- a/src/test/java/com/android/tools/r8/gson/GsonNoDefaultConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/gson/GsonNoDefaultConstructorTest.java
@@ -3,13 +3,19 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.gson;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
import com.android.tools.r8.ProguardVersion;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
@@ -43,6 +49,13 @@
private static final String EXPECTED_OUTPUT = StringUtils.lines("Hello, world!");
+ private void inspect(CodeInspector inspector) {
+ ClassSubject dataSubject = inspector.clazz(Data.class);
+ assertThat(dataSubject, isPresentAndRenamed());
+ assertThat(dataSubject.uniqueFieldWithOriginalName("s"), isPresentAndRenamed());
+ assertTrue(dataSubject.allMethods(FoundMethodSubject::isInstanceInitializer).isEmpty());
+ }
+
@Test
public void testR8() throws Exception {
parameters.assumeR8TestParameters();
@@ -52,6 +65,9 @@
.apply(GsonTestBase::addGsonLibraryAndKeepRules)
.addKeepMainRule(TestClass.class)
.setMinApi(parameters)
+ .compile()
+ .inspect(this::serializedNamePresentAndRenamed)
+ .inspect(this::inspect)
.run(parameters.getRuntime(), TestClass.class, enableUnsafe ? "enable" : "disable")
.applyIf(
enableUnsafe,
diff --git a/src/test/java/com/android/tools/r8/gson/GsonTestBase.java b/src/test/java/com/android/tools/r8/gson/GsonTestBase.java
index 970450c..f0029f4 100644
--- a/src/test/java/com/android/tools/r8/gson/GsonTestBase.java
+++ b/src/test/java/com/android/tools/r8/gson/GsonTestBase.java
@@ -3,6 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.gson;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+
import com.android.tools.r8.ArchiveProgramResourceProvider;
import com.android.tools.r8.ProguardTestBuilder;
import com.android.tools.r8.R8FullTestBuilder;
@@ -10,9 +13,16 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestShrinkerBuilder;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
public class GsonTestBase extends TestBase {
+ public static String SERIALIZED_NAME_CLASS_NAME = "com.google.gson.annotations.SerializedName";
+
+ public void serializedNamePresentAndRenamed(CodeInspector inspector) {
+ assertThat(inspector.clazz(SERIALIZED_NAME_CLASS_NAME), isPresentAndRenamed());
+ }
+
static void addRuntimeLibrary(TestShrinkerBuilder builder, TestParameters parameters) {
// Gson use java.lang.ReflectiveOperationException.
builder.addDefaultRuntimeLibraryWithReflectiveOperationException(parameters);
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/NarrowingWithoutSubtypingTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/NarrowingWithoutSubtypingTest.java
index 343a944..c719a9a 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/NarrowingWithoutSubtypingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/NarrowingWithoutSubtypingTest.java
@@ -4,12 +4,7 @@
package com.android.tools.r8.ir.analysis.type;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertThrows;
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.D8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
@@ -38,32 +33,17 @@
@Test
public void test() throws Exception {
- D8TestBuilder d8TestBuilder =
- testForD8()
- .addInnerClasses(NarrowingWithoutSubtypingTest.class)
- .addOptionsModification(
- options -> {
- options.testing.readInputStackMaps = readStackMap;
- options.testing.enableNarrowAndWideningingChecksInD8 = true;
- options.testing.noLocalsTableOnInput = true;
- })
- .setMinApi(parameters);
- if (readStackMap) {
- d8TestBuilder
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutputLines("Hello world!");
- } else {
- // TODO(b/169120386): We should not be narrowing in D8.
- assertThrows(
- CompilationFailedException.class,
- () -> {
- d8TestBuilder.compileWithExpectedDiagnostics(
- diagnostics ->
- diagnostics.assertAllErrorsMatch(
- diagnosticMessage(
- containsString("java.lang.AssertionError: During NARROWING"))));
- });
- }
+ testForD8()
+ .addInnerClasses(NarrowingWithoutSubtypingTest.class)
+ .addOptionsModification(
+ options -> {
+ options.testing.readInputStackMaps = readStackMap;
+ options.testing.enableNarrowAndWideningingChecksInD8 = true;
+ options.testing.noLocalsTableOnInput = true;
+ })
+ .setMinApi(parameters)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/regress/b316744331/Regress316744331Test.java b/src/test/java/com/android/tools/r8/regress/b316744331/Regress316744331Test.java
index e3e6058..2bcf2f7 100644
--- a/src/test/java/com/android/tools/r8/regress/b316744331/Regress316744331Test.java
+++ b/src/test/java/com/android/tools/r8/regress/b316744331/Regress316744331Test.java
@@ -86,8 +86,7 @@
breakpoint(fooMethod, IN_STREAM_IS_NULL_LINE),
breakpoint(fooMethod, NORMAL_EXIT_LINE),
run(),
- // TODO(b/316744331): D8 incorrectly optimizing out the code after the null check.
- checkLine(parameters.isCfRuntime() ? IN_STREAM_IS_NULL_LINE : NORMAL_EXIT_LINE),
+ checkLine(IN_STREAM_IS_NULL_LINE),
run());
}
@@ -105,8 +104,7 @@
breakpoint(fooMethod, OUT_STREAM_IS_NULL_LINE),
breakpoint(fooMethod, NORMAL_EXIT_LINE),
run(),
- // TODO(b/316744331): D8 incorrectly optimizing out the code after the null check.
- checkLine(parameters.isCfRuntime() ? OUT_STREAM_IS_NULL_LINE : NORMAL_EXIT_LINE),
+ checkLine(OUT_STREAM_IS_NULL_LINE),
run());
}
}