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()); } }